From: Eric Andersen Date: Sat, 16 Jul 2005 01:57:20 +0000 (-0000) Subject: Clone the busybox_0_60_stable branch from the old busybox.stable CVS tree X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=refs%2Fheads%2F0_60_stable;p=oweals%2Fbusybox.git Clone the busybox_0_60_stable branch from the old busybox.stable CVS tree --- diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 000000000..71269c542 --- /dev/null +++ b/.cvsignore @@ -0,0 +1,4 @@ +busybox +busybox.links +_install +applet_source_list diff --git a/.indent.pro b/.indent.pro new file mode 100644 index 000000000..492ecf1c7 --- /dev/null +++ b/.indent.pro @@ -0,0 +1,33 @@ +--blank-lines-after-declarations +--blank-lines-after-procedures +--break-before-boolean-operator +--no-blank-lines-after-commas +--braces-on-if-line +--braces-on-struct-decl-line +--comment-indentation25 +--declaration-comment-column25 +--no-comment-delimiters-on-blank-lines +--cuddle-else +--continuation-indentation4 +--case-indentation0 +--else-endif-column33 +--space-after-cast +--line-comments-indentation0 +--declaration-indentation1 +--dont-format-first-column-comments +--dont-format-comments +--honour-newlines +--indent-level4 +/* changed from 0 to 4 */ +--parameter-indentation4 +--line-length78 /* changed from 75 */ +--continue-at-parentheses +--no-space-after-function-call-names +--dont-break-procedure-type +--dont-star-comments +--leave-optional-blank-lines +--dont-space-special-semicolon +--tab-size4 +/* additions by Mark */ +--case-brace-indentation0 +--leave-preprocessor-space diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..9cee03792 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,93 @@ +List of the authors of code contained in BusyBox. + +If you have code in BusyBox, you should be listed here. If you should be +listed, or the description of what you have done needs more detail, or is +incorect, _please_ let me know. + + -Erik + +----------- + +Erik Andersen , + Tons of new stuff, major rewrite of most of the + core apps, tons of new apps as noted in header files. + +Edward Betts + expr, hostid, logname, tty, wc, whoami, yes + +John Beppu + du, head, nslookup, sort, tee, uniq + +Brian Candler + tiny-ls(ls) + +Randolph Chung + fbset, ping, hostname, and mkfifo + +Dave Cinege + more(v2), makedevs, dutmp, modularization, auto links file, + various fixes, Linux Router Project maintenance + +Magnus Damm + tftp client + insmod powerpc support + +Larry Doolittle + pristine source directory compilation, lots of patches and fixes. + +Gennady Feldman + Sysklogd (single threaded syslogd, IPC Circular buffer support, + logread), various fixes. + +Karl M. Hegbloom + cp_mv.c, the test suite, various fixes to utility.c, &c. + +Daniel Jacobowitz + mktemp.c + +Matt Kraai + documentation, bugfixes, test suite + +John Lombardo + dirname, tr + +Glenn McGrath + ar, dpkg, dpkg-deb + +Vladimir Oleynik + cmdedit; ports: ash, stty, traceroute; locale, various fixes + and irreconcilable critic of everything not perfect. + +Bruce Perens + Original author of BusyBox. His code is still in many apps. + +Tim Riker + bug fixes, member of fan club + +Kent Robotti + reset, tons and tons of bug reports and patchs. + +Chip Rosenthal , + wget - Contributed by permission of Covad Communications + +Pavel Roskin + Lots of bugs fixes and patches. + +Gyepi Sam + Remote logging feature for syslogd + +Linus Torvalds + mkswap, fsck.minix, mkfs.minix + +Mark Whitley + grep, sed, cut, xargs, style-guide, new-applet-HOWTO, bug fixes, etc. + +Charles P. Wright + gzip, mini-netcat(nc) + +Enrique Zanardi + tarcat (since removed), loadkmap, various fixes, Debian maintenance + +Emanuele Aina + run-parts + diff --git a/Changelog b/Changelog new file mode 100644 index 000000000..46590b595 --- /dev/null +++ b/Changelog @@ -0,0 +1,1452 @@ +0.60.5 + + Stable Release + + Bugfixes: + * Fixed a race that could cause init to hang + * Fixed init orphan process reaping + * Fixed init to always attempt to provide a controlling tty. + This should fix most cases where ash would print + "job control disabled" -- the other cases are user error. + * Fixed 'gunzip -c' to not delete the source source file + * Fixed a silly math problem in the time applet + * Fixed 'cp -a' so it will once again copy symlinks properly + * Fixed a long standing problem in tftp with freeing memory + * Fixed Makefile largefile settings + * Fixed a buffer overflow in vi + * Cosmetic cleanups in lsmod, lash, init, swapon/off, and hostname + * Set the close-on-exec flag on files opened by init + * The updated top applet was backported from unstable + * Several ash bugfixes were backported from unstable + * Several warnings in ash, md5sum, and ifconfig + + -Erik Andersen, 26 October 2002 + + + +0.60.4 + + Stable Release + + New Applets & New Features: + * Added new a 'top' applet (by special request) + * Lots of small uClinux adjustments + + Bugfixes: + * This release has _lots_ of bugfixes. See Changelog.full + for the complete list of what was changed. + + -Erik Andersen, 18 September 2002 + + + +0.60.3 + + Stable Release + + New Applets & New Features: + * Added new a 'time' applet (by special request) + * Added new a 'losetup' applet + * The tftp has been fixed to work + * Default shell is now ash. + * msh shell should work properly on mmu-less systems again + * ls can now do color + + Bugfixes: + * Erik Andersen + -- Hacked together a new time applet + -- Fixed dangling comma in init.c (s390 arch only) + -- Fixed more so when it is run on files in the procfs that + claim 0 length, it will not do weird things i.e. more /proc/pci + -- Copyright message cleanups. Fixed sash attributions. + -- Backporting of fixes and general maintenance. + -- Fixed several cases where reboot, halt, and poweroff would fail + to function properly when Linux is booted into an initrd. + -- Fixed a silly compile bug in cpio + -- nslookup now works properly with uClibc, remove old workaround + -- Added conv=noerror support to dd + -- Fixed ash and msh cmdedit to properly account for the current + PATH setting + -- Document netcat options and add -e support + -- Fixed insanely broken insmod endianness handling + -- Update init.c for better syle conformance, properly detach from + terminal when necessary, better code reuse, FIFO inittab file + reading/executing, allow init to be halted and restarted, etc. + -- Allow gunzip to work on multiple archives, add -v option + -- Updated x86 optimizations to save over 10k. + * Edward Betts + -- added -x switch to du.c + * Cliff L. Biffle + -- Added memory usage to the ps listings + * Przemyslaw Czerpak + -- Made telnet 8-bit clean, handle screen size, and is now RFC + compliant. Works nicely now. + * Wolfgang Denk + -- hush now supports shell loops (for, while, until) and control + operators (||, &&) + * Russ Dill + -- Added an 'restart' inittab action, allowing init to re-exec + itself (or call a script which calls pivot_root then exec...) + * Larry Doolittle + -- Made syslogd not give up when errno is EINTR + * Geoffrey Espin + -- support find -newer + * Robert Griebl + -- Reworked modprobe so it now reads and uses modules.dep + * Karl M. Hegbloom + -- Fixed a silly bug where CONTEXT and EGREP_ALIAS were coupled. + * Kevin Hilman + -- Fixed memory corruption from long pathnames in /etc/fstab + * J.W.Janssen + -- color ls support! + * Matt Kraai + -- Fixed get_line_from_file() so that NULL is treated as end of + line, thereby fixing cut, grep, sed, etc. when working on binary + files or anything that might contain a NULL. + -- Fixed wget to do DNS initial DNS lookups, and do that only once + to avoid skipping to a different server when round-robin DNS is + in use (bug found by Mike Coleman ) + -- Several sed fixes + -- Added new losetup applet + * Ben Low + -- allow tftp to work with stdin as well as stdout. + * Frank P. MacLachlan avoid a potential + NULL pointer problem in mount. + * Glenn McGrath + -- gunzip was incorrectly reporting a failed crc and length + (Discovered by Change, Shu-Hao). The problem was the bitbuffer + needs to be unwound after decompression as it was eating into the + crc/size field. + -- Reworked wc.c to fix severe efficiency problems and make it + smaller. When just counting file chars, simply stat the file + instead of reading the whole thing. (Fixes Debian bug #103302) + -- Updated dmalloc options + * Manuel Novoa III + -- rewrote get_last_path_component() so it would not be so + horrible, and would behave correctly in several important corner + cases. + * Vladimir Oleynik + -- Fixed ash problem where ^C could be blocked + -- Several command line editing updates (cmdedit now supports + CTRL-K and CTRL-L, fixed a segfault, etc) + -- Fixed ash problem where ^C could be blocked + -- Several size optimizations for various applets + * Tim Riker + -- make ash prompt the same as other shells if cmdedit and + fancyprompt are enabled. + * Jeff Studer + -- tftp now generates default values for localfilename and + remotefilename based on provided file names when possible. + * Stefan Soucek and Miles Bader + -- Re-add mmu-less support to msh + * Jim Treadway + -- Fixed a buffer overflow in the local group handling code. + -- Fixed a missing "\" in usage.h + -- Made pidof not add trailing spaces + -- Fixed msh bugs so things like "A = 1; B = `eval $A`; echo $B" + can now work. + * Mike Voytovich + -- insmod big endian ARM support + + + -Erik Andersen, 27 April 2002 + + + + + +0.60.2 + + Stable Release + + * Please support busybox and help us buy busybox.net. See the + (current) busybox webpage for details. + + New Applets & New Features: + * msh was reworked by Vladimir Oleynik's so it can handle things like + for i in `ls *.c` ; do echo $i ; done + unfortunately, this also means that msh is no-longer uClinux safe, + and will require some surgery to make it use vfork() again. + * Charles Steinkuehler -- reworked hostname + so it behaves as expected (backport from busybox unstable) + + Known Problems + none. :) + + Bugfixes: + * Erik Andersen + -- Fixed grep -E and egrep so they actually behave as expected + -- init cleanups and (theoretical) uClinux support + -- Fixed large file (>2Gig) support (enable in the Makefile) + -- Always enable test when a shell is enabled (least surprise) + -- Made 'mount -a' use proc to avoid a static noauto list + -- lots of source tree cleanups + * Laurence Anderson + -- Removed some traces of no-longer existant rpmunpack (which + has been obsoleted by the rpm2cpio applet). + -- Fixed unarchive.c to use the correct buffer when calling + dirname, improve an error message, and plug some memory leaks. + -- Fixed rpm2cpio.c mkfs_minix.c fsck_minix.c fbset.c to use + standard types (s/u16/u_int16_t/g s/u32/u_int32_t/g etc) + * ASA -- fixed ash handling of command line args + when sourcing ('.') commands. + * Ethan Benson + -- Fix mount's noauto option to not automount as "usbdevfs" + * David Kimdon -- fixed md5sum binary sums + * Matt Kraai + -- Fix sed s/[/]// handling (noted by Dumas Patrice). + -- Fix dirname(3) improper consts, allow libc version to override. + -- Fixed invoking applets when their names contain a leading dash + and a full pathname. + -- Fix ash exec + -- Fixed basename to be SUSv2 compliant (which specifies that the + extension should stay if it is identical to the basename. + -- Fixed rmdir, since SuS2 says rmdir must provide -p + -- Fixed sed empty line substitutions (noted by Joshua Hudson). + * Steve Merrifield -- make vi use xmalloc + * Glenn McGrath + -- dpkg cleanups, various bugfixes + * Vladimir Oleynik + -- Add support for `busybox --help APPLET' + -- Fixed route so it properly displays all route entries + -- Fix for ash leading redirections (i.e. '2>/dev/null ls rubbish') + * Andrew Tipton -- enable vi cursor keys when in + edit mode as vim does. + + + -Erik Andersen, 20 November 2001 + + + + + +0.60.1 + + Stable Release + + + New Applets & New Features: + none. :) + + Known Problems (to be fixed in 0.60.2) + * msh can segfault on constructs such as + for i in `ls *.c` ; do echo $i ; done + due to a memory allocation problem. This only seems to cause + problems when the backtick expands to be several k in size. + + + Bugfixes: + * Matt Kraai + -- Fixed msh to support underscores in variable names. + -- Fixed a sed problem with unsatisfied backrefs (the problem was + noted by Martin Bene). + -- Removed BB_SH define entirely. Now one simply picks the shell + or shells they want as BB_ in Config.h + -- Fixed head to use ferror(3) to check for errors, not errno. + * Shu-Hao Chang + -- Fixed sed handling of multiple -e commands + * Magick + -- Fixed an init bug with AskFirst and /dev/null + * Jaspreet Singh + -- Fixed both a segfault and cosmetic bug in route + * Erik Andersen + -- Made the insmod options BB_FEATURE_NEW_MODULE_INTERFACE and + BB_FEATURE_OLD_MODULE_INTERFACE mutually exclusive + -- xgetcwd.c now includes sys/param.h to ensure PATH_MAX is defined + -- Fixed a potential segfault with lash + BB_FEATURE_CLEAN_UP + -- Removed uint64_t from dos2unix, avoiding C lib compat. problems. + * Glenn McGrath + -- Rewrite of tftp (commands match atftp, accepts -b, can use + non-standard ports, and is smaller). + -- Fixed unarchive exclude list handling + * Manuel Novoa III + -- rewrite of simplify_path so it behaves itself (fixing some + problems with mount and other applets). + -- Fixed ifconfig 'broadcast +' handling and disabled it by default + * Matthias ? + -- Fixed syslogd to log all messages from a single connection, not + just the first. + + + -Erik Andersen, 23 August 2001 + + + + +0.60.0 + + Note: + + For this release I have bumped the version number to 0.60.0. This + reflects the fact that this release is intended to form a new stable + BusyBox release series. If you need to rely on a stable version of + BusyBox, you should plan on using the stable 0.60.x series. If bugs + show up then I will release 0.60.1, then 0.60.2, etc... This is also + intended to deal with the fact that the BusyBox build system will be + getting a major overhaul for the next release and I don't want that to + break products that people are shipping. To avoid that, the new build + system will be released as part of a new BusyBox development series + that will have some not-yet-decided-on odd version number. Once things + stabablize and the new build system is working for everyone, then I + will release that as a new stable release series. + + Critical Bugfixes: + * Matt Kraai + -- Fixed wget output file opening (wget failed in 0.52). + -- Fixed a memory leak in syslogd (found by Adam Slattery). + * Vladimir Oleynik, Matt Kraai, Erik Andersen + -- several nasty bugs in ash and msh. msh could not assign + any variables and had debug code still enabled. ash + had several compile errors (depending on selected options) + and variable assignment problems as well. + + New Applets: + * David McCullough -- modprobe + * Vladimir Oleynik -- traceroute + * Erik Andersen -- pidof + + New Scripts: + * David Schleef, Erik Andersen, Stuart Hughes -- depmod.pl + This is a replacement for the depmod program from the modutils + package, but is fully cross platform and is designed to run on + your host system (not on the target). + + Other Changes: + * Erik Andersen + -- fixed busybox.spec so it should now work on redhat systems + -- fixed dos2unix and unix2dos so they should work once again + -- Adjustments to make busybox more uClinux friendly. Busybox + should now work on uClinux systems without needing and source + code changes (applets that won't work on uClinux systems are + now automagicaly disabled). + -- various things (cleanups, libc compatibility work, etc, etc) + * Jim Gleason + -- Fixed for sed, where it failed to preserve whether or not the + line was previously altered when running a subst command. + * Matt Kraai + -- Made tar read 20 512byte blocks at a time (like GNU tar) + -- Allow msh.c assignments with the export and readonly commands. + -- Added BB_FEATURE_DEVFS to enable devfs device names. + -- Better devfs support + -- Don't save/restore vi readonly flag if vi is compiled read-only. + -- Reworked rdate option handling (is now smaller). + -- Size reduction in ping + -- Always write dd counts to stderr + -- Allow multiple shells to be enabled + * Aaron Lehmann + -- slimmed down md5sum + -- contributed a nice new (hand written, not lex/yacc) Posix math + support for ash, which is once again a full posix shell. + * Felix von Leitner -- patches to make busybox + work with dietlibc. + * David McCullough + -- Adjustments to make busybox more uClinux friendly + * Glenn McGrath + -- Fixed gzip so when a filename is '-' it will use stdin/stdout + -- dpkg rewrite. Should now be compatable with the real dpkg, + but needs more testing. + -- Updates to archiving tools (gunzip/gzip/cpio/ar/etc) + -- Rewrote uuencode, will allow base64 encoding to be used by wget + * Vladimir Oleynik + -- Fixed tr to support 'tr a-z A-Z' syntax, + -- Many ash corrections, optimizations, and cleanups. + -- optimizations for traceroute, md5sum, chown, ping + -- cmdedit updates and API change + -- Namespace cleanup (i.e. adding 'static' private function calls) + -- added "stopped jobs" warning to ash on exit + * Adam Slattery + -- Fixed ping compile problem + * Robert J. Osborne + -- fixed a vi bug with delete and escape sequences on empty files. + + + -Erik Andersen, 31 July 2001 + + + +0.52 + + Critical Bugfixes: + * Glenn McGrath -- Fixed gunzip, zcat when reading from stdin + * Marc Karasek and Kanoj (kernel serial.c maintainer) -- fixed init + problem on serial consoles with 2.4.3+ kernels. + + New Applets: + * Laurence Anderson -- rpm2cpio applet, this obsoletes rpmunpack + which has now been removed from BusyBox + * Laurence Anderson and Glenn McGrath -- cpio applet, currently + only supports unpacking the ascii cpio format. + * Vladimir Oleynik and Erik Andersen -- added ash, the most correct + busybox shell. + * Larry Doolittle -- hush, small shell designed specifically + for busybox. Quite usable but still a work in progress. + * Erik Andersen -- msh, minix shell. A very small but capable shell + that only uses vfork, so it can be used on uClinux systems. + + Other Changes: + * Sterling Huxley -- Several bugfixes for the vi applet. + * Glenn McGrath -- Restructure unarchiving code to make more code + common to the ar, cpio, dpkg, dpkg-deb applets. + tar applet has not yet been assimilated... + * Matt Kraai -- Rewrote cp, dirname, mkdir, mv, and rm. + * Paul J.Y. Lahaie -- Fixed an endian-ness + bug in md5sum (in 0.51, md5sum on big endian machines was broken) + * Mark Whitley -- rewrote cut, major updates to grep and sed. + * Erik Andersen -- bunches of insmod fixes. It should now always + work (no more segfault or missing symbols problems). + * Bernhard Kuhn and Jinux Kim + added uClinux/m68k insmod support. + * Manuel Novoa III -- rewrote make_human_readable so ls, du, and df + should work as expected. Eliminated use of floats. + * Aaron Lehmann -- Scrubbed gzip.c + * Alan Modra -- fixed an hard to spot + bug breaking gunzip checksum checking. + * Gennady Feldman -- Fixed 'syslog -C' + * Gernot Poerner -- Added mount bind support. + * Adam Heath -- wget arbitrary header support + * John Beppu -- updated the automagical doc generator + * Zillions of other bugfixes, optimizations, and cleanups. + + + + -Erik Andersen, 7 July 2001 + + +0.51 + Critical Bugfixes: + * Erik Andersen -- Fixed a bug that could crash the shell in 0.50 + when pressing on an empty line. + * Gennady Feldman -- Fixed a bug that could crash the shell in 0.50 + when performing an 'export' in the shell. + * Gennady Feldman -- fixed a syslogd bug where syslogd could cause + the init process to block (which can break systems badly). + + New Applets: + * Sterling Huxley -- contributed a new vi applet! This is a very + functional vi implementation in Only 22k. + * Erik Andersen -- added env applet + + Other changes: + * Erik Andersen -- Split utility.c into libbb, which provides a + much cleaner was for us to include shared functionality. + * Erik Andersen -- Reorganized how and when busybox includes + syscalls, aiding portability and (in this case) making the + busybox work on ia64 systems. + * Erik Andersen -- dpkg.c cleanup to use the updated gunzip interface. + * Erik Andersen -- Cleanups for libc5, glibc, and uClibc. + * Erik Andersen and Matt Kraai -- Cleanups for the human-readable + output from ls, du, and df. + * Laurence Anderson -- Fixed wget HTTP 1.1 + support and added chunked encoding so it is now RFC compliant. + * John Beppu -- The busybox.pod documentation is now automagically + generated from the source code. This makes it _much_ simpler. + Now to update the docs, just update the usage message... + * Dirk Behme -- Adjusted MIPS insmod + support a bit for Mips RS3. + * Christophe Boyanique -- egrep invoked the "init" applet in 0.50! + * Larry Doolittle -- Added -Wshadow and fixed a number of shadowed + variables + * David Douthitt -- fixed 'find -print' + * Gennady Feldman -- fixes for the syslogd circular buffer code + * Jeff Garzik -- a number of structural cleanups, fixes for -Wshadow + bugs, and similar problems. + * Matt Kraai -- Added a new 'shutdown' action to busybox init. Now + you can specify arbitrary behavior for 'ctrlaltdel' so now + pressing CTL-ALT-DEL can do something else (or nothing). + * Andreas Neuhaus -- fix for merging + kernel command line environment variables into child environment + for init.c + * Glenn McGrath -- Fixed problems with dpkg and dpkg-deb applets + * Glenn McGrath -- Don't try to automount devfs + * Vladimir Oleynik -- optimizations for more.c + * Vladimir Oleynik -- Added locale support to the shell, and fixed + locale support in several other places + * Vladimir Oleynik -- moved struct applet from busybox.c to applets.c + * Vladimir Oleynik -- A size optimization for rdate + * Vladimir Oleynik -- Fixed printf applets's locale handling + * Vladimir Oleynik -- More cmdedit updates + * Vladimir Oleynik -- Fixed `du' applet so it continues running + after permission errors. + * Vladimir Oleynik -- Reduced stack usage in recursive_action() + * Pierre Peiffer -- made + find_pid_by_name() cope with swapped out processes. + * Jari Ruusu -- updates so that setting + D_FILE_OFFSET_BITS=64 now works as expected. + * Anthony Towns -- fixed a bug with + sed address range handling + * Dmitry Zakharov -- a number of updates + to wget: support for ftp downloads, basic HTTP basic auth, handling + of http redirects, when attempting to continue an aborted download + but server doesn't support restarts then reopen output file in + write mode, bugfix: when content-length not given, wget didn't + download anything, if -c is not specified, it no longer default to + restarting an aborted download. + + + -Erik Andersen, 10 April 2001 + + +0.50 + * Erik Andersen -- added ifconfig interface status reporting + * Erik Andersen -- Debian packaging updates + * Erik Andersen -- lash environment variable expansion rewritten, + with lots of help/fixes/testing from Larry Doolittle. + * Erik Andersen -- Fix use of busybox with dmalloc debugging lib + * Erik Andersen -- fixed ls behavior for broken or very narrow terminals + * Erik Andersen -- stub umount2 and pivot_root if they are not available + * Erik Andersen -- libc5 fixes + * Erik Andersen -- make init work with devfsd + * Erik Andersen -- fixed df for nfs and dos where blksize = 512 + * Erik Andersen -- Make sure libpwd.a is linked _last_ so it + overrides the system pwd/grp + * Christophe Boyanique -- added an optional egrep alias for grep. + * Christophe Boyanique -- added optional 'rm -i' support. + * Kenneth Chalmers and Erik Andersen -- fixed ln so it + behaves when given no arguments (prints usage) and when + given just one arg (tries to make a link in the cwd). + * Magnus Damm -- added a tftp applet + * Magnus Damm -- powerpc support for busybox insmod. + * David Douthitt -- fixed a build error in df.c when + BB_FEATURE_HUMAN_READABLE was disabled + * John Beppu -- wrote autodocifier.pl, which will be used to auto- + generate the documentation from the source code, making life + much simpler for all. + * Magnus Damm -- Fixed an 'inner scope var + masking outer scope var with same name' bug that prevented + the loopback device from being unmounted if mount() failed. + * Larry Doolittle -- rewrote ifconfig to make it smaller + * Larry Doolittle and Erik Andersen -- cleanups to pristine source + * Larry Doolittle -- many bugfixes resulting from regression testing + * Gennady Feldman -- split syslogd.c into syslogd and klogd + * Gennady Feldman -- make syslogd single threaded -- no more forking + * Jeff Garzik -- getopt-ified rmmod. + * Jeff Garzik -- glibc 2.2 warning cleanups + * Jeff Garzik -- namespace pollution cleanup (staticified variables). + * Erik Gustavsson -- allow env variables set on the + kernel command line to be inherited into init and its children. + * Erik Habbinga -- fixed an uninitialized substitution delimiter in sed. + * Chris Jaeger -- Makefile cleanup to make option setting less error-prone + * Chris Jaeger -- Carefully check NFS_MOUNT_VERSION + depending on what kernel is being used. + * Quinn Jensen -- MIPS support for busybox insmod. + * Evin Robertson -- new pivot_root applet + * Kent Robotti -- usage message cleanups + * Kent Robotti -- reworked dos2unix/unix2dos + * Evin Robertson and Manuel Novoa III -- reworked how usage messages + are stored to save several k of space. + * Matt Kraai -- Keep trying if an NFS mount fails + * Matt Kraai -- fixed insmod so it won't try to insmod directories. + * Matt Kraai -- added nc listening support + * Matt Kraai and David Douthitt -- reworked fine to support -type, + -perm, -mtime, and other improvements. + * Matt Kraai -- added find_applet_by_name and saved some memory thereby + * Matt Kraai -- added chomp to reduce redundant code elsewhere + * Matt Kraai -- Removed trailing \n chars from error_msg{,_and_die} messages. + * John Lombardo -- fixed OOM in insmod. + * Glenn McGrath -- bypass /proc in mount, now uses sysfs. + * Glenn McGrath -- several updates to dpkg and dpkg-deb. + * Manuel Novoa III -- several size optimizations: parse_mode, + process_escape_sequence, format, and get_kernel_revision. + * Manuel Novoa III -- rewrote ifconfig again to make it smaller still + * Manuel Novoa III -- added ifconfig -a, updated interface reporting + * Vladimir N. Oleynik -- Fixed a bug where init set PATH incorrectly + * Vladimir N. Oleynik -- cleanups to route, cmdedit, mkdir, + mkfs_minix, mkswap, chmod_chown_chgrp and utility.c + * Vladimir N. Oleynik -- many fixes to cmdedit. so tab completion + is now working and general editing is much improved, and to + improve complex prompt handling. + * Vladimir N. Oleynik -- added route status reporting. + * Vladimir N. Oleynik -- fixed wget to use xfopen + * Vladimir N. Oleynik -- new stty applet + * Vladimir N. Oleynik -- fixed find, it used to stop on perm errors. + * Vladimir N. Oleynik -- locale forced to posix for scripts + * Vladimir N. Oleynik -- saved 128 bytes by moving error checking + for several my_* functions into utility.c + * Bjorn Wesen -- new ifconfig and route applet (taken from + work done by Axis Communications). + * Mark Whitley -- Added a 'How to contribute to Busybox' doc + and updated the style guide. + * Mark Whitley -- implemented grep -A, -B, and -C + * Mark Whitley -- overhauled the test suite. + + + -Erik Andersen, 15 March 2001 + +0.49 + + * Matt Kraai -- new sort.c + * Matt Kraai -- new tail.c + * Glenn McGrath -- new 'dpkg-deb' applet + * Glenn McGrath -- new ar code + * spoon -- new watchdog applet + * Vladimir N. Oleynik -- fixed cmdedit.c so now + scrolling and tab completion in lash work properly. Also several + byte saving optimizations. + * Erik Andersen -- disabled many less commonly used applets by default + * Mark Whitley -- more thrashing about to get clean perror_msg usage + * Matt Kraai -- new command line munging + * Larry Doolittle -- keep some locales from messing up busybox.sh + * Matt Kraai -- cleaned up dd and tail with new parse_number routine + * Mark Whitley -- remove debugging messages from deallocvt + * Matt Kraai and Mark Whitley -- new document "How to Add a New Applet + to BusyBox" + * David Douthitt -- fixed "grep -qv" bug + * Larry Doolittle -- fixed insmod bug with old kernels + * Matt Kraai -- logger remixed to use getopt, selection of stdin made + util-linux compatible + * Erik Andersen -- many more internal symbols classified static to + avoid namespace pollution + * Matt Kraai -- nc listening support + * Erik Andersen -- made sed understand arbitrary regexp delimiters + * Matt Kraai et al. -- more tar improvements and bug fixes, now + handles regexp file exclusion + * Larry Doolittle -- new script (multibuild.pl) to automate build rule + checking + * Matt Kraai -- update/cleanup of the docs on how to use init + * Erik Andersen -- renamed all sh.c symbols per the style guide, + better if-then-else-fi handling + * Erik Andersen -- cleaner division of labor between cmdedit.c and sh.c + * Larry Doolittle -- shell data structure cleanup, fixed buglets + in read, exec, and piped builtins + * Erik Andersen -- md5sum was broken in 0.48. Now fixed (and doesn't + use getline, shrinking static compiles (since nothing else used it). + * ?? -- squashed memory leak in shell prompt handling + * Mark Whitley -- Updates to style guide + * Mark Whitley -- Big cleanup in utility.c: style guide compliance, + de-macro-ifying some variables and functions + * Erik Andersen -- ls now honors BB_FEATURE_AUTOWIDTH so it can find + the width and height of the console. + * Erik Andersen -- insmod now ignores -L and accepts the -o option. + * Erik Andersen -- updates so you can now select from the Makefile + whether or not to use the system's passwd and group functions. + Since most systems use GNU libc, this can save you from having to + install the /etc/nsswitch.conf configuration file and the required + libnss_* libraries. Adds 1.5k. You can now, also, disable this, + causing busybox to use the system's pwd.h and grp.h functions. + + + -Erik Andersen, 27 January 2001 + +0.48 + + * Glenn McGrath -- tar now supports uncompressing tar files, + define BB_FEATURE_TAR_GZIP to use the -z option. + * Matt Kraai -- fix all usage of TRUE and FALSE so all apps now + return EXIT_SUCCESS or EXIT_FAILURE to the system. + Now TRUE and FALSE are set to the C standard where TRUE=1. + * me -- Fixed uname problem causing the kernel version to be + mis-detected (causing problems with poweroff, init, + and other things). + * Alcove, Julien Gaulmin and + Nicolas Ferre -- insmod support on ARM + and StrongArm, and suport for lsmod on older 2.0.x kernels. + * Kent Robotti -- Renamed unrpm to original rpmunpack, so you can use + an included shell script called unrpm as a front end to it. There's + also a shell script called undeb included for debian packages. + * Matt Kraai -- fix an infinite loop with ls -aR + * Larry Doolittle -- Shaved off about 100 bytes and 200 bytes heap + from date.c. Also document the "-d" option in the usage message. + * Gennady Feldman -- fixed dd to use blocksize when reading/writing, + (it was reading the whole thing and then writing it out). Also + updated usage information (was missing conv=notrunc) and added + conv=sync feature. + * Larry Doolittle (in collaboration with Matt Kraai) -- allow for a + pristine source directory -- where all the .o files and such are + not placed into the source tree. Thanks Larry! + * Larry Doolittle -- use the applet definitions in applets.h + to autogenerate the applet function and usage prototypes. + * Sebastien Huet, Arne Bernin, and Kent Robotti -- Add in tar -X and + fixed a bug breaking tar --exclude. + * Jonas Holmberg -- echo option handling made GNU-echo compatible + * Aleksey Demidov -- date option handling made + GNU-date compatible + * me -- Progress meter (optional) in wget + * Doolittle/me -- programs invoked by full path name take + precedence over applets unless BB_FEATURE_SH_BUILTINS_ALWAYS_WIN + * Gaute B Strokkenes -- applets found using a + binary search instead of linear search. Much faster! + * new applets: cmp readlink + * Mark Whitley -- Removed advertising clause of Berkeley license + according to decision by the Regents of the University of + California; included reference + * tail's confusing special treatment of single digit options removed; + people should use -n instead + * Larry Doolittle -- \r handled now in echo and tr + * Matt Kraai -- rewrite of uniq + * Mark Whitley -- remix of xargs + * Jim Gleason -- fixed tar so it no longer breaks + hard links. + * Matt Kraai -- logger now logs all arguments, not just the first + * Gennady Feldman -- syslogd no longer logs to localhost if compiled + for remote logging... + * Richard June -- support for 'gzip -d' + * various artists -- Other good stuff that I forgot to document. + + + -Erik Andersen, 13 December 2000 + +0.47 + + * A bug in syslogd was fixed that allowed it to potentially fork-bomb + your system. Anyone using 0.46 syslogd should upgrade. + * Renamed busybox.defs.h to the more sensible "Config.h" + * Improved portability between different libcs. + * Many apps ported to use getopt() + * Common handling of '--help' + * All usage messages centralized. + * Added a bunch of new commands: + * 'rdate' contributed by Sterling Huxley + * 'wget' contributed by Chip Rosenthal , + and Covad Communications + * 'getopt' from "Alfred M. Szmidt" + * dos2unix, unix2dos, reset, and unrpm.c (and lots of help + debugging) thanks to Kent Robotti . + * 'renice' command, thanks to Dave Cinege + * 'xargs' (written by me) + * 'expr' contributed by Edward Betts , based + on GNY expr + * lsmod now uses the query_module syscall, rather then /proc (me) + * syslogd can now log messages to remote hosts -- patch thanks + to Gyepi Sam + * chroot can now call the builtin shell - Pavel Roskin + * 'make install' now creates relative symlinks, and added a new + 'make install-hardlinks' target to (tada) install hardlinks. + * Rewrite of 'tail' to make it simpler, smaller, and more robust. + It now weighs only 2.25k (3k when full featured). The code is + cleaner too, thanks to Allen Soard + * Add optional ls file sorting, thanks to a patch from + Sterling Huxley + * Fixed chmod option parsing so things like 'chmod -r /tmp/file' + now work (previously it thought -r was an option). Doh! + * Fixed tar handling of stdin and stdout + * Renamed "internal.h" to the more sensible "busybox.h" + * Preliminary support for GNU HURD. + * Updated my devps and devmtab kernel patches for the latest 2.2.x + kernel, for those wanting to go proc-less. + * Tons of other bugfixes. + + + -Erik Andersen, 25 September 2000 + + +0.46 + + * Better portability. Now should compile cleanly with libc5, + GNU libc 2.0 and 2.1, and various Linux kernels including + 2.0.x, 2.2.x, and to 2.4.0-test*. (patch for 2.4.x kernels + to make /proc/mounts behave included in the kernel-patches dir). + * Fixed a _horrible_ bug where 'tar -tvf' could unlink + local files that matched tarball contents!!! Fix thanks + to Marius Groeger + * Fixed a nasty bug in tar when could mess up saved symlinks. + * Fixed tar creation support when reading from stdin ('tar -cf - . ') + thanks to Daniel Quinlan + * Updates to handle Linux 2.4.0 kernels (kludged around the + "none" entries in /proc/mounts, added a hack to make sysinfo + work with both old and new kernels). + * Fixed insmod module option parsing for options lacking an '='. + Fix thanks to Marc Nijdam + * Fixed segfault with 'cut -f 1 -d:' and added 'cut -s' suport. + Fix thanks to Arne Bernin + * Several fixes from Marius Groeger + - Added support for "sh -c command args..." + - Fixed globbing, i.e. 'echo * *' and 'echo "******"' now work. + - Added shell environment variable substitution + - Added the "read" shell builtin. + * Fixed cursor editing in cmdedit.c. The following keyboard sequence + used to create an infinite loop: ls, cursor up, left, down. + * Added support for being a login shell, so things like + '-su' or '-sh' (stuff where argv[0][0]=='-') will now always + invoke the shell. Now you can use BusyBox as a login shell. + * ls.c now ignores '-g', since some ftp clients like that sort + of thing. Patch thanks to David Vrabel + * Fix to init.c from Stuart Menefy so that + it always sets the controlling terminal before running any programs + * Several fixes from Matt Kraai + - Fixed tr so it recognizes standard escape sequences. + Merged common escape seq. code from tr and echo into utility.c. + - Major work in updating/cleaning up the docs, and getting the + new SGML based docs into shape. + - cleanup of ar.c + - BusyBox should now poweroff when asked to do so. + - Fixed 'ln -n' and 'ln -s' so they both work properly. + * Reorganized signal names in kill.c for better architecture support + -- patch thanks to simon wood + * In 0.43, backspace and delete worked properly, but with 0.45, + it just echoed a ^? for backspace, and ^H for control-h. This + was due to a broken macro in init.c, that is now fixed. + * Removed sfdisk from BusyBox. It was buggy, fat, and we really + couldn't maintain it very well, so including it was not really + very appropriate. Those wanting an fdisk are invited to + grab a copy from util-linux. + * Added 'dumpkmap' to allow people to dump a binary keymap, which can + then be loaded in by 'loadkmap' -- submitted by + Arne Bernin + * Fixed NFS so it supports 2.4.x kernels and NFSv3. + * Brand, new versions of grep and sed which use libc regex routines, + thanks to Mark Whitley . The hand-tooled + "regexp.[ch]" files have been removed. Much help on these from + Matt Kraai as well. + + + -Erik Andersen, 11 July 2000 + + +0.45 + * Now compiles vs libc5 (which can save lots of space for + embedded systems). + * Added BB_FEATURE_TRIVIAL_HELP which compiles out most all of the + help messages (i.e --help). Saves 17k over a full compile. + * Added cut and tr from minix, since due to the license change, + we can now use minix code. Minix tr saves 4k. + * insmod now works. It costs 29k, but imagine an initrd with a + staticly linked busybox containing only insmod and sh, a few /dev + entries, and a kernel module or two... It doesn't get smaller + then this folks (I pity the fool that writes insmod in asm ;-). + Many kudos go to Ron Alder for finishing this off! + * Added a mini ar archive utility, especially written for BusyBox by + Glenn McGrath + * Added mktemp, contributed by Daniel Jacobowitz + * Added setkeycodes, for those that have weird keyboard buttons. + * Added md5sum, uuencode and uudecode -- thanks to Alfred M. Szmidt + for contributing these. + * Added 'grep -v' option (inverted search) and updated + docs accordingly. -beppu + * Wrote which + * Replaced the telnet implementation with one written by + Tomi Ollila It works great and costs 3k. + * BusyBox sh (lash) now supports being used as a standalone shell. When + BB_FEATURE_SH_STANDALONE_SHELL is defined, all the busybox commands may + be invoked as shell internals. Best used when compiling staticly + (i.e. DOSTATIC=true) + * BusyBox sh (lash) internals now behave as expected wrt pipes + and redirects. + * Fixed ping warnings -- fix from Sascha Ziemann + * Fixed update segfault + * Fixed mknod -- minor number was always 0 + * Fixed tar option parsing, so both "tar xvf foo.tar" and + "tar -xvf foo.tar" now work (i.e. no "-" before options) + (this was very broken in 0.43). + * Several contributions from Randolph Chung . + * cp/mv now accepts the -f flag + * tail can now accept - commands (e.g. -10) for better + compatibility with the standard tail command + * added a simple id implementation; doesn't support sup. groups yet + * logname used getlogin(3) which uses utmp. Now it doesn't. + * whoami used getpwuid(3) which uses libc NSS. Now it behaves. + * Add support for "noatime" and "nodiratime" mount flags to mount. + * Changed 'umount -f' to mean force, and actually use umount2. + * Changed 'umount -l' to mean "Do not free loop device". + * Fixed basename to support stripping of suffixes. Patch thanks + to xiong jianxin + * cp -fa now works as expected for symlinks (it didn't before) + * zcat now works (wasn't working since option parsing was broken) + * Renamed "mnc" to the more correct "nc" (for netcat). + * Makefile intelligence updates + * Changed the way init parses /etc/inittab entries to avoid problems + with commands that contain colons in them. Fix thanks to + Pavel Roskin + * Fixed a warning in utility.c due to char being unsigned on Linux/PPC, + Fix thanks to Pavel Roskin + * Made "killall" complain (not error and exit) about processes that it + cannot find by name -- Pavel Roskin + * Fixed more and ps to have sensible terminal width defaults, thanks + to Pavel Roskin. + * Fixed all fatalError() calls lacking a "\n", thanks to Pavel Roskin. + * Fixed a segfault in yes when no args were given -- Pavel Roskin. + * Simplified freeramdisk and added argument checking -- Pavel Roskin. + * Fixed segfault caused by "touch -c" + * Fixed segfault caused by "rm -f" + * Fixed segfault caused by "ln -s -s" and similar abuses. Further fixes + and "--" support from Pavel Roskin. + * Fixed segfault caused by "cp -a -a" and similar abuses. + * Implemented "rm -- ". Implementation fixed by Pavel Roskin. + * "which" rewritten to use stat(). Fixes to improve its compatability + with traditional implementations -- Pavel Roskin. + * "mount" now reports errors from nfsmount() and assumes NFS mount + if ':' is present in the device name - Pavel Roskin + * Fixed exit status for killall - Pavel Roskin + * Fixed 'swapon -a' and 'swapoff -a', which were broken. + * Fixed 'mount -a' so it works as expected. + * Implemented 'ls -R' (enabled by enabling BB_FEATURE_LS_RECURSIVE) + * Implemented "ping -s", fixed error messages and argument parsing - + Pavel Roskin + * Syslogd will not go to background if "-n" is given. Better help + and argument checking -- Pavel Roskin + * Fixed a small bug that could cause tar to emit warning messages + and not extract the first file in a directory in some cases + of nested directories. Thanks to Kevin Traas + for helping track this one down. + * More doc updates + * Fixed grep "Line too long" problem -- John Beppu + * Fixed 'grep -q -i B some_file' so it works + * math takes input from stdin if no args are given. -- John Beppu + * math was renamed to dc. Although it deviates from dc's behaviour, + this will probably be remedied in the future. -- John Beppu + + + -Erik Andersen, June 21, 2000 + + +0.44 + Previously, an erronous announcement of BusyBox 0.44 was made, so to + avoid possible confusion, we are skipping straight to 0.45, and calling + it good. + + -Erik Andersen + + +0.43 + * Major update to the provided documentation. + * Busybox now includes a shell! It currently costs 7.5 k (plus an + additional 2.5 k if you compile in command line editing). Handles + job control, has the usual set of builtins, and does everything + except for handling programming statements (if, while, etc...) + * Busybox can now work perfectly when /proc is disabled, thereby + saving a bunch of memory (kernel /proc support is not thin). This + is done by making use of some nice kernel patches I wrote up to + support the features that busybox requires and that /proc usually + provides. To enable this, turn on BB_FEATURE_USE_DEVPS_PATCH and + patch your kernel with the devps patch in the kernel-patches/ + directory. + * Wrote basename, dirname, killall, and uptime. + * tar has been completely rewritten by me. Both tar creation and + extraction are now well behaved. Costs 7.6k with all optional + tar features enabled, and 5k for just tar extraction support. + * Added freeramdisk, which will free up all memory associated + with a ram disk. Contributed by Emanuele Caratti + and then adjusted a bit by me. + * Added tr from John Lombardo + * Added echo and test (from me). + * Added usleep contributed by Nicolas Pitre + * BusyBox's bss size has been majorly reduced (was 384668, is now 28740). + * Several fixes from Pavel Roskin : + - When `tail' fails to open a file it now exits. + - When `syslogd' is given the `-n' option it should still use + fork() for running klogd. + * nslookup types are now changed to u_int32_t (instead of uint32_t) + changed per a patch from Pascal Bellard + * Fixed "du" so it gives the same answers as GNU "du" (busybox du used + to count hard-linked files more then once). Many thanks to + Friedrich Vedder for the fix. + * Removed /proc dependancies for init and free (while maintaining + exactly the same functionality). /proc takes up 90k of kernel + space, so it is nice to avoid using it at all costs. + * init no longer tries to mount /proc (unless there is less the 1 meg + free). Use of /proc (or not) is policy that should be set up in + /etc/fstab (or in hardcoded scripts), not in init. + * Fixed rebooting when init runs as an initrd. + * Fixes and updates from Karl M. Hegbloom + - update.c rewritten to look more like update-2.11 + - moveed the inode hash out of du.c and into utility.c to make + it a common resource that can be used by other apps. + - cp_mv.c now checks inodes to see if a source and dest are + the same, and prints an error (instead of endlessly looping). + - mv now attempts to do a rename, and will fall back to doing + a copy only if the rename fails. + - Syslogd now supports multiple concurrent connections + * Several fixes from Pavel Roskin : + - Fixes to sort. Removed "-g", fixed and added "-r" + - Fixes to the makefile for handling "strip" + * An initial telnet implementation was added by + Randolph Chung . + * Fixed a bug where "sed 's/foo/bar/g'" (i.e. a script w/o a "-e") + * ps now supports BB_FEATURE_AUTOWIDTH, and can adjust its width + to match the terminal (defaults to width=79 when this is off). + * ps now accepts (and ignores) all options except for "--help" (which + as would be expected displays help). + * Fixed mount'ing loop devices when the filesystem type was not + specified. It used to revert to non-loop after the first try. + * all mallocs now use xmalloc (and so are OOM error safe), and + the common error handling saves a few bytes. Thanks to + Bob Tinsley for the patch. + * Fix "+" parsing bug in date, from "Merle F. McClelland" . + * Fix symlink following bug in chmod -R and friends. + * Now allows SYSV style 'chown foo:bar' in addition to 'chown foo.bar' + * Fixed a bug in the busybox globbing routine such that 'find /dir -name [i]' + no longer segfaults. + + + -Erik Andersen + + +0.42 + + * Fairly massive restructuring of umount.c to deal with remounting + busy devices read-only. Adds a -r option to control that; it is + optionally compiled in with BB_FEATURE_REMOUNT + * Added a bunch of functions to mtab.c to interact with the + {get,set,end}mntent interface; as it turns out, those functions do + not appear to be re-entrant, and that causes a lot of problems with + the way umount was originally written. + * Makes init send TERM and KILL (instead of HUP and KILL) on reboot + to be more consistent with sysvinit + * Changes to init.c to use the new -r option to umount. Also increased + the sleep time between the time the TERM and KILL signals are sent + + - Randolph Chung + + + * cp.c, mv.c: removed, replaced by cp_mv.c which has been + extensively rewritten from the original cp.c. + * Fixed cp and mv so if the source and destination are a the + same directory it will print an error and continue. + * Also added a warning message to the `mv' usage string saying that + this is not GNU mv, and it will break hard links. cp also breaks + hard links. + * ln.c: implemented `-n' switch, no-deref symlinks. + * include: and use PATH_MAX everywhere. busybox: File + * name buffer overrun guards to prevent future crashes. + - Always check exit status. + - Purge all use of `creat()', replace with `open()'. + * utility.c + - recursiveAction was overriding the value of followLinks thus + ignoring it. + - isDirectory now takes a followLinks boolean, updated all callers + - copyFile had the followLinks logic reversed. + * messages.c: New file. Put common error message strings all in + one place in an attempt to shrink the binary a little. + + -Karl M. Hegbloom + + + * changed fsck_minix.c to reduce its .bss size significantly + -beppu -piptigger + * Made tar creation support in busybox tar optional. You no longer + * _have_ to put a "-" in front of tar options. Tar could inadvertently + * change permissions and ownership on + certain directories pointed to by symlinks. + * Made grep and grep -h do the right thing wrt printing + the file name (it failed to print files names in many cases). + * Fix a namespace aliasing problem wereby if du was built in, the + symlink for both du and dutmp would be installed, or then rm was + built in, the symlinks for both rm and rmmod would be installed. + * Added a closelog() to init.c after loging -- fix thanks to + Taketoshi Sano + * Rewrote and simplified logger. Added the "-t" option, and made it + behave itself a bit better. + * Optional support contributed by Ben Collins + for the kernel init chroot patch by Werner Almesberger, which + allows init to chroot to a new device, and umount the old one. + * Fixed bug that wouldn't let one chown a symlink -- it would + always dereference before. -beppu + * Fixed a bug where init could have reference already freed memory. + Found and fixed by Taketoshi Sano + * Several contributions from Friedrich Vedder + * Added (and documented) "-n" option for head + * Cleanup for a number of usage messages -- also + contributed Friedrich Vedder + * Cosmetic fix to busybox.c (Don't print a comma at the + end of line if there are no more application names). + * Fixed a stupid bug in "head" option handling ("head -n" + would segfault). + * Moved commonly used functions "xmalloc()" and "exit()" + to utility.c (with proper #ifdef's). + * Created a tiny tail implementation, removing -c, -q, -v, and making + tail -f work only with a single file. This reduced tail from 6k to + 2.4k. The bigger/more featured tail can still be had by disabling + BB_FEATURE_SIMPLE_TAIL in busybox.defs.h + * Ping now falls back to doing the right thing if /etc/protocols + turns up missing. + * Fixed mount and umount. Previously they could leak loop device + allocations, causing the system to quickly run out. Fix for umount + by Ben Collins , and mount was fixed by me. + * ls formatting on eight charactor user names fixed by + Randolph Chung . + * cp could, when copying symlinks, change permissions of the + files pointed to by the symlinks. + * Several fixes from Pavel Roskin : + - `chown' with 1 argument displayed the error incorrectly + - `fdflush', `length' and `printf' crashed if run without arguments + - `fdflush' tried to flush itself using *argv + - added "skip" and "seek" to dd. + - ls no longer messus up output when combining files and + directories on the command line + * swapoff -a was not working. Now it is. + * init did not cleanly unmount filesystems on reboot. Now it does. + * "sed -ne s/foo/bar/" worked but "sed -n -e s/foo/bar/" didn't. + Now both work. + * Some architectures (PowerPc) assume chars are unsigned, so they could + not distinguish between EOF and '\0xFF' in sed. Sed now uses ints. + * Began converting error handling to use some common routines + in utility.c + * syslogd now has better message handling and ignores SIGHUP. + * install.sh had a bug preventing installation to the specified + target directory. Fix from Gilbert Coville + * You can now spefify alternative strip commands -- change + also from Gilbert Coville. + + + -Erik Andersen + +0.41 + * New Apps: wc, hostid, logname, tty, whoami, yes -- all contributed + by Edward Betts + * Fixed a bug in both cp and mv preventing 'cp foo/README bar' + type commands (file in a directory to another directory) from + working. + * Fixed a logger bug that caused garbage to be written to the syslog + (unless you used busybox syslog, which hid the bug). Thanks to + Alex Holden for the fix. + * /bin/true and /bin/false were echoing a blank line when run. + Now fixed. + * mkdir -p would print an error when asked to mkdir an existing dir + with no interveining subdirectories. + * Fixed "syslogd -O" so that it works. Added -o loop option for mount, + * and support in umount for loop + devices. Support is toggled by MOUNT_LOOP feature -- Ben Collins + + * Several fixes from Marco Pantaleoni compile in + * fullWrite() not only if BB_TAR is defined, but also + if BB_CP or BB_MV are (fullWrite() is referenced by copyFile()) + * add some compiler optimizations to further reduce executable size + (as a side note, on my machines the largest code is generated + by gcc 2.95.2 with -Os ! The smallest by plain gcc 2.7.2.3 with + -O2 -m386 ...) + * Compile now won't fail if busybox.def.h defines + BB_FEATURE_LINUXRC but not BB_INIT. (init_main used to be + referenced, but not compiled) + * Fixed a bug in setting TERM for serial console support. TERM now + defaults to "ansi" for serial consoles. + * Fixed a bug in handling the CONSOLE env. variable for serial + * consoles. + + -Erik Andersen, Jan 15, 2000 + +0.40 + * New Apps: sort, uniq. -beppu New Apps: lsmod, rmmod -erik New Apps: + * fbset contributed by Randolph Chung . New App:: + * loadacm contributed by Peter Novodvorsky + for loading application character maps for Unicode fonts. + * Major init re-work. init now supports inittab (slightly different + but similar to sysvinit), allowing me to get all the policy out of + init and into the conf file. It works just fine without inittab + being present, but if you dont like the default behavior you can + now do something about it. Init is much cleaner as a result. + * Fixed an bug in syslogd causing it to stop after 20 minutes. -erik + * Fixed an embarrasing segfault in head -beppu Fixed the embarrasing + * failure of 'logger -p'. -erik Added the -s option to du -beppu + * Re-worked the source tree a bit so it will compile under glibc 2.0.7 + with the 2.0.x Linux kernel. + * Added 'grep -q' thanks to a patch from "Konstantin Boldyshev" + . + * Grep -i previously failed on UPPER CASE patterns due to a silly + regexp implementation bug that is now fixed. + * Fixed a bug where tar would set, and then clear SGID and SUID bits. + * Fixed a bug where tar would not set the user and group on device + special files. + * Fixed a bug where tar would not restore the time to files. Fixed a + * major security problem with tar -- it changed ownership + of any file pointed to by a symlink to 777 (like say libc....) + Ouch!!! + * cp and mv were very broken when moving directories. I have rewritten + them so they should now work as expected. + * sed now supports addresses (numeric or regexp, with negation) and + has an append command, thanks to Marco Pantaleoni + * Fixed dmesg. It wasn't parsing its options (-n or -s) properly. + * Some cosmetic fixes to ls output formatting to make it behave more + like GNU ls. + * Fixed a stupid segfault in kill. Several fixes from Friedrich Vedder + * : + - Added gunzip -t, removed gunzip.c dead code, + - fixed several typos + - Glibc 2.0.7 and libc5 compile fixes + * Fixed a bug where 'mknod --help' would segfault. + + + -Erik Andersen, Jan 07, 2000 + +0.39 + * New Apps: ping, hostname, and mkfifo contributed by Randolph Chung + . 3 items off the TODO list! + * I wrote free (just calls "cat /proc/meminfo"). Added tail, based on + * tail from GNU textutils-1.19, but adjusted + to suit my evil purposes. Costs 6k. I'll make it smaller + sometime. + * on reboot, init called 'umount -a -n', which caused errors + when BB_MTAB was not enabled. Changed to 'umount -a', which does + the right thing. + * init will now try to run /sbin/getty if it is present (for easy + integration with the about-to-be-released tinylogin.) + * kill now behaves itself properly, added 'kill -l' to list signals 'ls + * -l' was failing on long directories, since my_getid was leaking + one file descriptor per file. Oops. + * Fixed rebooting from init. I'd accidently left some debugging code + * in + which blocked reboots. + * Fixed reboot, halt (and added poweroff) such that they handle it when + init is not at PID 1 (like when running in an initrd). + * Added a prelinary du implementation. Some parameter parsing + stuff still needs to be added. -beppu (John Beppu + ) + * Implemented tee. -beppu Implemented head. -beppu + + -Erik Andersen, Dec 10, 1999 + +0.38 + * Fixed a segfault in 'umount -a' when a badly formed /etc/fstab + file existed. + * df will not exit on error, but will stat all mounted filesystems. + * Fixed tar so uid/gid/permissions on extracted tarballs will be + correct. + * Fixed find -name so it properly uses shell wildcard patterns + (i.e. `*', `?', and `[]') instead of regular expressions, which + was causing some confusing and unexpected behavior. + * Added klogd to syslogd, so now the log will contain both system and + kernel messages. + * syslogd now creates the /dev/log socket to make sure it is there, and + is actually a socket with the right permissions. + * I've taken a first step to making busybox not need the /proc + filesystem. Most apps don't need it. Those that _require_ it, + will complain if you enable them when you disable + BB_FEATURE_USE_PROCFS. + + -Erik Andersen, Dec 5, 1999 + +0.37 + * Wrote a micro syslogd, and a logger util (to log things to the syslog + from the command line or scripts) With both compiled in, costs 4k. + * Fixed 'make install' so symlinks are installed in their proper + * locations. Changed the build system slightly so that features can + * now be enabled + or disabled from the busybox.defs.h header file, without trying to + compile in a source file named after that featue (unless that file + exists). + * Several options are now moved into busybox.defs.h Now 'rm -R' and 'rm + * -r' both work. dd now properly handles input beyond 1 block from + * stdin. Fixed a bug where tar unpacked everything a directories. + * Moved some code + from createPath into mkdir where it belonged, thereby making tar + work properly. + * Fixed an off-by-one bug in cat. Given a list of file it wouldn't cat + * out the + last file in the list. + * Fixed 'ls -ln' so numeric group/uid are presented properly, and fixed + * 'ls -l' + so when uid/gid is not in /etc/{passwd,group} the numeric group/uid + are presented properly. + * Also added a TODO. + + + -Erik Andersen, Nov 25, 1999 + +0.36 + * fixed dd so it properly defaults to stdin and stdout when no + if= and of= are set (fix thanks to Eric Delaunay). + * Don't try to close the file descriptor of a pipein tar. (fix also + * from + Eric Delaunay). + * Made createPath be quiet (again thanks to Eric Delaunay). If + * BB_CONSOLE_CMD_IF_RC_SCRIPT_EXITS is defined, then whatever + command you define it as will be run if the init script exits. + * Updated install.sh to make it more robust (thanks to Adam Di Carlo) + * NFS support added to mount by Eric Delaunay. It costs 10k when + * compiled + in, but that is still a big win for those that use NFS. + * Made 'rm -f' be silent for non-existant files (thanks to Eric + * Delaunay). changed zcat.c to gunzip.c. It now obeys the principle + * of least surprise + and acts as god intended gunzip and zcat to act. They answer + --help and obey the '-c' flag. + * Fixed a bug in mv which caused it to not move files when the + * destination + was a directory. + * Fixed a decimal-instead-of-octal bug causing mkdir to make + * directories + with very wrong permissions. + * chmod would overwrite file permissions instead of modifying them. + Now it properly modifies permissions. + * Init now sends warnings destined for the console to /dev/console to + * ensure + they show up on whatever the active console it. Otherwise + important messages (for example that the system is rebooting) were + not seen when switched to a different VT. + + -Erik Andersen, Nov 17, 1999 + +0.35 + * gzip now obeys the principle of least surprise and acts like god + * intended + (i.e. it accepts a file name, answers --help, and obeys the '-c' + flag and only then outputs to stdout). + * Fixed more.c to compile autowidth on sparc and set initial winsize + to 0,0 in case the TIOCGWINSZ ioctl fails. Fix thanks to Eric + Delaunay. + * Fixed tar so it now works as expected (it had TRUE/FALSE backwards) + * tar now accepts --help chmod, chown, and chgrp usage now works + * General usage (i.e. --help) cleanups for most apps umount now parses + * options correctly tar can now unpack tarballs containing device + * special files, + sockets, and fifos (though it can't pack them up) thanks to Matt + Porter. Creating archives containing these is still left to the + interested student. + * fixed up the license in more.c to properly point to Bruce Perens. + + -Erik Andersen, Nov 11, 1999 + +0.34 + * ls -l now displays link names outside the current directory, + Patch thanks to Eric Delaunay + * init now properly handles sparc serial consoles and does a + better job of finding the real console device rather than using + /dev/console which doesn't support job control. Patch also thanks + to Eric Delaunay. + * more started to read from stdin after the last file was finished, and + options were not parsed correctly (fix thanks to Eric Delaunay). + * more will now use the terminal size if BB_FEATURE_AUTOWIDTH is on. + * rm wouldn't remove a symlink unless the symlink was valid. This was + a side effect of the busybox 0.32 recursiveAction() fix. Things + should now work correctly. + * grep wouldn't grep stdin. Now it does. sed wouldn't sed stdin. Now + * it does. sed was appending a \n to the end of lines with + * replacements. + Now it doesn't do that. + * ls -l now bypasses libc6 nss when displaying user/group names. + Now uses my_getpwuid and my_getgrgid. + + -Erik Andersen, Nov 8, 1999 + +0.33 + * Fixed a bug where init could hang instead of rebooting. + * Removed some debugging noise from init.c + * Fixed ln so it works now (it was very broken). + * Fixed df so it won't segfault when there is no /etc/fstab, + * If BB_MTAB is not defined, df and mount will whine if /etc/fstab + is not installed (since they cannot fixup "/dev/root" to + state the real root device name) + * merged some redundant code from mtab.c/df.c into utility.c + + -Erik Andersen, Nov 5, 1999 + +0.32 + * More changes -- many thanks to Lineo for paying me to work on + busybox. If you have any problems please let me know ASAP at + andersee@debian.org + * usage() now prints the BusyBox version. This will help folks + realize that they are not in Kansas anymore. + * Fixed mkdir -m option so that it works. kill segfaulted w/o any + * arguments. Now it doesn't do that. kill wasn't properly accepting + * signal names. It does now. Added new apps chvt and deallocvt (I + * should probably add open) Major rewrite of init.c. Code is now + * readable by mere mortals IMHO. Wrote sed -- weighs only 1.8k (5.8k + * with full regular expressions!). Fixed a stupid seg-fault in sync + * Fixed mount -- mount -a failed to parse and apply mount options Fixed + * umount -n (patch thanks to Matthew Grant ) + * umount -a no longer umounts /proc Added BB_MTAB, allowing (at the + * cost of ~1.5k and the need for a rw /etc) + folks to use a real /etc/mtab file instead of a symlink to + /proc/mounts. mount, and umount will add/remove entries and df + will now use /etc/mtab if BB_MTAB is defined. + * Fixed a nice bug in recursiveAction() which caused it to infinitely + hunt through /proc/../fd/* creating new file descriptors if it + followed the /dev/fd link over to /proc. recursiveAction() now + lstat's the file when followLinks==FALSE so it won't follow links + as the name suggests. Fix thanks to Matt Porter + . + + + -Erik Andersen, Nov 4, 1999 + +0.31 + * I added a changelog for version 0.30. adjusted find internals to + * make it smaller, and removed + some redundancy. + * Fixed a segfault in ps when /etc/passwd or /etc/group + are absent. Now will warn you and carry on. + * Added in optional _real_ regular expression support (to be + the basis for a future sed utility). When compiled in it adds + 3.9k, but makes grep much more capable. + * Checked out using nftw(3) for recursive stuff, but unfortunatly + it wasn't supported before GNU libc 2.1, and some folks use glibc + 2.0.7 since it is much smaller than that latest and greatest. + + -Erik Andersen, Oct 21, 1999 + +0.30 + Major changes -- lots of stuff rewritten. Many thanks to Lineo for + paying me to make these updates. If you have any problems with busybox, + or notice any bugs -- please let me know so I can fix it. These + changes include: + + Core Changes: + * busybox can now invoke apps in two ways: via symlinks to the + busybox binary, and as 'busybox [function] [arguments]...' + * When invoked as busybox, the list of currently compiled in + functions is printed out (no this is not bloat -- the list has + to be there anyway to map invocation name to function). + * busybox no longer parses command lines for apps or displays their + usage info. Each app gets to handle (or not handle) this for + itself. + * Eliminated monadic, dyadic, descend, block_device, and + postprocess. It was cumbersome to have so many programs + cobbled together in this way. Without them, the app is much + more granular. + * All shared code now lives in utility.c, and is properly + ifdef'ed to be only included for those apps requiring it. + * Eliminated struct FileInfo (the basis of monadic, dyadic, etc) + so now each app has the function prototype of (da-dum): extern + int foo_main(int argc, char** argv); which speeds integration + of new apps. + * Adjusted the Makefile to make it easier to + {en|dis}able debugging. + * Changed default compiler optimization to -Os + (optimize for smaller binaries). + + App Changes: + * To cope with the new app function prototype and the removal of + monadic, dyadic, etc, the following apps were re-written: + * cat - Works same as always. chgrp, chmod, chown - + * rewrite. Combined into a single + source file. Absorbed patches from Enrique Zanardi + that removes the dependency on + libc6 libnss* libraries. + * cp - Can now do 'cp -a' can can copy devices, + pipes, symlinks, as well as recursive or non-recursive + dir copies. + * fdflush - adjusted to remove dependancy on struct + * FileInfo. find - Now includes some basic regexp matching + which will be the basic of a future mini-sed. + * ln - Same functionality. mkdir - Added -p flag to + * feature set. mv - rewrite. rm - Added -f flag to + * feature set. rmdir - Same functionality. swapon, + * swapoff - Combined into a single binary. No longer + uses /etc/swaps. swap{on|off} -a uses /etc/fstab + instead. + * touch - Same functionality. date - adjusted with a patch + * from Matthew Grant + to accomodate glibc timezone support. I then ripped out GNU + getopt. + * mkswap -- new version merged from util-linux. Can now make + >128Meg swaps. + * Replaced the old and star, unstar, and tarcat with the tar + implementation from sash. Now tar behaves as god intended it + to (i.e. tar -xvf and tar -cf work). + * dd -- rewritten. Can with with files, stdin, stdout. Added the + * following new apps: loadfont -- added from debian boot floppies + * chroot -- added based on a patch from Paolo Molaro + * grep -- I just wrote it. Only matches + * simple strings ps -- I just wrote it. Has _no_ options at all, + * but works. fsck_minix, mkfs_minix -- added from util-linux, but + * I ripped out + internationalization and such to make them smaller. + * sfdisk -- Added from util-linux (minus + * internationalization and such). Probably some other + * changes that I forgot to document... + + -Erik Andersen, Oct 20, 1999 + +0.29 + This version was a messy pre-alpha. stay away or it will bite you. + -Erik Andersen, Sep 24, 1999 + +0.28 + mini-netcat (mnc) rewritten. + +0.27 + Mount now supports -a, and -t auto. + Mount now updates mtab correctly for 'ro'. + More checks screen rows size, outputs bytes percentage. + Printf added as module. +0.26 + Touch now creates files. -c option for no create. + diff --git a/Changelog.full b/Changelog.full new file mode 100644 index 000000000..490283135 --- /dev/null +++ b/Changelog.full @@ -0,0 +1,138 @@ +2002-10-27 Erik Andersen + + * Makefile: Increment version number + + * debian/control, debian/changelog: Update packaging info + +2002-10-26 Erik Andersen + + * debian/Config.h-udeb: + Don't support init being run as /linux in the debian installer + -Erik + + * swaponoff.c: last_patch64 from vodz: + + The following usage from original user: + $ ./busybox swapon -a + Have typo problem: + swapon: swapon: Operation not permitted + + But regular version: + swapon: /dev/hda5: Operation not permitted + + Patch attached, reduced 9 bytes and advanced + exit code also. + + * vi.c: + A patch from Jouni Malinen to avoid some buffer overflows in vi, + closing bug #1270 + + * Makefile: Ivan Popov noticed that handling of PREFIX was bad. + -Erik + +2002-10-25 Erik Andersen + + * tftp.c: This patch from Magnus Damm fixed a long standing problem + with freeing memory. + +2002-10-23 Erik Andersen + + * top.c: Backport vodz' reworked top applet from unstable + +2002-10-22 Erik Andersen + + * ash.c, ifconfig.c: Fix warnings + + * md5sum.c: Fix undefined operation (temp = temp = ) and remove + double definition. + -Erik + + * init.c: I committed the fflush in the wrong spot. I should go to bed + earlier so I don't screw up such easy stuff. + -Erik + + * ash.c: Apply last_patch51_3 from vodz + + * init.c: Be absurdly careful about flushing stdout. + +2002-10-18 Erik Andersen + + * tests/sh.testcases: Missed a spot + + * tests/sh.testcases: disambiguate a test + + * lsmod.c: Fixup some needless formatting differences vs modutils + + * hostname.c: + Fixup slight difference in 'hostname -d' behavior vs GNU hostname + +2002-10-12 Erik Andersen + + * init.c: + After thinking about it, I think this patch from Matt Kraai is probably the + best way to go. Sysvinit does not provide a controlling tty since it doesn't + even try to open ttys for apps. We do. We we should _try_ to provide a + controlling tty if possible, but we needn't freak out if it doesn't work. So + we won't need to use openvt or similar, we'll just have init do the Right + Thing(tm). + +2002-10-08 Erik Andersen + + * docs/.cvsignore: oops + + * docs/.cvsignore, Makefile: Remove docs/busybox.pod on 'make clean' + + * init.c: + Patch from Ben Gamsa to handle it when orphaned + processes are created faster than busybox init reaps them. + + * lsmod.c: Fix missing \n noticed by Robert Schwebel + + * debian/Config.h-udeb: Enable pidof + + * libbb/copy_file.c: + Doh! It turns out I broke 'cp -a' symlink handling. Oops. This fix, from + Tollef Fog Heen fixes my stupid thinko so that 'cp -a' once + again copies symlinks properly. + +2002-09-30 Erik Andersen + + * usage.h: Fix docs + + * lash.c: + Use %m, not strerror (changing since strerror(err) was broken anyways) + + * init.c: Set the close-on-exec flag, just to be safe + + * time.c: Doh. We divide microseconds by 60? + +2002-09-27 Erik Andersen + + * time.c: Bug fix from Nitin Gupta + +2002-09-26 Erik Andersen + + * lash.c: Avoid calling exit() from within fork/vfork'ed processes. + -Erik + +2002-09-25 Erik Andersen + + * init.c: + Ignoring SIGCHLD causes a race leading to the occasional hang of init + when init will wait() on itself in waitfor() when the child exits before + init is scheduled to run. Letting init hang is very seriously bad. + -Erik + +2002-09-22 Erik Andersen + + * Makefile: Fixup largefile settings. + -Erik + +2002-09-20 Erik Andersen + + * gunzip.c: Doh! As noted by K.-P. Kirchdörfer" , + gunzip -c deletes the source source file! This fixes it. + -Erik + + * top.c: Don't leak FILEs + diff --git a/Config.h b/Config.h new file mode 100644 index 000000000..c5ece5939 --- /dev/null +++ b/Config.h @@ -0,0 +1,494 @@ +/* vi: set sw=4 ts=4: */ +// This file defines the feature set to be compiled into busybox. +// When you turn things off here, they won't be compiled in at all. +// +//// This file is parsed by sed. You MUST use single line comments. +// i.e., //#define BB_BLAH +// +// +// BusyBox Applications +//#define BB_ADJTIMEX +//#define BB_AR +#define BB_ASH +#define BB_BASENAME +#define BB_CAT +#define BB_CHGRP +#define BB_CHMOD +#define BB_CHOWN +#define BB_CHROOT +#define BB_CHVT +#define BB_CLEAR +//#define BB_CMP +#define BB_CP +//#define BB_CPIO +#define BB_CUT +#define BB_DATE +//#define BB_DC +#define BB_DD +//#define BB_DEALLOCVT +#define BB_DF +#define BB_DIRNAME +#define BB_DMESG +//#define BB_DOS2UNIX +//#define BB_DPKG +//#define BB_DPKG_DEB +//#define BB_DUTMP +#define BB_DU +//#define BB_DUMPKMAP +#define BB_ECHO +#define BB_ENV +//#define BB_EXPR +//#define BB_FBSET +//#define BB_FDFLUSH +#define BB_FIND +#define BB_FREE +//#define BB_FREERAMDISK +//#define BB_FSCK_MINIX +//#define BB_GETOPT +#define BB_GREP +#define BB_GUNZIP +#define BB_GZIP +#define BB_HALT +#define BB_HEAD +//#define BB_HOSTID +//#define BB_HOSTNAME +//#define BB_HUSH +#define BB_ID +//#define BB_IFCONFIG +#define BB_INIT +//#define BB_INSMOD +#define BB_KILL +#define BB_KILLALL +#define BB_KLOGD +//#define BB_LASH +//#define BB_LENGTH +#define BB_LN +//#define BB_LOADACM +//#define BB_LOADFONT +//#define BB_LOADKMAP +#define BB_LOGGER +//#define BB_LOGNAME +//#define BB_LOSETUP +#define BB_LS +#define BB_LSMOD +//#define BB_MAKEDEVS +//#define BB_MD5SUM +#define BB_MKDIR +//#define BB_MKFIFO +//#define BB_MKFS_MINIX +#define BB_MKNOD +#define BB_MKSWAP +//#define BB_MKTEMP +#define BB_MODPROBE +#define BB_MORE +#define BB_MOUNT +//#define BB_MSH +//#define BB_MT +#define BB_MV +//#define BB_NC +//#define BB_NSLOOKUP +#define BB_PIDOF +//#define BB_PING +//#define BB_PIVOT_ROOT +#define BB_POWEROFF +//#define BB_PRINTF +#define BB_PS +#define BB_PWD +//#define BB_RDATE +//#define BB_READLINK +#define BB_REBOOT +//#define BB_RENICE +#define BB_RESET +#define BB_RM +#define BB_RMDIR +//#define BB_RMMOD +//#define BB_ROUTE +//#define BB_RPM2CPIO +#define BB_SED +//#define BB_SETKEYCODES +#define BB_SLEEP +#define BB_SORT +//#define BB_STTY +#define BB_SWAPONOFF +#define BB_SYNC +#define BB_SYSLOGD +#define BB_TAIL +#define BB_TAR +//#define BB_TEE +//#define BB_TEST +//#define BB_TELNET +//#define BB_TFTP +//#define BB_TIME +//#define BB_TOP +#define BB_TOUCH +//#define BB_TR +//#define BB_TRACEROUTE +#define BB_TRUE_FALSE +#define BB_TTY +//#define BB_UNIX2DOS +//#define BB_UUENCODE +//#define BB_UUDECODE +#define BB_UMOUNT +#define BB_UNIQ +#define BB_UNAME +//#define BB_UPDATE +#define BB_UPTIME +//#define BB_USLEEP +//#define BB_VI +//#define BB_WATCHDOG +#define BB_WC +//#define BB_WGET +#define BB_WHICH +#define BB_WHOAMI +#define BB_XARGS +#define BB_YES +// End of Applications List +// +// +// +// --------------------------------------------------------- +// This is where feature definitions go. Generally speaking, +// turning this stuff off makes things a bit smaller (and less +// pretty/useful). +// +// +// If you enabled one or more of the shells, you may select which one +// should be run when sh is invoked: +#define BB_FEATURE_SH_IS_ASH +//#define BB_FEATURE_SH_IS_HUSH +//#define BB_FEATURE_SH_IS_LASH +//#define BB_FEATURE_SH_IS_MSH +// +// BusyBox will, by default, malloc space for its buffers. This costs code +// size for the call to xmalloc. You can use the following feature to have +// them put on the stack. For some very small machines with limited stack +// space, this can be deadly. For most folks, this works just fine... +//#define BB_FEATURE_BUFFERS_GO_ON_STACK +// The third alternative for buffer allocation is to use BSS. This works +// beautifully for computers with a real MMU (and OS support), but wastes +// runtime RAM for uCLinux. This behavior was the only one available for +// BusyBox versions 0.48 and earlier. +//#define BB_FEATURE_BUFFERS_GO_IN_BSS +// +// Turn this on to use Erik's very cool devps, and devmtab kernel drivers, +// thereby eliminating the need for the /proc filesystem and thereby saving +// lots and lots memory for more important things. NOTE: If you enable this +// feature, you _must_ have patched the kernel to include the devps patch that +// is included in the busybox/kernel-patches directory. You will also need to +// create some device special files in /dev on your embedded system: +// mknod /dev/mtab c 10 22 +// mknod /dev/ps c 10 21 +// I emailed Linus and this patch will not be going into the stock kernel. +//#define BB_FEATURE_USE_DEVPS_PATCH +// +// show verbose usage messages +#define BB_FEATURE_VERBOSE_USAGE +// +// Use termios to manipulate the screen ('more' is prettier with this on) +//#define BB_FEATURE_USE_TERMIOS +// +// calculate terminal & column widths (for more, ls, and telnet) +#define BB_FEATURE_AUTOWIDTH +// +// show username/groupnames for ls +#define BB_FEATURE_LS_USERNAME +// +// show file timestamps in ls +#define BB_FEATURE_LS_TIMESTAMPS +// +// enable ls -p and -F +#define BB_FEATURE_LS_FILETYPES +// +// sort the file names +#define BB_FEATURE_LS_SORTFILES +// +// enable ls -R +#define BB_FEATURE_LS_RECURSIVE +// +// enable ls -L +#define BB_FEATURE_LS_FOLLOWLINKS +// +// Use color to identify different file types +#define BB_FEATURE_LS_COLOR +// +// Disable for a smaller (but less functional) ping +#define BB_FEATURE_FANCY_PING +// +// Make init use a simplified /etc/inittab file (recommended). +#define BB_FEATURE_USE_INITTAB +// +//Enable init being called as /linuxrc +#define BB_FEATURE_LINUXRC +// +//Have init enable core dumping for child processes (for debugging only) +//#define BB_FEATURE_INIT_COREDUMPS +// +//Make sure nothing is printed to the console on boot +//#define BB_FEATURE_EXTRA_QUIET +// +// enable syslogd -R remotehost +#define BB_FEATURE_REMOTE_LOG +// +// enable syslogd -C +//#define BB_FEATURE_IPC_SYSLOG +// +//Disable for a simple tail implementation (2.34k vs 3k for the full one). +//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. +#define BB_FEATURE_FANCY_TAIL +// +// Enable support for loop devices in mount +#define BB_FEATURE_MOUNT_LOOP +// +// Enable support for a real /etc/mtab file instead of /proc/mounts +//#define BB_FEATURE_MTAB_SUPPORT +// +// Enable support for mounting remote NFS volumes. +// You may need to mount with "-o nolock" if you are +// not running a local portmapper daemon... +// +// If you are using uClibc, be sure that you've already compiled +// uClibc with INCLUDE_RPC=true (contained in the Config file) +//#define BB_FEATURE_NFSMOUNT +// +// Enable support forced filesystem unmounting +// (i.e., in case of an unreachable NFS system). +#define BB_FEATURE_MOUNT_FORCE +// +// Enable support for creation of tar files. +#define BB_FEATURE_TAR_CREATE +// +// Enable support for "--exclude" and "-X" for excluding files +#define BB_FEATURE_TAR_EXCLUDE +// +// Enable support for tar -z option (currently only works for inflating) +#define BB_FEATURE_TAR_GZIP +// +// Enable reverse sort +#define BB_FEATURE_SORT_REVERSE +// +// Enable uniqe sort +#define BB_FEATURE_SORT_UNIQUE +// +// Enable command line editing in the shell. +// Only relevant if a shell is enabled. On by default. +#define BB_FEATURE_COMMAND_EDITING +// +// Enable tab completion in the shell. This is now working quite nicely. +// This feature adds a bit over 4k. Only relevant if a shell is enabled. +#define BB_FEATURE_COMMAND_TAB_COMPLETION +// +// Attempts to match usernames in a ~-prefixed path +//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION +// +//Allow the shell to invoke all the compiled in BusyBox applets as if they +//were shell builtins. Nice for staticly linking an emergency rescue shell, +//among other things. Off by default. +// Only relevant if a shell is enabled. +//#define BB_FEATURE_SH_STANDALONE_SHELL +// +//When this is enabled, busybox shell applets can be called using full path +//names. This causes applets (i.e., most busybox commands) to override +//real commands on the filesystem. For example, if you run run /bin/cat, it +//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_ +//busybox. Some systems want this, others do not. Choose wisely. :-) This +//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled. +// Only relevant if a shell is enabled. Off by default. +//#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN +// +// Uncomment this option for a fancy shell prompt that includes the +// current username and hostname. On systems that don't have usernames +// or hostnames, this can look hideous. +// Only relevant if a shell is enabled. +//#define BB_FEATURE_SH_FANCY_PROMPT +// +// Uncomment this option to disable job control. Job control lets you +// run jobs in the background (which completely useless for is all you +// are doing is running scripts). Disabing this is bad for interactive +// use, since when you hit ^C in an application, it will also kill the +// shell. This adds about 2.5k on an x86 system. +#define BB_FEATURE_ASH_JOB_CONTROL +// +//Turn on extra fbset options +//#define BB_FEATURE_FBSET_FANCY +// +//Turn on fbset readmode support +//#define BB_FEATURE_FBSET_READMODE +// +// Support insmod/lsmod/rmmod for post 2.1 kernels +#define BB_FEATURE_NEW_MODULE_INTERFACE +// +// Support insmod/lsmod/rmmod for pre 2.1 kernels +//#define BB_FEATURE_OLD_MODULE_INTERFACE +// +// Support module version checking +//#define BB_FEATURE_INSMOD_VERSION_CHECKING +// +// Support for uClinux memory usage optimization, which will load the image +// directly into the kernel memory. This divides memory requrements by three. +// If you are not running uClinux (i.e., your CPU has an MMU) leave this +// disabled... +//#define BB_FEATURE_INSMOD_LOADINKMEM +// +// Support for Minix filesystem, version 2 +//#define BB_FEATURE_MINIX2 +// +// Enable ifconfig status reporting output -- this feature adds 7k. +//#define BB_FEATURE_IFCONFIG_STATUS +// +// Enable ifconfig slip-specific options "keepalive" and "outfill" +//#define BB_FEATURE_IFCONFIG_SLIP +// +// Enable ifconfig options "mem_start", "io_addr", and "irq". +//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ +// +// Enable ifconfig option "hw". Currently works for only with "ether". +//#define BB_FEATURE_IFCONFIG_HW +// +// Allows "broadcast +" to set broadcast automatically based on hostaddr +// and netmask, at a cost of about 100 bytes of code (i386). +//#define BB_FEATURE_IFCONFIG_BROADCAST_PLUS +// +// Enable busybox --install [-s] +// to create links (or symlinks) for all the commands that are +// compiled into the binary. (needs /proc filesystem) +//#define BB_FEATURE_INSTALLER +// +// Enable a nifty progress meter in wget (adds just under 2k) +#define BB_FEATURE_WGET_STATUSBAR +// +// Enable HTTP authentication in wget +#define BB_FEATURE_WGET_AUTHENTICATION +// +// Clean up all memory before exiting -- usually not needed +// as the OS can clean up... Don't enable this unless you +// have a really good reason for cleaning things up manually. +//#define BB_FEATURE_CLEAN_UP +// +// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G) +#define BB_FEATURE_HUMAN_READABLE +// +// Support for the find -type option. +#define BB_FEATURE_FIND_TYPE +// +// Support for the find -perm option. +#define BB_FEATURE_FIND_PERM +// +// Support for the find -mtime option. +#define BB_FEATURE_FIND_MTIME +// +//// Support for the find -newer option. +#define BB_FEATURE_FIND_NEWER +// +// Support for the -A -B and -C context flags in grep +//#define BB_FEATURE_GREP_CONTEXT +// +// Support for the EGREP applet (alias to the grep applet) +//#define BB_FEATURE_GREP_EGREP_ALIAS +// +// Tell tftp what commands that should be supported. +#define BB_FEATURE_TFTP_PUT +#define BB_FEATURE_TFTP_GET +// +// features for vi +#define BB_FEATURE_VI_COLON // ":" colon commands, no "ex" mode +#define BB_FEATURE_VI_YANKMARK // Yank/Put commands and Mark cmds +#define BB_FEATURE_VI_SEARCH // search and replace cmds +#define BB_FEATURE_VI_USE_SIGNALS // catch signals +#define BB_FEATURE_VI_DOT_CMD // remember previous cmd and "." cmd +#define BB_FEATURE_VI_READONLY // vi -R and "view" mode +#define BB_FEATURE_VI_SETOPTS // set-able options, ai ic showmatch +#define BB_FEATURE_VI_SET // :set +#define BB_FEATURE_VI_WIN_RESIZE // handle window resize +// +// Enable a if you system have setuped locale +//#define BB_LOCALE_SUPPORT +// +// Support for TELNET to pass TERM type to remote host. Adds 384 bytes. +#define BB_FEATURE_TELNET_TTYPE +// +// Support for devfs. +//#define BB_FEATURE_DEVFS +// +// End of Features List +// +// +// +// +// +// +//--------------------------------------------------- +// Nothing beyond this point should ever be touched by +// mere mortals so leave this stuff alone. +// +#include +#if defined(__uClinux__) + #undef BB_ASH /* Not even a chance it will work */ + #undef BB_RPM2CPIO /* Uses gz_open(), which uses fork() */ + #undef BB_DPKG_DEB /* Uses gz_open(), which uses fork() */ + #undef BB_FEATURE_TAR_GZIP /* Uses fork() */ + #undef BB_UPDATE /* Uses daemon() */ +#endif +#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH + #if defined BB_FEATURE_COMMAND_EDITING + #define BB_CMDEDIT + #else + #undef BB_FEATURE_COMMAND_EDITING + #undef BB_FEATURE_COMMAND_TAB_COMPLETION + #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION + #undef BB_FEATURE_SH_FANCY_PROMPT + #endif +#else + #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN + #undef BB_FEATURE_SH_STANDALONE_SHELL + #undef BB_FEATURE_SH_FANCY_PROMPT +#endif +// +#if (defined BB_ASH || defined BB_HUSH || defined BB_MSH) && ! defined BB_TEST + #define BB_TEST +#endif +// +#ifdef BB_KILLALL + #ifndef BB_KILL + #define BB_KILL + #endif +#endif +// +#ifndef BB_INIT + #undef BB_FEATURE_LINUXRC +#endif +// +#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT + #define BB_NFSMOUNT +#endif +// +#if defined BB_FEATURE_AUTOWIDTH + #ifndef BB_FEATURE_USE_TERMIOS + #define BB_FEATURE_USE_TERMIOS + #endif +#endif +// +#if defined BB_INSMOD || defined BB_LSMOD + #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE + #define BB_FEATURE_NEW_MODULE_INTERFACE + #endif +#endif +// +#ifdef BB_UNIX2DOS + #define BB_DOS2UNIX +#endif +// +#ifdef BB_SYSLOGD + #if defined BB_FEATURE_IPC_SYSLOG + #define BB_LOGREAD + #endif +#endif +// +#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH +# define shell_main ash_main +#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH +# define shell_main hush_main +#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH +# define shell_main lash_main +#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH +# define shell_main msh_main +#endif diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..e17bd80d3 --- /dev/null +++ b/INSTALL @@ -0,0 +1,8 @@ +1) Check Config.h and adjust if you need a different functionality than + defined by default. + +2) Check the Makefile + +3) make + +4) make install diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..3f792d018 --- /dev/null +++ b/LICENSE @@ -0,0 +1,377 @@ +Original release code (unless otherwise noted) +Copyright 1995, 1996 Bruce Perens + +mkswap +Copyright 1991 Linus Torvalds + +tiny-ls(ls) +Copyright 1996 Brian Candler + +tarcat, loadkmap, various fixes, Debian maintenance +Copyright 1998 Enrique Zanardi + +more(v2), makedevs, dutmp, modularization, auto links file, +various fixes, Linux Router Project maintenance +Copyright 1998 Dave Cinege + +mini-gzip(gzip), mini-netcat(mnc) +Copyright 1998 Charles P. Wright + +Tons of new stuff as noted in header files +Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen +Copyright (C) 1999,2000,2001 by Erik Andersen + + +Please feed suggestions, bug reports, insults, and bribes back to: + Erik Andersen + + + + + +Busybox may be used and distributed under the GNU General Public License. + +--------------------------------------------------------------------------- + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..331929365 --- /dev/null +++ b/Makefile @@ -0,0 +1,487 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2002 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 +# + +PROG := busybox +VERSION := 0.60.5 +BUILDTIME := $(shell TZ=UTC date -u "+%Y.%m.%d-%H:%M%z") +export VERSION + +# With a modern GNU make(1) (highly recommended, that's what all the +# developers use), all of the following configuration values can be +# overridden at the command line. For example: +# make CROSS=powerpc-linux- BB_SRC_DIR=$HOME/busybox PREFIX=/mnt/app + +# If you want to add some simple compiler switches (like -march=i686), +# especially from the command line, use this instead of CFLAGS directly. +# For optimization overrides, it's better still to set OPTIMIZATION. +CFLAGS_EXTRA = + +# If you want a static binary, turn this on. +DOSTATIC = false + +# Set the following to `true' to make a debuggable build. +# Leave this set to `false' for production use. +DODEBUG = false + +# If you enable this option, busybox will use the system's password +# and group functions. And if you are using the GNU C library +# (glibc), you will then need to install the /etc/nsswitch.conf +# configuration file and the required /lib/libnss_* libraries in +# order for the password and group functions to work. This generally +# makes your embedded system quite a bit larger. +# Disabling this option will cause busybox to directly access the +# system's /etc/password, /etc/group files (and your system will be +# smaller, and I will get fewer emails asking about how glibc NSS +# works). When this option is disabled, you will not be able to use +# PAM to access remote LDAP password servers and whatnot. And if you +# want hostname resolution to work with glibc, you still need the +# /lib/libnss_* libraries. +# If you disable this option, it will add about 1.5k to busybox. +USE_SYSTEM_PWD_GRP = true + +# This enables compiling with dmalloc ( http://dmalloc.com/ ) +# which is an excellent public domain mem leak and malloc problem +# detector. To enable dmalloc, before running busybox you will +# want to first set up your environment. +# eg: `export DMALLOC_OPTIONS=debug=0x34f47d83,inter=100,log=logfile` +# The debug= value is generated using the following command +# dmalloc -p log-stats -p log-non-free -p log-bad-space -p log-elapsed-time \ +# -p check-fence -p check-heap -p check-lists -p check-blank \ +# -p check-funcs -p realloc-copy -p allow-free-null +# Do not enable this for production builds... +DODMALLOC = false + +# Electric-fence is another very useful malloc debugging library. +# Do not enable this for production builds... +DOEFENCE = false + +# If you want large file summit support, turn this on. +# This has no effect if you don't have a kernel with lfs +# support, and a system with libc-2.1.3 or later. +# Some of the programs that can benefit from lfs support +# are dd, gzip, mount, tar, and mkfs_minix. +# LFS allows you to use the above programs for files +# larger than 2GB! +DOLFS = false + +# If you have a "pristine" source directory, point BB_SRC_DIR to it. +# Experimental and incomplete; tell the mailing list +# if you do or don't like it so far. +BB_SRC_DIR = + +# If you are running a cross compiler, you may want to set this +# to something more interesting, like "powerpc-linux-". +CROSS = +CC = $(CROSS)gcc +AR = $(CROSS)ar +STRIP = $(CROSS)strip + +# To compile vs uClibc, just use the compiler wrapper built by uClibc... +# Everything should compile and work as expected these days... +#CC=/usr/i386-linux-uclibc/bin/i386-uclibc-gcc + +# To compile vs some other alternative libc, you may need to use/adjust +# the following lines to meet your needs... +# +# If you are using Red Hat 6.x with the compatible RPMs (for developing under +# Red Hat 5.x and glibc 2.0) uncomment the following. Be sure to read about +# using the compatible RPMs (compat-*) at http://www.redhat.com ! +#LIBCDIR=/usr/i386-glibc20-linux +# +# The following is used for libc5 (if you install altgcc and libc5-altdev +# on a Debian system). +#LIBCDIR=/usr/i486-linuxlibc1 +# +# For other libraries, you are on your own... +#LDFLAGS+=-nostdlib +#LIBRARIES = $(LIBCDIR)/lib/libc.a -lgcc +#CROSS_CFLAGS+=-nostdinc -I$(LIBCDIR)/include -I$(GCCINCDIR) +#GCCINCDIR = $(shell gcc -print-search-dirs | sed -ne "s/install: \(.*\)/\1include/gp") + +WARNINGS = -Wall -Wshadow + +ARFLAGS = -r + + +TARGET_ARCH:=${shell $(CC) -dumpmachine | sed -e s'/-.*//' \ + -e 's/i.86/i386/' \ + -e 's/sparc.*/sparc/' \ + -e 's/arm.*/arm/g' \ + -e 's/m68k.*/m68k/' \ + -e 's/ppc/powerpc/g' \ + -e 's/v850.*/v850/g' \ + -e 's/sh[234]/sh/' \ + -e 's/mips.*/mips/' \ + } + +#-------------------------------------------------------- +# Arch specific compiler optimization stuff should go here. +# Unless you want to override the defaults, do not set anything +# for OPTIMIZATION... + +# use '-Os' optimization if available, else use -O2 +OPTIMIZATION := ${shell if $(CC) -Os -S -o /dev/null -xc /dev/null >/dev/null 2>&1; \ + then echo "-Os"; else echo "-O2" ; fi} + +# Some nice architecture specific optimizations +ifeq ($(strip $(TARGET_ARCH)),arm) + OPTIMIZATION+=-fstrict-aliasing +endif +ifeq ($(strip $(TARGET_ARCH)),i386) + OPTIMIZATION+=-march=i386 + OPTIMIZATION+=${shell if $(CC) -mpreferred-stack-boundary=2 -S -o /dev/null -xc \ + /dev/null >/dev/null 2>&1; then echo "-mpreferred-stack-boundary=2"; fi} + OPTIMIZATION+=${shell if $(CC) -falign-functions=1 -falign-jumps=0 -falign-loops=0 \ + -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo \ + "-falign-functions=1 -falign-jumps=0 -falign-loops=0"; else \ + if $(CC) -malign-functions=0 -malign-jumps=0 -S -o /dev/null -xc \ + /dev/null >/dev/null 2>&1; then echo "-malign-functions=0 -malign-jumps=0"; fi; fi} +endif +OPTIMIZATIONS:=$(OPTIMIZATION) -fomit-frame-pointer + + +#-------------------------------------------------------- +# If you're going to do a lot of builds with a non-vanilla configuration, +# it makes sense to adjust parameters above, so you can type "make" +# by itself, instead of following it by the same half-dozen overrides +# every time. The stuff below, on the other hand, is probably less +# prone to casual user adjustment. +# +ifeq ($(strip $(DOLFS)),true) + # For large file support + CFLAGS+=-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 +endif +ifeq ($(strip $(DODMALLOC)),true) + # For testing mem leaks with dmalloc + CFLAGS+=-DDMALLOC + LIBRARIES = -ldmalloc + # Force debug=true, since this is useless when not debugging... + DODEBUG = true +else + ifeq ($(strip $(DOEFENCE)),true) + LIBRARIES = -lefence + # Force debug=true, since this is useless when not debugging... + DODEBUG = true + endif +endif +ifeq ($(strip $(DODEBUG)),true) + CFLAGS += $(WARNINGS) -g -D_GNU_SOURCE + LDFLAGS += -Wl,-warn-common + STRIPCMD = /bin/true -Since_we_are_debugging +else + CFLAGS += $(WARNINGS) $(OPTIMIZATIONS) -D_GNU_SOURCE + LDFLAGS += -s -Wl,-warn-common + STRIPCMD = $(STRIP) -s --remove-section=.note --remove-section=.comment +endif +ifeq ($(strip $(DOSTATIC)),true) + LDFLAGS += --static + # + #use '-ffunction-sections -fdata-sections' and '--gc-sections' (if they + # work) to try and strip out any unused junk. Doesn't do much for me, + # but you may want to give it a shot... + # + #ifeq ($(shell $(CC) -ffunction-sections -fdata-sections -S \ + # -o /dev/null -xc /dev/null 2>/dev/null && $(LD) \ + # --gc-sections -v >/dev/null && echo 1),1) + # CFLAGS += -ffunction-sections -fdata-sections + # LDFLAGS += --gc-sections + #endif +endif + +ifeq ($(strip $(PREFIX)),) + PREFIX = `pwd`/_install +endif + +# Additional complications due to support for pristine source dir. +# Include files in the build directory should take precedence over +# the copy in BB_SRC_DIR, both during the compilation phase and the +# shell script that finds the list of object files. +# Work in progress by . +# +ifneq ($(strip $(BB_SRC_DIR)),) + VPATH = $(BB_SRC_DIR) +endif +#ifneq ($(strip $(VPATH)),) +# CFLAGS += -I- -I. $(patsubst %,-I%,$(subst :, ,$(VPATH))) +#endif + +# We need to set APPLET_SOURCES to something like +# $(shell busybox.sh Config.h) +# but in a manner that works with VPATH and BB_SRC_DIR. +# Possible ways to approach this: +# +# 1. Explicitly search through .:$(VPATH) for busybox.sh and config.h, +# then $(shell $(BUSYBOX_SH) $(CONFIG_H) $(BB_SRC_DIR)) +# +# 2. Explicity search through .:$(VPATH) for slist.mk, +# then $(shell $(MAKE) -f $(SLIST_MK) VPATH=$(VPATH) BB_SRC_DIR=$(BB_SRC_DIR)) +# +# 3. Create slist.mk in this directory, with commands embedded in +# a $(shell ...) command, and $(MAKE) it immediately. +# +# 4. Use a real rule within this makefile to create a file that sets +# APPLET_SOURCE_LIST, then include that file. Has complications +# with the first trip through the makefile (before processing the +# include) trying to do too much, and a spurious warning the first +# time make is run. +# +# This is option 3: +# +#APPLET_SOURCES = $(shell \ +# echo -e 'all: busybox.sh Config.h\n\t@ $$(SHELL) $$^ $$(BB_SRC_DIR)' >slist.mk; \ +# make -f slist.mk VPATH=$(VPATH) BB_SRC_DIR=$(BB_SRC_DIR) \ +#) +# And option 4: +-include applet_source_list + +OBJECTS = $(APPLET_SOURCES:.c=.o) busybox.o usage.o applets.o +CFLAGS += $(CROSS_CFLAGS) +CFLAGS += -DBB_VER='"$(VERSION)"' +CFLAGS += -DBB_BT='"$(BUILDTIME)"' +ifdef BB_INIT_SCRIPT + CFLAGS += -DINIT_SCRIPT='"$(BB_INIT_SCRIPT)"' +endif + +ifneq ($(strip $(USE_SYSTEM_PWD_GRP)),true) + PWD_GRP = pwd_grp + PWD_GRP_DIR = $(BB_SRC_DIR:=/)$(PWD_GRP) + PWD_LIB = libpwd.a + PWD_CSRC=__getpwent.c pwent.c getpwnam.c getpwuid.c putpwent.c getpw.c \ + fgetpwent.c __getgrent.c grent.c getgrnam.c getgrgid.c fgetgrent.c \ + initgroups.c setgroups.c + PWD_OBJS=$(patsubst %.c,$(PWD_GRP)/%.o, $(PWD_CSRC)) +ifneq ($(strip $(BB_SRC_DIR)),) + PWD_CFLAGS = -I- -I. +endif + PWD_CFLAGS += -I$(PWD_GRP_DIR) +else + CFLAGS += -DUSE_SYSTEM_PWD_GRP +endif + +LIBBB = libbb +LIBBB_LIB = libbb.a +LIBBB_CSRC= ask_confirmation.c chomp.c concat_path_file.c copy_file.c \ +copy_file_chunk.c libc5.c device_open.c error_msg.c inode_hash.c \ +error_msg_and_die.c fgets_str.c find_mount_point.c find_pid_by_name.c \ +find_root_device.c full_read.c full_write.c get_console.c \ +get_last_path_component.c get_line_from_file.c gz_open.c human_readable.c \ +isdirectory.c kernel_version.c loop.c mode_string.c module_syscalls.c mtab.c \ +mtab_file.c my_getgrnam.c my_getgrgid.c my_getpwnam.c my_getpwnamegid.c \ +my_getpwuid.c parse_mode.c parse_number.c perror_msg.c perror_msg_and_die.c \ +print_file.c process_escape_sequence.c read_package_field.c recursive_action.c \ +safe_read.c safe_write.c safe_strncpy.c syscalls.c syslog_msg_with_name.c time_string.c \ +trim.c unzip.c vdprintf.c verror_msg.c vperror_msg.c wfopen.c xfuncs.c \ +xgetcwd.c xreadlink.c xregcomp.c interface.c remove_file.c last_char_is.c \ +copyfd.c vherror_msg.c herror_msg.c herror_msg_and_die.c xgethostbyname.c \ +dirname.c make_directory.c create_icmp_socket.c u_signal_names.c arith.c \ +simplify_path.c +LIBBB_OBJS=$(patsubst %.c,$(LIBBB)/%.o, $(LIBBB_CSRC)) +ifeq ($(strip $(BB_SRC_DIR)),) + LIBBB_CFLAGS += -I$(LIBBB) +else + LIBBB_CFLAGS = -I- -I. -I./$(LIBBB) -I$(BB_SRC_DIR)/$(LIBBB) -I$(BB_SRC_DIR) +endif + +LIBBB_MSRC=libbb/messages.c +LIBBB_MESSAGES= full_version name_too_long omitting_directory not_a_directory \ +memory_exhausted invalid_date invalid_option io_error dash_dash_help \ +write_error too_few_args name_longer_than_foo unknown can_not_create_raw_socket +LIBBB_MOBJ=$(patsubst %,$(LIBBB)/%.o, $(LIBBB_MESSAGES)) + +LIBBB_ARCSRC=libbb/unarchive.c +LIBBB_ARCOBJ= archive_offset seek_sub_file extract_archive unarchive \ +get_header_ar get_header_cpio get_header_tar deb_extract +LIBBB_AROBJS=$(patsubst %,$(LIBBB)/%.o, $(LIBBB_ARCOBJ)) + + +# Put user-supplied flags at the end, where they +# have a chance of winning. +CFLAGS += $(CFLAGS_EXTRA) + +.EXPORT_ALL_VARIABLES: + +all: applet_source_list busybox busybox.links doc + +applet_source_list: busybox.sh Config.h + (echo -n "APPLET_SOURCES := "; CC="$(CC)" BB_SRC_DIR="$(BB_SRC_DIR)" $(SHELL) $^) > $@ + +doc: olddoc + +# Old Docs... +olddoc: docs/busybox.pod docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html + +docs/busybox.pod : docs/busybox_header.pod usage.h docs/busybox_footer.pod + - ( cat docs/busybox_header.pod; \ + docs/autodocifier.pl usage.h; \ + cat docs/busybox_footer.pod ) > docs/busybox.pod + +docs/BusyBox.txt: docs/busybox.pod + @echo + @echo BusyBox Documentation + @echo + -mkdir -p docs + -pod2text $< > $@ + +docs/BusyBox.1: docs/busybox.pod + - mkdir -p docs + - pod2man --center=BusyBox --release="version $(VERSION)" \ + $< > $@ + +docs/BusyBox.html: docs/busybox.pod + -@ mkdir -p docs + - pod2html --noindex $< > docs/BusyBox.html + -@ rm -f pod2htm* + + +# New docs based on DOCBOOK SGML +newdoc: docs/busybox.txt docs/busybox.pdf docs/busybox/busyboxdocumentation.html + +docs/busybox.txt: docs/busybox.sgml + @echo + @echo BusyBox Documentation + @echo + - mkdir -p docs + (cd docs; sgmltools -b txt busybox.sgml) + +docs/busybox.dvi: docs/busybox.sgml + - mkdir -p docs + (cd docs; sgmltools -b dvi busybox.sgml) + +docs/busybox.ps: docs/busybox.sgml + - mkdir -p docs + (cd docs; sgmltools -b ps busybox.sgml) + +docs/busybox.pdf: docs/busybox.ps + - mkdir -p docs + (cd docs; ps2pdf busybox.ps) + +docs/busybox/busyboxdocumentation.html: docs/busybox.sgml + - mkdir -p docs + (cd docs; sgmltools -b html ../busybox.sgml) + + +busybox: $(PWD_LIB) $(LIBBB_LIB) $(OBJECTS) + $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBBB_LIB) $(PWD_LIB) $(LIBRARIES) + $(STRIPCMD) $(PROG) + +# Without VPATH, rule expands to "/bin/sh busybox.mkll Config.h applets.h" +# but with VPATH, some or all of those file names are resolved to the +# directories in which they live. +busybox.links: busybox.mkll Config.h applets.h + - $(SHELL) $^ >$@ + +nfsmount.o cmdedit.o: %.o: %.h +ash.o hush.o lash.o msh.o: cmdedit.h +$(OBJECTS): %.o: %.c Config.h busybox.h applets.h Makefile +ifeq ($(strip $(BB_SRC_DIR)),) + $(CC) $(CFLAGS) -I. $(patsubst %,-I%,$(subst :, ,$(BB_SRC_DIR))) -c $< -o $*.o +else + $(CC) $(CFLAGS) -I- -I. $(patsubst %,-I%,$(subst :, ,$(BB_SRC_DIR))) -c $< -o $*.o +endif + +$(PWD_OBJS): %.o: %.c Config.h busybox.h applets.h Makefile +ifneq ($(strip $(BB_SRC_DIR)),) + -mkdir -p $(PWD_GRP) +endif + $(CC) $(CFLAGS) $(PWD_CFLAGS) -c $< -o $*.o + +$(LIBBB_OBJS): %.o: %.c Config.h busybox.h applets.h Makefile libbb/libbb.h +ifneq ($(strip $(BB_SRC_DIR)),) + -mkdir -p $(LIBBB) +endif + $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -c $< -o $*.o + +$(LIBBB_MOBJ): $(LIBBB_MSRC) +ifneq ($(strip $(BB_SRC_DIR)),) + -mkdir -p $(LIBBB) +endif + $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -DL_$(patsubst libbb/%,%,$*) -c $< -o $*.o + +$(LIBBB_AROBJS): $(LIBBB_ARCSRC) +ifneq ($(strip $(BB_SRC_DIR)),) + -mkdir -p $(LIBBB) +endif + $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -DL_$(patsubst libbb/%,%,$*) -c $< -o $*.o + +libpwd.a: $(PWD_OBJS) + $(AR) $(ARFLAGS) $@ $^ + +libbb.a: $(LIBBB_MOBJ) $(LIBBB_AROBJS) $(LIBBB_OBJS) + $(AR) $(ARFLAGS) $@ $^ + +usage.o: usage.h + +libbb/loop.o: libbb/loop.h + +libbb/loop.h: mk_loop_h.sh + @ $(SHELL) $< > $@ + +test tests: + # old way of doing it + #cd tests && $(MAKE) all + # new way of doing it + cd tests && ./tester.sh + +clean: + - cd tests && $(MAKE) clean + - rm -f docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html docs/BusyBox.html + - rm -f docs/busybox.txt docs/busybox.dvi docs/busybox.ps \ + docs/busybox.pdf docs/busybox.html docs/busybox.pod + - rm -f multibuild.log Config.h.orig *.gdb *.elf + - rm -rf docs/busybox _install libpwd.a libbb.a pod2htm* + - rm -f busybox busybox.links libbb/loop.h *~ slist.mk core applet_source_list + - find . -name \*.o -exec rm -f {} \; + +distclean: clean + - cd tests && $(MAKE) distclean + - rm -f busybox applet_source_list + +install: install.sh busybox busybox.links + $(SHELL) $< $(PREFIX) + +uninstall: busybox busybox.links + for i in `cat busybox.links` ; do rm -f $$PREFIX$$i; done + +install-hardlinks: install.sh busybox busybox.links + $(SHELL) $< $(PREFIX) --hardlinks + +debug_pristine: + @ echo VPATH=\"$(VPATH)\" + @ echo OBJECTS=\"$(OBJECTS)\" + +dist release: distclean doc + cd ..; \ + rm -rf busybox-$(VERSION); \ + cp -a busybox busybox-$(VERSION); \ + \ + find busybox-$(VERSION)/ -type d \ + -name CVS \ + -print \ + -exec rm -rf {} \; ; \ + \ + find busybox-$(VERSION)/ -type f \ + -name .\#* \ + -print \ + -exec rm -f {} \; ; \ + \ + tar -cvzf busybox-$(VERSION).tar.gz busybox-$(VERSION)/; + +.PHONY: tags +tags: + ctags -R . diff --git a/README b/README new file mode 100644 index 000000000..7e978b632 --- /dev/null +++ b/README @@ -0,0 +1,148 @@ +Please see the LICENSE file for copyright information. + +BusyBox combines tiny versions of many common UNIX utilities into a single +small executable. It provides minimalist replacements for most of the utilities +you usually find in fileutils, shellutils, findutils, textutils, grep, gzip, +tar, etc. BusyBox provides a fairly complete POSIX environment for any small or +embedded system. The utilities in BusyBox generally have fewer options than +their full featured GNU cousins; however, the options that are included provide +the expected functionality and behave very much like their GNU counterparts. + +BusyBox has been written with size-optimization and limited resources in mind. +It is also extremely modular so you can easily include or exclude commands (or +features) at compile time. This makes it easy to customize your embedded +systems. To create a working system, just add /dev, /etc, and a kernel. + +BusyBox was originally written to support the Debian Rescue/Install disks, but +it also makes an excellent environment for any small or embedded system. + +As of version 0.20 there is now a version number. : ) Also as of version 0.20, +BusyBox is now modularized to easily allow you to build only the components you +need, thereby reducing binary size. To turn off unwanted BusyBox components, +simply edit the file "Config.h" and comment out the components you do not need +using C++ style (//) comments. + +After the build is complete, a busybox.links file is generated. This is +used by 'make install' to create symlinks to the busybox binary for all +compiled in functions. By default, 'make install' will place the symlink +forest into `pwd`/_install unless you have defined the PREFIX environment +variable (i.e., 'make PREFIX=/tmp/foo install') + +---------------- + +Supported architectures: + + Busybox in general will build on any architecture supported by gcc. It has + a few specialized features added for __sparc__ and __alpha__. insmod + functionality is currently limited to x86, ARM, SH3/4, powerpc, m68k, + and MIPS. + +Supported libcs: + + glibc-2.0.x, glibc-2.1.x, glibc-2.2.x, Linux-libc5, uClibc. People + are looking at newlib and diet-libc, but consider them unsupported, + untested, or worse. + +Supported kernels: + + Full functionality requires Linux 2.0.x, 2.2.x, or 2.4.x. A large fraction + of the code should run on just about anything. + +---------------- + +Shells: + +lash is the very smallest shell (adds just 10k) and it is quite usable as +a command prompt, but it is not suitable for any but the most trivial +scripting (such as an initrd that calls insmod a few times) since it does +not understand Bourne shell grammer. It does handle pipes, redirects, and +job control though. Adding in command editing makes it a very nice +lightweight command prompt. + +hush is also quite small (just 18k) and it has very complete Bourne shell +grammer. It handles if/then/else/fi just fine, but doesn't handle loops +like for/do/done or case/esac and such. It also currently has a problem +with job control. Using hush is not yet recommended. + +msh: The minix shell (adds just 30k) is quite complete and handles things +like for/do/done, case/esac and all the things you expect a Bourne shell to +do. It is not always pedantically correct about Bourne shell grammer (try +running the shell testscript "tests/sh.testcases" on it and compare vs bash) +but for most things it works quite well. It also uses only vfork, so it can +be used on uClinux systems. This was only recently added, so there is still +room to shrink it further... + +ash: This adds about 60k in the default configuration and is the most +complete and most pedantically correct shell included with busybox. This +shell was also recently added, and several people (mainly Vladimir and Erik) +have been working on it. There are a number of configurable things at the +top of ash.c as well, so check those out if you want to tweak things. + +---------------- + +Getting help: + +When you find you need help, you can check out the BusyBox mailing list +archives at http://busybox.net/lists/busybox/ or even join +the mailing list if you are interested. + +---------------- + +Bugs: + +If you find bugs, please submit a bug report. Full instructions on how to +report a bug are found at http://bugs.busybox.net/Reporting.html. + +For the impatient: To submit a bug, simply send an email describing the problem +to submit@bugs.busybox.net. Bug reports should look something like this: + + To: submit@bugs.busybox.net + From: diligent@testing.linux.org + Subject: /bin/true doesn't work + + Package: busybox + Version: 0.51 + + When I invoke '/bin/true' it doesn't work. I expected it to return + a "0" but it returned a "1" instead. Here is the transcript: + $ /bin/true ; echo $? + 1 + With GNU /bin/true, I get the following output: + $ /bin/true ; echo $? + 0 + I am using Debian 2.2r2, kernel version 2.2.18, and the latest + uClibc from CVS. Thanks for the wonderful program! + -Diligent + +Note the careful description and use of examples showing not only what BusyBox +does, but also a counter example showing what an equivalent GNU app does. Bug +reports lacking such detail may take a _long_ time to be fixed... Thanks for +understanding. + +---------------- + +FTP: + +Source for the latest released version can always be downloaded from + http://busybox.net/downloads/ + +---------------- + +CVS: + +BusyBox now has its own publicly browsable CVS tree at: + http://busybox.net/cgi-bin/cvsweb/busybox/ + +Anonymous CVS access is available. For instructions, check out: + http://busybox.net/cvs_anon.html + +For those that are actively contributing there is even CVS write access: + http://busybox.net/cvs_write.html + +---------------- + +Please feed suggestions, bug reports, insults, and bribes back to: + Erik Andersen + + + diff --git a/TODO b/TODO new file mode 100644 index 000000000..1e6388576 --- /dev/null +++ b/TODO @@ -0,0 +1,52 @@ +TODO list for busybox in no particular order. Just because something +is listed here doesn't mean that it is going to be added to busybox, +or that doing so is even a good idea. It just means that I _might_ get +around to it some time. If you have any good ideas, please let me know. + +* login/sulogin/passwd/getty/etc are part of tinylogin, and so are not + needed or wanted in busybox (or else I'd have to link to libcrypt). + +* We _were_ going to split networking apps into a new package called + netkit-tiny. Per discussions on the mailing list, this isn't going + to happen. False alarm. Sorry about the confusion. + + + -Erik + +----------- + +Possible apps to include some time: + +* hwclock +* group/commonize strings, remove dups (for i18n, l10n) + +----------- + +With sysvinit, reboot, poweroff and halt all used a named pipe, +/dev/initctl, to communicate with the init process. Busybox +currently uses signals to communicate with init. This makes +busybox incompatible with sysvinit. We should probably use +a named pipe as well so we can be compatible. + +----------------------- + +Run the following: + + rm -f busybox && make LDFLAGS+=-nostdlib 2>&1 | \ + sed -ne 's/.*undefined reference to `\(.*\)..*/\1/gp' | sort | uniq + +reveals the list of all external (i.e., libc) things that BusyBox depends on. +It would be a very nice thing to reduce this list to an absolute minimum, to +reduce the footprint of busybox, especially when staticly linking with +libraries such as uClibc. + +----------------------- + +Compile with debugging on, run 'nm --size-sort ./busybox' +and then start with the biggest things and make them smaller... + +----------------------- + +xargs could use a -l option + +------------------------------------------------------------------ diff --git a/adjtimex.c b/adjtimex.c new file mode 100644 index 000000000..e3c160d87 --- /dev/null +++ b/adjtimex.c @@ -0,0 +1,176 @@ +/* + * adjtimex.c - read, and possibly modify, the Linux kernel `timex' variables. + * + * Originally written: October 1997 + * Last hack: March 2001 + * Copyright 1997, 2000, 2001 Larry Doolittle + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (Version 2, + * June 1991) as published by the Free Software Foundation. At the + * time of writing, that license was published by the FSF with the URL + * http://www.gnu.org/copyleft/gpl.html, and is incorporated herein by + * reference. + * + * 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 adjtimex(1) is very similar in intent to adjtimex(8) by Steven + * Dick and Jim Van Zandt + * (see http://metalab.unc.edu/pub/Linux/system/admin/time/adjtimex*). + * That version predates this one, and is _much_ bigger and more + * featureful. My independently written version was very similar to + * Steven's from the start, because they both follow the kernel timex + * structure. I further tweaked this version to be equivalent to Steven's + * where possible, but I don't like getopt_long, so the actual usage + * syntax is incompatible. + * + * Amazingly enough, my Red Hat 5.2 sys/timex (and sub-includes) + * don't actually give a prototype for adjtimex(2), so building + * this code (with -Wall) gives a warning. Later versions of + * glibc fix this issue. + * + * This program is too simple for a Makefile, just build with: + * gcc -Wall -O adjtimex.c -o adjtimex + * + * busyboxed 20 March 2001, Larry Doolittle + * It will autosense if it is built in a busybox environment, based + * on the BB_VER preprocessor macro. + */ + +#include +#include +#include +#include + +#if __GNU_LIBRARY__ < 5 +#include +extern int adjtimex(struct timex *buf); +#else +#include +#endif + +#ifdef BB_VER +#include "busybox.h" +#endif + +static struct {int bit; char *name;} statlist[] = { + { STA_PLL, "PLL" }, + { STA_PPSFREQ, "PPSFREQ" }, + { STA_PPSTIME, "PPSTIME" }, + { STA_FLL, "FFL" }, + { STA_INS, "INS" }, + { STA_DEL, "DEL" }, + { STA_UNSYNC, "UNSYNC" }, + { STA_FREQHOLD, "FREQHOLD" }, + { STA_PPSSIGNAL, "PPSSIGNAL" }, + { STA_PPSJITTER, "PPSJITTER" }, + { STA_PPSWANDER, "PPSWANDER" }, + { STA_PPSERROR, "PPSERROR" }, + { STA_CLOCKERR, "CLOCKERR" }, + { 0, NULL } }; + +static char *ret_code_descript[] = { + "clock synchronized", + "insert leap second", + "delete leap second", + "leap second in progress", + "leap second has occurred", + "clock not synchronized" }; + +#ifdef BB_VER +#define main adjtimex_main +#else +void usage(char *prog) +{ + fprintf(stderr, + "Usage: %s [ -q ] [ -o offset ] [ -f frequency ] [ -p timeconstant ] [ -t tick ]\n", + prog); +} +#define show_usage() usage(argv[0]) +#endif + +int main(int argc, char ** argv) +{ + struct timex txc; + int quiet=0; + int c, i, ret, sep; + char *descript; + txc.modes=0; + for (;;) { + c = getopt( argc, argv, "qo:f:p:t:"); + if (c == EOF) break; + switch (c) { + case 'q': + quiet=1; + break; + case 'o': + txc.offset = atoi(optarg); + txc.modes |= ADJ_OFFSET_SINGLESHOT; + break; + case 'f': + txc.freq = atoi(optarg); + txc.modes |= ADJ_FREQUENCY; + break; + case 'p': + txc.constant = atoi(optarg); + txc.modes |= ADJ_TIMECONST; + break; + case 't': + txc.tick = atoi(optarg); + txc.modes |= ADJ_TICK; + break; + default: + show_usage(); + exit(1); + } + } + if (argc != optind) { /* no valid non-option parameters */ + show_usage(); + exit(1); + } + + ret = adjtimex(&txc); + + if (ret < 0) perror("adjtimex"); + + if (!quiet && ret>=0) { + printf( + " mode: %d\n" + "-o offset: %ld\n" + "-f frequency: %ld\n" + " maxerror: %ld\n" + " esterror: %ld\n" + " status: %d ( ", + txc.modes, txc.offset, txc.freq, txc.maxerror, + txc.esterror, txc.status); + + /* representative output of next code fragment: + "PLL | PPSTIME" */ + sep=0; + for (i=0; statlist[i].name; i++) { + if (txc.status & statlist[i].bit) { + if (sep) fputs(" | ",stdout); + fputs(statlist[i].name,stdout); + sep=1; + } + } + + descript = "error"; + if (ret >= 0 && ret <= 5) descript = ret_code_descript[ret]; + printf(" )\n" + "-p timeconstant: %ld\n" + " precision: %ld\n" + " tolerance: %ld\n" + "-t tick: %ld\n" + " time.tv_sec: %ld\n" + " time.tv_usec: %ld\n" + " return value: %d (%s)\n", + txc.constant, + txc.precision, txc.tolerance, txc.tick, + (long)txc.time.tv_sec, (long)txc.time.tv_usec, ret, descript); + } + return (ret<0); +} diff --git a/applets.c b/applets.c new file mode 100644 index 000000000..f3e56a9f3 --- /dev/null +++ b/applets.c @@ -0,0 +1,116 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) tons of folks. Tracking down who wrote what + * isn't something I'm going to worry about... If you wrote something + * here, please feel free to acknowledge your work. + * + * 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 + * + * Based in part on code from sash, Copyright (c) 1999 by David I. Bell + * Permission has been granted to redistribute this code under the GPL. + * + */ + +#include +#include +#include +#include "busybox.h" + +#undef APPLET +#undef APPLET_NOUSAGE +#undef PROTOTYPES +#include "applets.h" + +struct BB_applet *applet_using; + +/* The -1 arises because of the {0,NULL,0,-1} entry above. */ +const size_t NUM_APPLETS = (sizeof (applets) / sizeof (struct BB_applet) - 1); + +extern void show_usage(void) +{ + const char *format_string; + const char *usage_string = usage_messages; + int i; + + for (i = applet_using - applets; i > 0; ) { + if (!*usage_string++) { + --i; + } + } + format_string = "%s\n\nUsage: %s %s\n\n"; + if(*usage_string == 0) + format_string = "%s\n\nNo help available.\n\n"; + fprintf(stderr, format_string, + full_version, applet_using->name, usage_string); + exit(EXIT_FAILURE); +} + +static int applet_name_compare(const void *x, const void *y) +{ + const char *name = x; + const struct BB_applet *applet = y; + + return strcmp(name, applet->name); +} + +extern const size_t NUM_APPLETS; + +struct BB_applet *find_applet_by_name(const char *name) +{ + return bsearch(name, applets, NUM_APPLETS, sizeof(struct BB_applet), + applet_name_compare); +} + +void run_applet_by_name(const char *name, int argc, char **argv) +{ + static int recurse_level = 0; + extern int been_there_done_that; /* From busybox.c */ + + recurse_level++; + /* Do a binary search to find the applet entry given the name. */ + if ((applet_using = find_applet_by_name(name)) != NULL) { + applet_name = applet_using->name; + if (argv[1] && strcmp(argv[1], "--help") == 0) { + if (strcmp(applet_using->name, "busybox")==0) { + if(argv[2]) + applet_using = find_applet_by_name(argv[2]); + else + applet_using = NULL; + } + if(applet_using) + show_usage(); + been_there_done_that=1; + busybox_main(0, NULL); + } + exit((*(applet_using->main)) (argc, argv)); + } + /* Just in case they have renamed busybox - Check argv[1] */ + if (recurse_level == 1) { + run_applet_by_name("busybox", argc, argv); + } + recurse_level--; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/applets.h b/applets.h new file mode 100644 index 000000000..403c06ee7 --- /dev/null +++ b/applets.h @@ -0,0 +1,487 @@ +/* + * applets.h - a listing of all busybox applets. + * + * If you write a new applet, you need to add an entry to this list to make + * busybox aware of it. + * + * It is CRUCIAL that this listing be kept in ascii order, otherwise the binary + * search lookup contributed by Gaute B Strokkenes stops working. If you value + * your kneecaps, you'll be sure to *make sure* that any changes made to this + * file result in the listing remaining in ascii order. You have been warned. + */ + +#undef APPLET +#undef APPLET_ODDNAME +#undef APPLET_NOUSAGE + + +#if defined(PROTOTYPES) + #define APPLET(a,b,c) extern int b(int argc, char **argv); + #define APPLET_NOUSAGE(a,b,c) extern int b(int argc, char **argv); + #define APPLET_ODDNAME(a,b,c,d) extern int b(int argc, char **argv); + extern const char usage_messages[]; +#elif defined(MAKE_USAGE) + #ifdef BB_FEATURE_VERBOSE_USAGE + #define APPLET(a,b,c) a##_trivial_usage "\n\n" a##_full_usage "\0" + #define APPLET_NOUSAGE(a,b,c) "\0" + #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\n\n" d##_full_usage "\0" + #else + #define APPLET(a,b,c) a##_trivial_usage "\0" + #define APPLET_NOUSAGE(a,b,c) "\0" + #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\0" + #endif +#elif defined(MAKE_LINKS) +# define APPLET(a,b,c) LINK c a +# define APPLET_NOUSAGE(a,b,c) LINK c a +# define APPLET_ODDNAME(a,b,c,d) LINK c a +#else + const struct BB_applet applets[] = { + #define APPLET(a,b,c) {#a,b,c}, + #define APPLET_NOUSAGE(a,b,c) {a,b,c}, + #define APPLET_ODDNAME(a,b,c,d) {a,b,c}, +#endif + + + +#ifdef BB_TEST + APPLET_NOUSAGE("[", test_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_ADJTIMEX + APPLET(adjtimex, adjtimex_main, _BB_DIR_SBIN) +#endif +#ifdef BB_AR + APPLET(ar, ar_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_ASH + APPLET_NOUSAGE("ash", ash_main, _BB_DIR_BIN) +#endif +#ifdef BB_BASENAME + APPLET(basename, basename_main, _BB_DIR_USR_BIN) +#endif + APPLET_NOUSAGE("busybox", busybox_main, _BB_DIR_BIN) +#ifdef BB_CAT + APPLET(cat, cat_main, _BB_DIR_BIN) +#endif +#ifdef BB_CHGRP + APPLET(chgrp, chgrp_main, _BB_DIR_BIN) +#endif +#ifdef BB_CHMOD + APPLET(chmod, chmod_main, _BB_DIR_BIN) +#endif +#ifdef BB_CHOWN + APPLET(chown, chown_main, _BB_DIR_BIN) +#endif +#ifdef BB_CHROOT + APPLET(chroot, chroot_main, _BB_DIR_USR_SBIN) +#endif +#ifdef BB_CHVT + APPLET(chvt, chvt_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_CLEAR + APPLET(clear, clear_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_CMP + APPLET(cmp, cmp_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_CP + APPLET(cp, cp_main, _BB_DIR_BIN) +#endif +#ifdef BB_CPIO + APPLET(cpio, cpio_main, _BB_DIR_BIN) +#endif +#ifdef BB_CUT + APPLET(cut, cut_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_DATE + APPLET(date, date_main, _BB_DIR_BIN) +#endif +#ifdef BB_DC + APPLET(dc, dc_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_DD + APPLET(dd, dd_main, _BB_DIR_BIN) +#endif +#ifdef BB_DEALLOCVT + APPLET(deallocvt, deallocvt_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_DF + APPLET(df, df_main, _BB_DIR_BIN) +#endif +#ifdef BB_DIRNAME + APPLET(dirname, dirname_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_DMESG + APPLET(dmesg, dmesg_main, _BB_DIR_BIN) +#endif +#ifdef BB_DOS2UNIX + APPLET(dos2unix, dos2unix_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_DPKG + APPLET(dpkg, dpkg_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_DPKG_DEB + APPLET_ODDNAME("dpkg-deb", dpkg_deb_main, _BB_DIR_USR_BIN, dpkg_deb) +#endif +#ifdef BB_DU + APPLET(du, du_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_DUMPKMAP + APPLET(dumpkmap, dumpkmap_main, _BB_DIR_BIN) +#endif +#ifdef BB_DUTMP + APPLET(dutmp, dutmp_main, _BB_DIR_USR_SBIN) +#endif +#ifdef BB_ECHO + APPLET(echo, echo_main, _BB_DIR_BIN) +#endif +#if defined(BB_FEATURE_GREP_EGREP_ALIAS) && defined(BB_GREP) + APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN) +#endif +#ifdef BB_ENV + APPLET(env, env_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_EXPR + APPLET(expr, expr_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_TRUE_FALSE + APPLET(false, false_main, _BB_DIR_BIN) +#endif +#ifdef BB_FBSET + APPLET(fbset, fbset_main, _BB_DIR_USR_SBIN) +#endif +#ifdef BB_FDFLUSH + APPLET(fdflush, fdflush_main, _BB_DIR_BIN) +#endif +#ifdef BB_FIND + APPLET(find, find_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_FREE + APPLET(free, free_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_FREERAMDISK + APPLET(freeramdisk, freeramdisk_main, _BB_DIR_SBIN) +#endif +#ifdef BB_FSCK_MINIX + APPLET_ODDNAME("fsck.minix", fsck_minix_main, _BB_DIR_SBIN, fsck_minix) +#endif +#ifdef BB_GETOPT + APPLET(getopt, getopt_main, _BB_DIR_BIN) +#endif +#ifdef BB_GREP + APPLET(grep, grep_main, _BB_DIR_BIN) +#endif +#ifdef BB_GUNZIP + APPLET(gunzip, gunzip_main, _BB_DIR_BIN) +#endif +#ifdef BB_GZIP + APPLET(gzip, gzip_main, _BB_DIR_BIN) +#endif +#ifdef BB_HALT + APPLET(halt, halt_main, _BB_DIR_SBIN) +#endif +#ifdef BB_HEAD + APPLET(head, head_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_HOSTID + APPLET(hostid, hostid_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_HOSTNAME + APPLET(hostname, hostname_main, _BB_DIR_BIN) +#endif +#ifdef BB_HUSH + APPLET_NOUSAGE("hush", hush_main, _BB_DIR_BIN) +#endif +#ifdef BB_ID + APPLET(id, id_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_IFCONFIG + APPLET(ifconfig, ifconfig_main, _BB_DIR_SBIN) +#endif +#ifdef BB_INIT + APPLET(init, init_main, _BB_DIR_SBIN) +#endif +#ifdef BB_INSMOD + APPLET(insmod, insmod_main, _BB_DIR_SBIN) +#endif +#ifdef BB_KILL + APPLET(kill, kill_main, _BB_DIR_BIN) +#endif +#ifdef BB_KILLALL + APPLET(killall, kill_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_KLOGD + APPLET(klogd, klogd_main, _BB_DIR_SBIN) +#endif +#ifdef BB_LASH + APPLET(lash, lash_main, _BB_DIR_BIN) +#endif +#ifdef BB_LENGTH + APPLET(length, length_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_FEATURE_LINUXRC + APPLET_NOUSAGE("linuxrc", init_main, _BB_DIR_ROOT) +#endif +#ifdef BB_LN + APPLET(ln, ln_main, _BB_DIR_BIN) +#endif +#ifdef BB_LOADACM + APPLET(loadacm, loadacm_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_LOADFONT + APPLET(loadfont, loadfont_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_LOADKMAP + APPLET(loadkmap, loadkmap_main, _BB_DIR_SBIN) +#endif +#ifdef BB_LOGGER + APPLET(logger, logger_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_LOGNAME + APPLET(logname, logname_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_LOGREAD + APPLET(logread, logread_main, _BB_DIR_SBIN) +#endif +#ifdef BB_LOSETUP + APPLET(losetup, losetup_main, _BB_DIR_SBIN) +#endif +#ifdef BB_LS + APPLET(ls, ls_main, _BB_DIR_BIN) +#endif +#ifdef BB_LSMOD + APPLET(lsmod, lsmod_main, _BB_DIR_SBIN) +#endif +#ifdef BB_MAKEDEVS + APPLET(makedevs, makedevs_main, _BB_DIR_SBIN) +#endif +#ifdef BB_MD5SUM + APPLET(md5sum, md5sum_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_MKDIR + APPLET(mkdir, mkdir_main, _BB_DIR_BIN) +#endif +#ifdef BB_MKFIFO + APPLET(mkfifo, mkfifo_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_MKFS_MINIX + APPLET_ODDNAME("mkfs.minix", mkfs_minix_main, _BB_DIR_SBIN, mkfs_minix) +#endif +#ifdef BB_MKNOD + APPLET(mknod, mknod_main, _BB_DIR_BIN) +#endif +#ifdef BB_MKSWAP + APPLET(mkswap, mkswap_main, _BB_DIR_SBIN) +#endif +#ifdef BB_MKTEMP + APPLET(mktemp, mktemp_main, _BB_DIR_BIN) +#endif +#ifdef BB_MODPROBE + APPLET(modprobe, modprobe_main, _BB_DIR_SBIN) +#endif +#ifdef BB_MORE + APPLET(more, more_main, _BB_DIR_BIN) +#endif +#ifdef BB_MOUNT + APPLET(mount, mount_main, _BB_DIR_BIN) +#endif +#ifdef BB_MSH + APPLET_NOUSAGE("msh", msh_main, _BB_DIR_BIN) +#endif +#ifdef BB_MT + APPLET(mt, mt_main, _BB_DIR_BIN) +#endif +#ifdef BB_MV + APPLET(mv, mv_main, _BB_DIR_BIN) +#endif +#ifdef BB_NC + APPLET(nc, nc_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_NSLOOKUP + APPLET(nslookup, nslookup_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_PIDOF + APPLET(pidof, pidof_main, _BB_DIR_BIN) +#endif +#ifdef BB_PING + APPLET(ping, ping_main, _BB_DIR_BIN) +#endif +#ifdef BB_PIVOT_ROOT + APPLET(pivot_root, pivot_root_main, _BB_DIR_SBIN) +#endif +#ifdef BB_POWEROFF + APPLET(poweroff, poweroff_main, _BB_DIR_SBIN) +#endif +#ifdef BB_PRINTF + APPLET(printf, printf_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_PS + APPLET(ps, ps_main, _BB_DIR_BIN) +#endif +#ifdef BB_PWD + APPLET(pwd, pwd_main, _BB_DIR_BIN) +#endif +#ifdef BB_RDATE + APPLET(rdate, rdate_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_READLINK + APPLET(readlink, readlink_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_REBOOT + APPLET(reboot, reboot_main, _BB_DIR_SBIN) +#endif +#ifdef BB_RENICE + APPLET(renice, renice_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_RESET + APPLET(reset, reset_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_RM + APPLET(rm, rm_main, _BB_DIR_BIN) +#endif +#ifdef BB_RMDIR + APPLET(rmdir, rmdir_main, _BB_DIR_BIN) +#endif +#ifdef BB_RMMOD + APPLET(rmmod, rmmod_main, _BB_DIR_SBIN) +#endif +#ifdef BB_ROUTE + APPLET(route, route_main, _BB_DIR_SBIN) +#endif +#ifdef BB_RPM2CPIO + APPLET(rpm2cpio, rpm2cpio_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_SED + APPLET(sed, sed_main, _BB_DIR_BIN) +#endif +#ifdef BB_SETKEYCODES + APPLET(setkeycodes, setkeycodes_main, _BB_DIR_USR_BIN) +#endif +#if defined(BB_FEATURE_SH_IS_ASH) && defined(BB_ASH) + APPLET_NOUSAGE("sh", ash_main, _BB_DIR_BIN) +#elif defined(BB_FEATURE_SH_IS_HUSH) && defined(BB_HUSH) + APPLET_NOUSAGE("sh", hush_main, _BB_DIR_BIN) +#elif defined(BB_FEATURE_SH_IS_LASH) && defined(BB_LASH) + APPLET_NOUSAGE("sh", lash_main, _BB_DIR_BIN) +#elif defined(BB_FEATURE_SH_IS_MSH) && defined(BB_MSH) + APPLET_NOUSAGE("sh", msh_main, _BB_DIR_BIN) +#endif +#ifdef BB_SLEEP + APPLET(sleep, sleep_main, _BB_DIR_BIN) +#endif +#ifdef BB_SORT + APPLET(sort, sort_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_STTY + APPLET(stty, stty_main, _BB_DIR_BIN) +#endif +#ifdef BB_SWAPONOFF + APPLET(swapoff, swap_on_off_main, _BB_DIR_SBIN) +#endif +#ifdef BB_SWAPONOFF + APPLET(swapon, swap_on_off_main, _BB_DIR_SBIN) +#endif +#ifdef BB_SYNC + APPLET(sync, sync_main, _BB_DIR_BIN) +#endif +#ifdef BB_SYSLOGD + APPLET(syslogd, syslogd_main, _BB_DIR_SBIN) +#endif +#ifdef BB_TAIL + APPLET(tail, tail_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_TAR + APPLET(tar, tar_main, _BB_DIR_BIN) +#endif +#ifdef BB_TEE + APPLET(tee, tee_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_TELNET + APPLET(telnet, telnet_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_TEST + APPLET(test, test_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_TFTP + APPLET(tftp, tftp_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_TIME + APPLET(time, time_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_TOP + APPLET(top, top_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_TOUCH + APPLET(touch, touch_main, _BB_DIR_BIN) +#endif +#ifdef BB_TR + APPLET(tr, tr_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_TRACEROUTE + APPLET(traceroute, traceroute_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_TRUE_FALSE + APPLET(true, true_main, _BB_DIR_BIN) +#endif +#ifdef BB_TTY + APPLET(tty, tty_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_UMOUNT + APPLET(umount, umount_main, _BB_DIR_BIN) +#endif +#ifdef BB_UNAME + APPLET(uname, uname_main, _BB_DIR_BIN) +#endif +#ifdef BB_UNIQ + APPLET(uniq, uniq_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_UNIX2DOS + APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_UPDATE + APPLET(update, update_main, _BB_DIR_SBIN) +#endif +#ifdef BB_UPTIME + APPLET(uptime, uptime_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_USLEEP + APPLET(usleep, usleep_main, _BB_DIR_BIN) +#endif +#ifdef BB_UUDECODE + APPLET(uudecode, uudecode_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_UUENCODE + APPLET(uuencode, uuencode_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_VI + APPLET(vi, vi_main, _BB_DIR_BIN) +#endif +#ifdef BB_WATCHDOG + APPLET(watchdog, watchdog_main, _BB_DIR_SBIN) +#endif +#ifdef BB_WC + APPLET(wc, wc_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_WGET + APPLET(wget, wget_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_WHICH + APPLET(which, which_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_WHOAMI + APPLET(whoami, whoami_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_XARGS + APPLET(xargs, xargs_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_YES + APPLET(yes, yes_main, _BB_DIR_USR_BIN) +#endif +#ifdef BB_GUNZIP + APPLET(zcat, gunzip_main, _BB_DIR_BIN) +#endif + +#if !defined(PROTOTYPES) && !defined(MAKE_USAGE) + { 0,NULL,0 } +}; + +#endif diff --git a/ar.c b/ar.c new file mode 100644 index 000000000..7f3396c8c --- /dev/null +++ b/ar.c @@ -0,0 +1,89 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini ar implementation for busybox + * + * Copyright (C) 2000 by Glenn McGrath + * Written by Glenn McGrath 1 June 2000 + * + * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar. + * + * 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 "busybox.h" + +extern int ar_main(int argc, char **argv) +{ + FILE *src_stream = NULL; + char **extract_names = NULL; + char ar_magic[8]; + int extract_function = extract_unconditional; + int opt; + int num_of_entries = 0; + extern off_t archive_offset; + + while ((opt = getopt(argc, argv, "ovtpx")) != -1) { + switch (opt) { + case 'o': + extract_function |= extract_preserve_date; + break; + case 'v': + extract_function |= extract_verbose_list; + break; + case 't': + extract_function |= extract_list; + break; + case 'p': + extract_function |= extract_to_stdout; + break; + case 'x': + extract_function |= extract_all_to_fs; + break; + default: + show_usage(); + } + } + + /* check the src filename was specified */ + if (optind == argc) { + show_usage(); + } + + src_stream = xfopen(argv[optind++], "r"); + + /* check ar magic */ + fread(ar_magic, 1, 8, src_stream); + archive_offset = 8; + if (strncmp(ar_magic,"!",7) != 0) { + error_msg_and_die("invalid magic"); + } + + /* Create a list of files to extract */ + while (optind < argc) { + extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2)); + extract_names[num_of_entries] = xstrdup(argv[optind]); + num_of_entries++; + extract_names[num_of_entries] = NULL; + optind++; + } + + unarchive(src_stream, stdout, &get_header_ar, extract_function, "./", extract_names); + return EXIT_SUCCESS; +} diff --git a/ash.c b/ash.c new file mode 100644 index 000000000..6db0c887f --- /dev/null +++ b/ash.c @@ -0,0 +1,13528 @@ +/* vi: set sw=4 ts=4: */ +/* + * ash shell port for busybox + * + * Copyright (c) 1989, 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 1997-2003 Herbert Xu + * was re-ported from NetBSD and debianized. + * + * + * This code is derived from software contributed to Berkeley by + * Kenneth Almquist. + * + * 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 + * + * Original BSD copyright notice is retained at the end of this file. + */ + +/* + * rewrite arith.y to micro stack based cryptic algorithm by + * Copyright (c) 2001 Aaron Lehmann + * + * Modified by Vladimir Oleynik (c) 2001-2003 to be + * used in busybox and size optimizations, + * support locale, rewrited arith (see notes to this) + * + */ + + +/* + * The follow should be set to reflect the type of system you have: + * JOBS -> 1 if you have Berkeley job control, 0 otherwise. + * define SYSV if you are running under System V. + * define DEBUG=1 to compile in debugging ('set -o debug' to turn on) + * define DEBUG=2 to compile in and turn on debugging. + * + * When debugging is on, debugging info will be written to ./trace and + * a quit signal will generate a core dump. + */ + +/* This enables alias support in ash. If you want to support things + * like "alias ls='ls -l'" with ash, enable this. This is only useful + * when ash is used as an intractive shell. This adds about 1.5k */ +#define BB_ASH_ALIAS + +/* If you need ash to act as a full Posix shell, with full math + * support, enable this. This adds a bit over 2k an x86 system. */ +#define BB_ASH_MATH_SUPPORT + +/* Getopts is used by shell procedures to parse positional parameters. + * You probably want to leave this disabled, and use the busybox getopt + * applet if you want to do this sort of thing. There are some scripts + * out there that use it, so if you need it, enable it. Most people will + * leave this disabled. This adds 1k on an x86 system. */ +#undef BB_ASH_GETOPTS + +/* This allows you to override shell builtins and use whatever is on + * the filesystem. This is most useful when ash is acting as a + * standalone shell. Adds about 272 bytes. */ +#undef BB_ASH_CMDCMD + +/* Check for mail */ +#undef BB_ASH_MAIL + +/* Optimize size vs speed as size */ +#define BB_ASH_OPTIMIZE_FOR_SIZE + +/* Enable this to compile in extra debugging noise. When debugging is + * on, debugging info will be written to $HOME/trace and a quit signal + * will generate a core dump. */ +#undef DEBUG + + + +#define IFS_BROKEN + +#define PROFILE 0 + +#ifdef DEBUG +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#include "busybox.h" +#include "pwd_grp/pwd.h" + +#ifdef BB_ASH_JOB_CONTROL +#define JOBS 1 +#else +#undef JOBS +#endif + +#if JOBS +#include +#endif + +#include "cmdedit.h" + +#ifdef __GLIBC__ +/* glibc sucks */ +static int *dash_errno; +#undef errno +#define errno (*dash_errno) +#endif + +#if defined(__uClinux__) +#error "Do not even bother, ash will not run on uClinux" +#endif + +#ifdef DEBUG +#define _DIAGASSERT(assert_expr) assert(assert_expr) +#else +#define _DIAGASSERT(assert_expr) +#endif + + +#ifdef BB_ASH_ALIAS +/* $NetBSD: alias.h,v 1.5 2002/11/24 22:35:38 christos Exp $ */ + +#define ALIASINUSE 1 +#define ALIASDEAD 2 + +struct alias { + struct alias *next; + char *name; + char *val; + int flag; +}; + +static struct alias *lookupalias(const char *, int); +static int aliascmd(int, char **); +static int unaliascmd(int, char **); +static void rmaliases(void); +static int unalias(const char *); +static void printalias(const struct alias *); +#endif + +/* $NetBSD: cd.h,v 1.3 2002/11/24 22:35:39 christos Exp $ */ + + +static void setpwd(const char *, int); + +/* $NetBSD: error.h,v 1.15 2002/11/24 22:35:39 christos Exp $ */ + + +/* + * Types of operations (passed to the errmsg routine). + */ + + +static const char not_found_msg[] = "%s: not found"; + + +#define E_OPEN "No such file" /* opening a file */ +#define E_CREAT "Directory nonexistent" /* creating a file */ +#define E_EXEC not_found_msg+4 /* executing a program */ + +/* + * We enclose jmp_buf in a structure so that we can declare pointers to + * jump locations. The global variable handler contains the location to + * jump to when an exception occurs, and the global variable exception + * contains a code identifying the exeception. To implement nested + * exception handlers, the user should save the value of handler on entry + * to an inner scope, set handler to point to a jmploc structure for the + * inner scope, and restore handler on exit from the scope. + */ + +struct jmploc { + jmp_buf loc; +}; + +static struct jmploc *handler; +static int exception; +static volatile int suppressint; +static volatile sig_atomic_t intpending; + +static int exerrno; /* Last exec error, error for EXEXEC */ + +/* exceptions */ +#define EXINT 0 /* SIGINT received */ +#define EXERROR 1 /* a generic error */ +#define EXSHELLPROC 2 /* execute a shell procedure */ +#define EXEXEC 3 /* command execution failed */ +#define EXEXIT 4 /* exit the shell */ +#define EXSIG 5 /* trapped signal in wait(1) */ + + +/* do we generate EXSIG events */ +static int exsig; +/* last pending signal */ +static volatile sig_atomic_t pendingsigs; + +/* + * These macros allow the user to suspend the handling of interrupt signals + * over a period of time. This is similar to SIGHOLD to or sigblock, but + * much more efficient and portable. (But hacking the kernel is so much + * more fun than worrying about efficiency and portability. :-)) + */ + +#define barrier() ({ __asm__ __volatile__ ("": : :"memory"); }) +#define INTOFF \ + ({ \ + suppressint++; \ + barrier(); \ + 0; \ + }) +#define SAVEINT(v) ((v) = suppressint) +#define RESTOREINT(v) \ + ({ \ + barrier(); \ + if ((suppressint = (v)) == 0 && intpending) onint(); \ + 0; \ + }) +#define EXSIGON() \ + ({ \ + exsig++; \ + barrier(); \ + if (pendingsigs) \ + exraise(EXSIG); \ + 0; \ + }) +/* EXSIG is turned off by evalbltin(). */ + + +static void exraise(int) __attribute__((__noreturn__)); +static void onint(void) __attribute__((__noreturn__)); + +static void error(const char *, ...) __attribute__((__noreturn__)); +static void exerror(int, const char *, ...) __attribute__((__noreturn__)); + +static void sh_warnx(const char *, ...); + +#ifdef BB_ASH_OPTIMIZE_FOR_SIZE +static void +inton(void) { + if (--suppressint == 0 && intpending) { + onint(); + } +} +#define INTON inton() +static void forceinton(void) +{ + suppressint = 0; + if (intpending) + onint(); +} +#define FORCEINTON forceinton() +#else +#define INTON \ + ({ \ + barrier(); \ + if (--suppressint == 0 && intpending) onint(); \ + 0; \ + }) +#define FORCEINTON \ + ({ \ + barrier(); \ + suppressint = 0; \ + if (intpending) onint(); \ + 0; \ + }) +#endif /* BB_ASH_OPTIMIZE_FOR_SIZE */ + +/* + * BSD setjmp saves the signal mask, which violates ANSI C and takes time, + * so we use _setjmp instead. + */ + +#if defined(BSD) && !defined(__SVR4) && !defined(__GLIBC__) +#define setjmp(jmploc) _setjmp(jmploc) +#define longjmp(jmploc, val) _longjmp(jmploc, val) +#endif + +/* $NetBSD: expand.h,v 1.13 2002/11/24 22:35:40 christos Exp $ */ + +struct strlist { + struct strlist *next; + char *text; +}; + + +struct arglist { + struct strlist *list; + struct strlist **lastp; +}; + +/* + * expandarg() flags + */ +#define EXP_FULL 0x1 /* perform word splitting & file globbing */ +#define EXP_TILDE 0x2 /* do normal tilde expansion */ +#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ +#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ +#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ +#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */ +#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ +#define EXP_WORD 0x80 /* expand word in parameter expansion */ +#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */ + + +union node; +static void expandarg(union node *, struct arglist *, int); +#define rmescapes(p) _rmescapes((p), 0) +static char *_rmescapes(char *, int); +static int casematch(union node *, char *); + +#ifdef BB_ASH_MATH_SUPPORT +static void expari(int); +#endif + +/* $NetBSD: eval.h,v 1.13 2002/11/24 22:35:39 christos Exp $ */ + +static char *commandname; /* currently executing command */ +static struct strlist *cmdenviron; /* environment for builtin command */ +static int exitstatus; /* exit status of last command */ +static int back_exitstatus; /* exit status of backquoted command */ + + +struct backcmd { /* result of evalbackcmd */ + int fd; /* file descriptor to read from */ + char *buf; /* buffer */ + int nleft; /* number of chars in buffer */ + struct job *jp; /* job structure for command */ +}; + +/* + * This file was generated by the mknodes program. + */ + +#define NCMD 0 +#define NPIPE 1 +#define NREDIR 2 +#define NBACKGND 3 +#define NSUBSHELL 4 +#define NAND 5 +#define NOR 6 +#define NSEMI 7 +#define NIF 8 +#define NWHILE 9 +#define NUNTIL 10 +#define NFOR 11 +#define NCASE 12 +#define NCLIST 13 +#define NDEFUN 14 +#define NARG 15 +#define NTO 16 +#define NCLOBBER 17 +#define NFROM 18 +#define NFROMTO 19 +#define NAPPEND 20 +#define NTOFD 21 +#define NFROMFD 22 +#define NHERE 23 +#define NXHERE 24 +#define NNOT 25 + + + +struct ncmd { + int type; + union node *assign; + union node *args; + union node *redirect; +}; + + +struct npipe { + int type; + int backgnd; + struct nodelist *cmdlist; +}; + + +struct nredir { + int type; + union node *n; + union node *redirect; +}; + + +struct nbinary { + int type; + union node *ch1; + union node *ch2; +}; + + +struct nif { + int type; + union node *test; + union node *ifpart; + union node *elsepart; +}; + + +struct nfor { + int type; + union node *args; + union node *body; + char *var; +}; + + +struct ncase { + int type; + union node *expr; + union node *cases; +}; + + +struct nclist { + int type; + union node *next; + union node *pattern; + union node *body; +}; + + +struct narg { + int type; + union node *next; + char *text; + struct nodelist *backquote; +}; + + +struct nfile { + int type; + union node *next; + int fd; + union node *fname; + char *expfname; +}; + + +struct ndup { + int type; + union node *next; + int fd; + int dupfd; + union node *vname; +}; + + +struct nhere { + int type; + union node *next; + int fd; + union node *doc; +}; + + +struct nnot { + int type; + union node *com; +}; + + +union node { + int type; + struct ncmd ncmd; + struct npipe npipe; + struct nredir nredir; + struct nbinary nbinary; + struct nif nif; + struct nfor nfor; + struct ncase ncase; + struct nclist nclist; + struct narg narg; + struct nfile nfile; + struct ndup ndup; + struct nhere nhere; + struct nnot nnot; +}; + + +struct nodelist { + struct nodelist *next; + union node *n; +}; + + +struct funcnode { + int count; + union node n; +}; + + +static void freefunc(struct funcnode *); +/* $NetBSD: parser.h,v 1.15 2002/11/24 22:35:42 christos Exp $ */ + +/* control characters in argument strings */ +#define CTL_FIRST '\201' /* first 'special' character */ +#define CTLESC '\201' /* escape next character */ +#define CTLVAR '\202' /* variable defn */ +#define CTLENDVAR '\203' +#define CTLBACKQ '\204' +#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ +/* CTLBACKQ | CTLQUOTE == '\205' */ +#define CTLARI '\206' /* arithmetic expression */ +#define CTLENDARI '\207' +#define CTLQUOTEMARK '\210' +#define CTL_LAST '\210' /* last 'special' character */ + +/* variable substitution byte (follows CTLVAR) */ +#define VSTYPE 0x0f /* type of variable substitution */ +#define VSNUL 0x10 /* colon--treat the empty string as unset */ +#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ + +/* values of VSTYPE field */ +#define VSNORMAL 0x1 /* normal variable: $var or ${var} */ +#define VSMINUS 0x2 /* ${var-text} */ +#define VSPLUS 0x3 /* ${var+text} */ +#define VSQUESTION 0x4 /* ${var?message} */ +#define VSASSIGN 0x5 /* ${var=text} */ +#define VSTRIMRIGHT 0x6 /* ${var%pattern} */ +#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */ +#define VSTRIMLEFT 0x8 /* ${var#pattern} */ +#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */ +#define VSLENGTH 0xa /* ${#var} */ + +/* values of checkkwd variable */ +#define CHKALIAS 0x1 +#define CHKKWD 0x2 +#define CHKNL 0x4 + +#define IBUFSIZ (BUFSIZ + 1) + +/* + * NEOF is returned by parsecmd when it encounters an end of file. It + * must be distinct from NULL, so we use the address of a variable that + * happens to be handy. + */ +static int plinno = 1; /* input line number */ + +/* number of characters left in input buffer */ +static int parsenleft; /* copy of parsefile->nleft */ +static int parselleft; /* copy of parsefile->lleft */ + +/* next character in input buffer */ +static char *parsenextc; /* copy of parsefile->nextc */ + +struct strpush { + struct strpush *prev; /* preceding string on stack */ + char *prevstring; + int prevnleft; +#ifdef BB_ASH_ALIAS + struct alias *ap; /* if push was associated with an alias */ +#endif + char *string; /* remember the string since it may change */ +}; + +struct parsefile { + struct parsefile *prev; /* preceding file on stack */ + int linno; /* current line */ + int fd; /* file descriptor (or -1 if string) */ + int nleft; /* number of chars left in this line */ + int lleft; /* number of chars left in this buffer */ + char *nextc; /* next char in buffer */ + char *buf; /* input buffer */ + struct strpush *strpush; /* for pushing strings at this level */ + struct strpush basestrpush; /* so pushing one is fast */ +}; + +static struct parsefile basepf; /* top level input file */ +static char basebuf[IBUFSIZ]; /* buffer for top level input file */ +static struct parsefile *parsefile = &basepf; /* current input file */ + + +static int tokpushback; /* last token pushed back */ +#define NEOF ((union node *)&tokpushback) +static int parsebackquote; /* nonzero if we are inside backquotes */ +static int doprompt; /* if set, prompt the user */ +static int needprompt; /* true if interactive and at start of line */ +static int lasttoken; /* last token read */ +static char *wordtext; /* text of last word returned by readtoken */ +static int checkkwd; +static struct nodelist *backquotelist; +static union node *redirnode; +static struct heredoc *heredoc; +static int quoteflag; /* set if (part of) last token was quoted */ +static int startlinno; /* line # where last token started */ + +static union node *parsecmd(int); +static void fixredir(union node *, const char *, int); +static const char *const *findkwd(const char *); +static char *endofname(const char *); + +/* $NetBSD: shell.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */ + +typedef void *pointer; + +static char nullstr[1]; /* zero length string */ +static const char spcstr[] = " "; +static const char snlfmt[] = "%s\n"; +static const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' }; +static const char illnum[] = "Illegal number: %s"; +static const char homestr[] = "HOME"; + +#ifdef DEBUG +#define TRACE(param) trace param +#define TRACEV(param) tracev param +#else +#define TRACE(param) +#define TRACEV(param) +#endif + +#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) +#define __builtin_expect(x, expected_value) (x) +#endif + +#define likely(x) __builtin_expect((x),1) + + +#define TEOF 0 +#define TNL 1 +#define TREDIR 2 +#define TWORD 3 +#define TSEMI 4 +#define TBACKGND 5 +#define TAND 6 +#define TOR 7 +#define TPIPE 8 +#define TLP 9 +#define TRP 10 +#define TENDCASE 11 +#define TENDBQUOTE 12 +#define TNOT 13 +#define TCASE 14 +#define TDO 15 +#define TDONE 16 +#define TELIF 17 +#define TELSE 18 +#define TESAC 19 +#define TFI 20 +#define TFOR 21 +#define TIF 22 +#define TIN 23 +#define TTHEN 24 +#define TUNTIL 25 +#define TWHILE 26 +#define TBEGIN 27 +#define TEND 28 + +/* first char is indicating which tokens mark the end of a list */ +static const char *const tokname_array[] = { + "\1end of file", + "\0newline", + "\0redirection", + "\0word", + "\0;", + "\0&", + "\0&&", + "\0||", + "\0|", + "\0(", + "\1)", + "\1;;", + "\1`", +#define KWDOFFSET 13 + /* the following are keywords */ + "\0!", + "\0case", + "\1do", + "\1done", + "\1elif", + "\1else", + "\1esac", + "\1fi", + "\0for", + "\0if", + "\0in", + "\1then", + "\0until", + "\0while", + "\0{", + "\1}", +}; + +static const char *tokname(int tok) +{ + static char buf[16]; + + if (tok >= TSEMI) + buf[0] = '"'; + sprintf(buf + (tok >= TSEMI), "%s%c", + tokname_array[tok] + 1, (tok >= TSEMI ? '"' : 0)); + return buf; +} + +/* $NetBSD: machdep.h,v 1.10 2002/10/07 14:26:08 christos Exp $ */ + +/* + * Most machines require the value returned from malloc to be aligned + * in some way. The following macro will get this right on many machines. + */ + +#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1) +/* + * It appears that grabstackstr() will barf with such alignments + * because stalloc() will return a string allocated in a new stackblock. + */ +#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE) + +/* + * This file was generated by the mksyntax program. + */ + + +/* Syntax classes */ +#define CWORD 0 /* character is nothing special */ +#define CNL 1 /* newline character */ +#define CBACK 2 /* a backslash character */ +#define CSQUOTE 3 /* single quote */ +#define CDQUOTE 4 /* double quote */ +#define CENDQUOTE 5 /* a terminating quote */ +#define CBQUOTE 6 /* backwards single quote */ +#define CVAR 7 /* a dollar sign */ +#define CENDVAR 8 /* a '}' character */ +#define CLP 9 /* a left paren in arithmetic */ +#define CRP 10 /* a right paren in arithmetic */ +#define CENDFILE 11 /* end of file */ +#define CCTL 12 /* like CWORD, except it must be escaped */ +#define CSPCL 13 /* these terminate a word */ +#define CIGN 14 /* character should be ignored */ + +#ifdef BB_ASH_ALIAS +#define SYNBASE 130 +#define PEOF -130 +#define PEOA -129 +#define PEOA_OR_PEOF PEOA +#else +#define SYNBASE 129 +#define PEOF -129 +#define PEOA_OR_PEOF PEOF +#endif + +#define is_digit(c) ((unsigned)((c) - '0') <= 9) +#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) +#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) + +/* + * is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise + * (assuming ascii char codes, as the original implementation did) + */ +#define is_special(c) \ + ( (((unsigned int)c) - 33 < 32) \ + && ((0xc1ff920dUL >> (((unsigned int)c) - 33)) & 1)) + +#define digit_val(c) ((c) - '0') + +/* + * This file was generated by the mksyntax program. + */ + +#ifdef BB_ASH_OPTIMIZE_FOR_SIZE +#define USE_SIT_FUNCTION +#endif + +/* number syntax index */ +#define BASESYNTAX 0 /* not in quotes */ +#define DQSYNTAX 1 /* in double quotes */ +#define SQSYNTAX 2 /* in single quotes */ +#define ARISYNTAX 3 /* in arithmetic */ + +#ifdef BB_ASH_MATH_SUPPORT +static const char S_I_T[][4] = { +#ifdef BB_ASH_ALIAS + {CSPCL, CIGN, CIGN, CIGN}, /* 0, PEOA */ +#endif + {CSPCL, CWORD, CWORD, CWORD}, /* 1, ' ' */ + {CNL, CNL, CNL, CNL}, /* 2, \n */ + {CWORD, CCTL, CCTL, CWORD}, /* 3, !*-/:=?[]~ */ + {CDQUOTE, CENDQUOTE, CWORD, CWORD}, /* 4, '"' */ + {CVAR, CVAR, CWORD, CVAR}, /* 5, $ */ + {CSQUOTE, CWORD, CENDQUOTE, CWORD}, /* 6, "'" */ + {CSPCL, CWORD, CWORD, CLP}, /* 7, ( */ + {CSPCL, CWORD, CWORD, CRP}, /* 8, ) */ + {CBACK, CBACK, CCTL, CBACK}, /* 9, \ */ + {CBQUOTE, CBQUOTE, CWORD, CBQUOTE}, /* 10, ` */ + {CENDVAR, CENDVAR, CWORD, CENDVAR}, /* 11, } */ +#ifndef USE_SIT_FUNCTION + {CENDFILE, CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */ + {CWORD, CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */ + {CCTL, CCTL, CCTL, CCTL} /* 14, CTLESC ... */ +#endif +}; +#else +static const char S_I_T[][3] = { +#ifdef BB_ASH_ALIAS + {CSPCL, CIGN, CIGN}, /* 0, PEOA */ +#endif + {CSPCL, CWORD, CWORD}, /* 1, ' ' */ + {CNL, CNL, CNL}, /* 2, \n */ + {CWORD, CCTL, CCTL}, /* 3, !*-/:=?[]~ */ + {CDQUOTE, CENDQUOTE, CWORD}, /* 4, '"' */ + {CVAR, CVAR, CWORD}, /* 5, $ */ + {CSQUOTE, CWORD, CENDQUOTE}, /* 6, "'" */ + {CSPCL, CWORD, CWORD}, /* 7, ( */ + {CSPCL, CWORD, CWORD}, /* 8, ) */ + {CBACK, CBACK, CCTL}, /* 9, \ */ + {CBQUOTE, CBQUOTE, CWORD}, /* 10, ` */ + {CENDVAR, CENDVAR, CWORD}, /* 11, } */ +#ifndef USE_SIT_FUNCTION + {CENDFILE, CENDFILE, CENDFILE}, /* 12, PEOF */ + {CWORD, CWORD, CWORD}, /* 13, 0-9A-Za-z */ + {CCTL, CCTL, CCTL} /* 14, CTLESC ... */ +#endif +}; +#endif /* BB_ASH_MATH_SUPPORT */ + +#ifdef USE_SIT_FUNCTION + +#define U_C(c) ((unsigned char)(c)) + +static int SIT(int c, int syntax) +{ + static const char spec_symbls[] = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~"; +#ifdef BB_ASH_ALIAS + static const char syntax_index_table[] = { + 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */ + 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */ + 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */ + 11, 3 /* "}~" */ + }; +#else + static const char syntax_index_table[] = { + 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */ + 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */ + 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */ + 10, 2 /* "}~" */ + }; +#endif + const char *s; + int indx; + + if (c == PEOF) /* 2^8+2 */ + return CENDFILE; +#ifdef BB_ASH_ALIAS + if (c == PEOA) /* 2^8+1 */ + indx = 0; + else +#endif + if (U_C(c) >= U_C(CTLESC) && U_C(c) <= U_C(CTLQUOTEMARK)) + return CCTL; + else { + s = strchr(spec_symbls, c); + if (s == 0 || *s == 0) + return CWORD; + indx = syntax_index_table[(s - spec_symbls)]; + } + return S_I_T[indx][syntax]; +} + +#else /* USE_SIT_FUNCTION */ + +#define SIT(c, syntax) S_I_T[(int)syntax_index_table[((int)c)+SYNBASE]][syntax] + +#ifdef BB_ASH_ALIAS +#define CSPCL_CIGN_CIGN_CIGN 0 +#define CSPCL_CWORD_CWORD_CWORD 1 +#define CNL_CNL_CNL_CNL 2 +#define CWORD_CCTL_CCTL_CWORD 3 +#define CDQUOTE_CENDQUOTE_CWORD_CWORD 4 +#define CVAR_CVAR_CWORD_CVAR 5 +#define CSQUOTE_CWORD_CENDQUOTE_CWORD 6 +#define CSPCL_CWORD_CWORD_CLP 7 +#define CSPCL_CWORD_CWORD_CRP 8 +#define CBACK_CBACK_CCTL_CBACK 9 +#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 10 +#define CENDVAR_CENDVAR_CWORD_CENDVAR 11 +#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 12 +#define CWORD_CWORD_CWORD_CWORD 13 +#define CCTL_CCTL_CCTL_CCTL 14 +#else +#define CSPCL_CWORD_CWORD_CWORD 0 +#define CNL_CNL_CNL_CNL 1 +#define CWORD_CCTL_CCTL_CWORD 2 +#define CDQUOTE_CENDQUOTE_CWORD_CWORD 3 +#define CVAR_CVAR_CWORD_CVAR 4 +#define CSQUOTE_CWORD_CENDQUOTE_CWORD 5 +#define CSPCL_CWORD_CWORD_CLP 6 +#define CSPCL_CWORD_CWORD_CRP 7 +#define CBACK_CBACK_CCTL_CBACK 8 +#define CBQUOTE_CBQUOTE_CWORD_CBQUOTE 9 +#define CENDVAR_CENDVAR_CWORD_CENDVAR 10 +#define CENDFILE_CENDFILE_CENDFILE_CENDFILE 11 +#define CWORD_CWORD_CWORD_CWORD 12 +#define CCTL_CCTL_CCTL_CCTL 13 +#endif + +static const char syntax_index_table[258] = { + /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */ + /* 0 PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE, +#ifdef BB_ASH_ALIAS + /* 1 PEOA */ CSPCL_CIGN_CIGN_CIGN, +#endif + /* 2 -128 0x80 */ CWORD_CWORD_CWORD_CWORD, + /* 3 -127 CTLESC */ CCTL_CCTL_CCTL_CCTL, + /* 4 -126 CTLVAR */ CCTL_CCTL_CCTL_CCTL, + /* 5 -125 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL, + /* 6 -124 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL, + /* 7 -123 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL, + /* 8 -122 CTLARI */ CCTL_CCTL_CCTL_CCTL, + /* 9 -121 CTLENDARI */ CCTL_CCTL_CCTL_CCTL, + /* 10 -120 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL, + /* 11 -119 */ CWORD_CWORD_CWORD_CWORD, + /* 12 -118 */ CWORD_CWORD_CWORD_CWORD, + /* 13 -117 */ CWORD_CWORD_CWORD_CWORD, + /* 14 -116 */ CWORD_CWORD_CWORD_CWORD, + /* 15 -115 */ CWORD_CWORD_CWORD_CWORD, + /* 16 -114 */ CWORD_CWORD_CWORD_CWORD, + /* 17 -113 */ CWORD_CWORD_CWORD_CWORD, + /* 18 -112 */ CWORD_CWORD_CWORD_CWORD, + /* 19 -111 */ CWORD_CWORD_CWORD_CWORD, + /* 20 -110 */ CWORD_CWORD_CWORD_CWORD, + /* 21 -109 */ CWORD_CWORD_CWORD_CWORD, + /* 22 -108 */ CWORD_CWORD_CWORD_CWORD, + /* 23 -107 */ CWORD_CWORD_CWORD_CWORD, + /* 24 -106 */ CWORD_CWORD_CWORD_CWORD, + /* 25 -105 */ CWORD_CWORD_CWORD_CWORD, + /* 26 -104 */ CWORD_CWORD_CWORD_CWORD, + /* 27 -103 */ CWORD_CWORD_CWORD_CWORD, + /* 28 -102 */ CWORD_CWORD_CWORD_CWORD, + /* 29 -101 */ CWORD_CWORD_CWORD_CWORD, + /* 30 -100 */ CWORD_CWORD_CWORD_CWORD, + /* 31 -99 */ CWORD_CWORD_CWORD_CWORD, + /* 32 -98 */ CWORD_CWORD_CWORD_CWORD, + /* 33 -97 */ CWORD_CWORD_CWORD_CWORD, + /* 34 -96 */ CWORD_CWORD_CWORD_CWORD, + /* 35 -95 */ CWORD_CWORD_CWORD_CWORD, + /* 36 -94 */ CWORD_CWORD_CWORD_CWORD, + /* 37 -93 */ CWORD_CWORD_CWORD_CWORD, + /* 38 -92 */ CWORD_CWORD_CWORD_CWORD, + /* 39 -91 */ CWORD_CWORD_CWORD_CWORD, + /* 40 -90 */ CWORD_CWORD_CWORD_CWORD, + /* 41 -89 */ CWORD_CWORD_CWORD_CWORD, + /* 42 -88 */ CWORD_CWORD_CWORD_CWORD, + /* 43 -87 */ CWORD_CWORD_CWORD_CWORD, + /* 44 -86 */ CWORD_CWORD_CWORD_CWORD, + /* 45 -85 */ CWORD_CWORD_CWORD_CWORD, + /* 46 -84 */ CWORD_CWORD_CWORD_CWORD, + /* 47 -83 */ CWORD_CWORD_CWORD_CWORD, + /* 48 -82 */ CWORD_CWORD_CWORD_CWORD, + /* 49 -81 */ CWORD_CWORD_CWORD_CWORD, + /* 50 -80 */ CWORD_CWORD_CWORD_CWORD, + /* 51 -79 */ CWORD_CWORD_CWORD_CWORD, + /* 52 -78 */ CWORD_CWORD_CWORD_CWORD, + /* 53 -77 */ CWORD_CWORD_CWORD_CWORD, + /* 54 -76 */ CWORD_CWORD_CWORD_CWORD, + /* 55 -75 */ CWORD_CWORD_CWORD_CWORD, + /* 56 -74 */ CWORD_CWORD_CWORD_CWORD, + /* 57 -73 */ CWORD_CWORD_CWORD_CWORD, + /* 58 -72 */ CWORD_CWORD_CWORD_CWORD, + /* 59 -71 */ CWORD_CWORD_CWORD_CWORD, + /* 60 -70 */ CWORD_CWORD_CWORD_CWORD, + /* 61 -69 */ CWORD_CWORD_CWORD_CWORD, + /* 62 -68 */ CWORD_CWORD_CWORD_CWORD, + /* 63 -67 */ CWORD_CWORD_CWORD_CWORD, + /* 64 -66 */ CWORD_CWORD_CWORD_CWORD, + /* 65 -65 */ CWORD_CWORD_CWORD_CWORD, + /* 66 -64 */ CWORD_CWORD_CWORD_CWORD, + /* 67 -63 */ CWORD_CWORD_CWORD_CWORD, + /* 68 -62 */ CWORD_CWORD_CWORD_CWORD, + /* 69 -61 */ CWORD_CWORD_CWORD_CWORD, + /* 70 -60 */ CWORD_CWORD_CWORD_CWORD, + /* 71 -59 */ CWORD_CWORD_CWORD_CWORD, + /* 72 -58 */ CWORD_CWORD_CWORD_CWORD, + /* 73 -57 */ CWORD_CWORD_CWORD_CWORD, + /* 74 -56 */ CWORD_CWORD_CWORD_CWORD, + /* 75 -55 */ CWORD_CWORD_CWORD_CWORD, + /* 76 -54 */ CWORD_CWORD_CWORD_CWORD, + /* 77 -53 */ CWORD_CWORD_CWORD_CWORD, + /* 78 -52 */ CWORD_CWORD_CWORD_CWORD, + /* 79 -51 */ CWORD_CWORD_CWORD_CWORD, + /* 80 -50 */ CWORD_CWORD_CWORD_CWORD, + /* 81 -49 */ CWORD_CWORD_CWORD_CWORD, + /* 82 -48 */ CWORD_CWORD_CWORD_CWORD, + /* 83 -47 */ CWORD_CWORD_CWORD_CWORD, + /* 84 -46 */ CWORD_CWORD_CWORD_CWORD, + /* 85 -45 */ CWORD_CWORD_CWORD_CWORD, + /* 86 -44 */ CWORD_CWORD_CWORD_CWORD, + /* 87 -43 */ CWORD_CWORD_CWORD_CWORD, + /* 88 -42 */ CWORD_CWORD_CWORD_CWORD, + /* 89 -41 */ CWORD_CWORD_CWORD_CWORD, + /* 90 -40 */ CWORD_CWORD_CWORD_CWORD, + /* 91 -39 */ CWORD_CWORD_CWORD_CWORD, + /* 92 -38 */ CWORD_CWORD_CWORD_CWORD, + /* 93 -37 */ CWORD_CWORD_CWORD_CWORD, + /* 94 -36 */ CWORD_CWORD_CWORD_CWORD, + /* 95 -35 */ CWORD_CWORD_CWORD_CWORD, + /* 96 -34 */ CWORD_CWORD_CWORD_CWORD, + /* 97 -33 */ CWORD_CWORD_CWORD_CWORD, + /* 98 -32 */ CWORD_CWORD_CWORD_CWORD, + /* 99 -31 */ CWORD_CWORD_CWORD_CWORD, + /* 100 -30 */ CWORD_CWORD_CWORD_CWORD, + /* 101 -29 */ CWORD_CWORD_CWORD_CWORD, + /* 102 -28 */ CWORD_CWORD_CWORD_CWORD, + /* 103 -27 */ CWORD_CWORD_CWORD_CWORD, + /* 104 -26 */ CWORD_CWORD_CWORD_CWORD, + /* 105 -25 */ CWORD_CWORD_CWORD_CWORD, + /* 106 -24 */ CWORD_CWORD_CWORD_CWORD, + /* 107 -23 */ CWORD_CWORD_CWORD_CWORD, + /* 108 -22 */ CWORD_CWORD_CWORD_CWORD, + /* 109 -21 */ CWORD_CWORD_CWORD_CWORD, + /* 110 -20 */ CWORD_CWORD_CWORD_CWORD, + /* 111 -19 */ CWORD_CWORD_CWORD_CWORD, + /* 112 -18 */ CWORD_CWORD_CWORD_CWORD, + /* 113 -17 */ CWORD_CWORD_CWORD_CWORD, + /* 114 -16 */ CWORD_CWORD_CWORD_CWORD, + /* 115 -15 */ CWORD_CWORD_CWORD_CWORD, + /* 116 -14 */ CWORD_CWORD_CWORD_CWORD, + /* 117 -13 */ CWORD_CWORD_CWORD_CWORD, + /* 118 -12 */ CWORD_CWORD_CWORD_CWORD, + /* 119 -11 */ CWORD_CWORD_CWORD_CWORD, + /* 120 -10 */ CWORD_CWORD_CWORD_CWORD, + /* 121 -9 */ CWORD_CWORD_CWORD_CWORD, + /* 122 -8 */ CWORD_CWORD_CWORD_CWORD, + /* 123 -7 */ CWORD_CWORD_CWORD_CWORD, + /* 124 -6 */ CWORD_CWORD_CWORD_CWORD, + /* 125 -5 */ CWORD_CWORD_CWORD_CWORD, + /* 126 -4 */ CWORD_CWORD_CWORD_CWORD, + /* 127 -3 */ CWORD_CWORD_CWORD_CWORD, + /* 128 -2 */ CWORD_CWORD_CWORD_CWORD, + /* 129 -1 */ CWORD_CWORD_CWORD_CWORD, + /* 130 0 */ CWORD_CWORD_CWORD_CWORD, + /* 131 1 */ CWORD_CWORD_CWORD_CWORD, + /* 132 2 */ CWORD_CWORD_CWORD_CWORD, + /* 133 3 */ CWORD_CWORD_CWORD_CWORD, + /* 134 4 */ CWORD_CWORD_CWORD_CWORD, + /* 135 5 */ CWORD_CWORD_CWORD_CWORD, + /* 136 6 */ CWORD_CWORD_CWORD_CWORD, + /* 137 7 */ CWORD_CWORD_CWORD_CWORD, + /* 138 8 */ CWORD_CWORD_CWORD_CWORD, + /* 139 9 "\t" */ CSPCL_CWORD_CWORD_CWORD, + /* 140 10 "\n" */ CNL_CNL_CNL_CNL, + /* 141 11 */ CWORD_CWORD_CWORD_CWORD, + /* 142 12 */ CWORD_CWORD_CWORD_CWORD, + /* 143 13 */ CWORD_CWORD_CWORD_CWORD, + /* 144 14 */ CWORD_CWORD_CWORD_CWORD, + /* 145 15 */ CWORD_CWORD_CWORD_CWORD, + /* 146 16 */ CWORD_CWORD_CWORD_CWORD, + /* 147 17 */ CWORD_CWORD_CWORD_CWORD, + /* 148 18 */ CWORD_CWORD_CWORD_CWORD, + /* 149 19 */ CWORD_CWORD_CWORD_CWORD, + /* 150 20 */ CWORD_CWORD_CWORD_CWORD, + /* 151 21 */ CWORD_CWORD_CWORD_CWORD, + /* 152 22 */ CWORD_CWORD_CWORD_CWORD, + /* 153 23 */ CWORD_CWORD_CWORD_CWORD, + /* 154 24 */ CWORD_CWORD_CWORD_CWORD, + /* 155 25 */ CWORD_CWORD_CWORD_CWORD, + /* 156 26 */ CWORD_CWORD_CWORD_CWORD, + /* 157 27 */ CWORD_CWORD_CWORD_CWORD, + /* 158 28 */ CWORD_CWORD_CWORD_CWORD, + /* 159 29 */ CWORD_CWORD_CWORD_CWORD, + /* 160 30 */ CWORD_CWORD_CWORD_CWORD, + /* 161 31 */ CWORD_CWORD_CWORD_CWORD, + /* 162 32 " " */ CSPCL_CWORD_CWORD_CWORD, + /* 163 33 "!" */ CWORD_CCTL_CCTL_CWORD, + /* 164 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD, + /* 165 35 "#" */ CWORD_CWORD_CWORD_CWORD, + /* 166 36 "$" */ CVAR_CVAR_CWORD_CVAR, + /* 167 37 "%" */ CWORD_CWORD_CWORD_CWORD, + /* 168 38 "&" */ CSPCL_CWORD_CWORD_CWORD, + /* 169 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD, + /* 170 40 "(" */ CSPCL_CWORD_CWORD_CLP, + /* 171 41 ")" */ CSPCL_CWORD_CWORD_CRP, + /* 172 42 "*" */ CWORD_CCTL_CCTL_CWORD, + /* 173 43 "+" */ CWORD_CWORD_CWORD_CWORD, + /* 174 44 "," */ CWORD_CWORD_CWORD_CWORD, + /* 175 45 "-" */ CWORD_CCTL_CCTL_CWORD, + /* 176 46 "." */ CWORD_CWORD_CWORD_CWORD, + /* 177 47 "/" */ CWORD_CCTL_CCTL_CWORD, + /* 178 48 "0" */ CWORD_CWORD_CWORD_CWORD, + /* 179 49 "1" */ CWORD_CWORD_CWORD_CWORD, + /* 180 50 "2" */ CWORD_CWORD_CWORD_CWORD, + /* 181 51 "3" */ CWORD_CWORD_CWORD_CWORD, + /* 182 52 "4" */ CWORD_CWORD_CWORD_CWORD, + /* 183 53 "5" */ CWORD_CWORD_CWORD_CWORD, + /* 184 54 "6" */ CWORD_CWORD_CWORD_CWORD, + /* 185 55 "7" */ CWORD_CWORD_CWORD_CWORD, + /* 186 56 "8" */ CWORD_CWORD_CWORD_CWORD, + /* 187 57 "9" */ CWORD_CWORD_CWORD_CWORD, + /* 188 58 ":" */ CWORD_CCTL_CCTL_CWORD, + /* 189 59 ";" */ CSPCL_CWORD_CWORD_CWORD, + /* 190 60 "<" */ CSPCL_CWORD_CWORD_CWORD, + /* 191 61 "=" */ CWORD_CCTL_CCTL_CWORD, + /* 192 62 ">" */ CSPCL_CWORD_CWORD_CWORD, + /* 193 63 "?" */ CWORD_CCTL_CCTL_CWORD, + /* 194 64 "@" */ CWORD_CWORD_CWORD_CWORD, + /* 195 65 "A" */ CWORD_CWORD_CWORD_CWORD, + /* 196 66 "B" */ CWORD_CWORD_CWORD_CWORD, + /* 197 67 "C" */ CWORD_CWORD_CWORD_CWORD, + /* 198 68 "D" */ CWORD_CWORD_CWORD_CWORD, + /* 199 69 "E" */ CWORD_CWORD_CWORD_CWORD, + /* 200 70 "F" */ CWORD_CWORD_CWORD_CWORD, + /* 201 71 "G" */ CWORD_CWORD_CWORD_CWORD, + /* 202 72 "H" */ CWORD_CWORD_CWORD_CWORD, + /* 203 73 "I" */ CWORD_CWORD_CWORD_CWORD, + /* 204 74 "J" */ CWORD_CWORD_CWORD_CWORD, + /* 205 75 "K" */ CWORD_CWORD_CWORD_CWORD, + /* 206 76 "L" */ CWORD_CWORD_CWORD_CWORD, + /* 207 77 "M" */ CWORD_CWORD_CWORD_CWORD, + /* 208 78 "N" */ CWORD_CWORD_CWORD_CWORD, + /* 209 79 "O" */ CWORD_CWORD_CWORD_CWORD, + /* 210 80 "P" */ CWORD_CWORD_CWORD_CWORD, + /* 211 81 "Q" */ CWORD_CWORD_CWORD_CWORD, + /* 212 82 "R" */ CWORD_CWORD_CWORD_CWORD, + /* 213 83 "S" */ CWORD_CWORD_CWORD_CWORD, + /* 214 84 "T" */ CWORD_CWORD_CWORD_CWORD, + /* 215 85 "U" */ CWORD_CWORD_CWORD_CWORD, + /* 216 86 "V" */ CWORD_CWORD_CWORD_CWORD, + /* 217 87 "W" */ CWORD_CWORD_CWORD_CWORD, + /* 218 88 "X" */ CWORD_CWORD_CWORD_CWORD, + /* 219 89 "Y" */ CWORD_CWORD_CWORD_CWORD, + /* 220 90 "Z" */ CWORD_CWORD_CWORD_CWORD, + /* 221 91 "[" */ CWORD_CCTL_CCTL_CWORD, + /* 222 92 "\" */ CBACK_CBACK_CCTL_CBACK, + /* 223 93 "]" */ CWORD_CCTL_CCTL_CWORD, + /* 224 94 "^" */ CWORD_CWORD_CWORD_CWORD, + /* 225 95 "_" */ CWORD_CWORD_CWORD_CWORD, + /* 226 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE, + /* 227 97 "a" */ CWORD_CWORD_CWORD_CWORD, + /* 228 98 "b" */ CWORD_CWORD_CWORD_CWORD, + /* 229 99 "c" */ CWORD_CWORD_CWORD_CWORD, + /* 230 100 "d" */ CWORD_CWORD_CWORD_CWORD, + /* 231 101 "e" */ CWORD_CWORD_CWORD_CWORD, + /* 232 102 "f" */ CWORD_CWORD_CWORD_CWORD, + /* 233 103 "g" */ CWORD_CWORD_CWORD_CWORD, + /* 234 104 "h" */ CWORD_CWORD_CWORD_CWORD, + /* 235 105 "i" */ CWORD_CWORD_CWORD_CWORD, + /* 236 106 "j" */ CWORD_CWORD_CWORD_CWORD, + /* 237 107 "k" */ CWORD_CWORD_CWORD_CWORD, + /* 238 108 "l" */ CWORD_CWORD_CWORD_CWORD, + /* 239 109 "m" */ CWORD_CWORD_CWORD_CWORD, + /* 240 110 "n" */ CWORD_CWORD_CWORD_CWORD, + /* 241 111 "o" */ CWORD_CWORD_CWORD_CWORD, + /* 242 112 "p" */ CWORD_CWORD_CWORD_CWORD, + /* 243 113 "q" */ CWORD_CWORD_CWORD_CWORD, + /* 244 114 "r" */ CWORD_CWORD_CWORD_CWORD, + /* 245 115 "s" */ CWORD_CWORD_CWORD_CWORD, + /* 246 116 "t" */ CWORD_CWORD_CWORD_CWORD, + /* 247 117 "u" */ CWORD_CWORD_CWORD_CWORD, + /* 248 118 "v" */ CWORD_CWORD_CWORD_CWORD, + /* 249 119 "w" */ CWORD_CWORD_CWORD_CWORD, + /* 250 120 "x" */ CWORD_CWORD_CWORD_CWORD, + /* 251 121 "y" */ CWORD_CWORD_CWORD_CWORD, + /* 252 122 "z" */ CWORD_CWORD_CWORD_CWORD, + /* 253 123 "{" */ CWORD_CWORD_CWORD_CWORD, + /* 254 124 "|" */ CSPCL_CWORD_CWORD_CWORD, + /* 255 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR, + /* 256 126 "~" */ CWORD_CCTL_CCTL_CWORD, + /* 257 127 */ CWORD_CWORD_CWORD_CWORD, +}; + +#endif /* USE_SIT_FUNCTION */ + +/* $NetBSD: alias.c,v 1.11 2002/11/24 22:35:38 christos Exp $ */ + + +#define ATABSIZE 39 + +static int funcblocksize; /* size of structures in function */ +static int funcstringsize; /* size of strings in node */ +static pointer funcblock; /* block to allocate function from */ +static char *funcstring; /* block to allocate strings from */ + +static const short nodesize[26] = { + SHELL_ALIGN(sizeof (struct ncmd)), + SHELL_ALIGN(sizeof (struct npipe)), + SHELL_ALIGN(sizeof (struct nredir)), + SHELL_ALIGN(sizeof (struct nredir)), + SHELL_ALIGN(sizeof (struct nredir)), + SHELL_ALIGN(sizeof (struct nbinary)), + SHELL_ALIGN(sizeof (struct nbinary)), + SHELL_ALIGN(sizeof (struct nbinary)), + SHELL_ALIGN(sizeof (struct nif)), + SHELL_ALIGN(sizeof (struct nbinary)), + SHELL_ALIGN(sizeof (struct nbinary)), + SHELL_ALIGN(sizeof (struct nfor)), + SHELL_ALIGN(sizeof (struct ncase)), + SHELL_ALIGN(sizeof (struct nclist)), + SHELL_ALIGN(sizeof (struct narg)), + SHELL_ALIGN(sizeof (struct narg)), + SHELL_ALIGN(sizeof (struct nfile)), + SHELL_ALIGN(sizeof (struct nfile)), + SHELL_ALIGN(sizeof (struct nfile)), + SHELL_ALIGN(sizeof (struct nfile)), + SHELL_ALIGN(sizeof (struct nfile)), + SHELL_ALIGN(sizeof (struct ndup)), + SHELL_ALIGN(sizeof (struct ndup)), + SHELL_ALIGN(sizeof (struct nhere)), + SHELL_ALIGN(sizeof (struct nhere)), + SHELL_ALIGN(sizeof (struct nnot)), +}; + + +static void calcsize(union node *); +static void sizenodelist(struct nodelist *); +static union node *copynode(union node *); +static struct nodelist *copynodelist(struct nodelist *); +static char *nodesavestr(char *); + + + +static void evalstring(char *, int); +union node; /* BLETCH for ansi C */ +static void evaltree(union node *, int); +static void evalbackcmd(union node *, struct backcmd *); + +/* in_function returns nonzero if we are currently evaluating a function */ +#define in_function() funcnest +static int evalskip; /* set if we are skipping commands */ +static int skipcount; /* number of levels to skip */ +static int funcnest; /* depth of function calls */ + +/* reasons for skipping commands (see comment on breakcmd routine) */ +#define SKIPBREAK 1 +#define SKIPCONT 2 +#define SKIPFUNC 3 +#define SKIPFILE 4 + +/* + * This file was generated by the mkbuiltins program. + */ + +#ifdef JOBS +static int bgcmd(int, char **); +#endif +static int breakcmd(int, char **); +static int cdcmd(int, char **); +#ifdef BB_ASH_CMDCMD +static int commandcmd(int, char **); +#endif +static int dotcmd(int, char **); +static int evalcmd(int, char **); +static int execcmd(int, char **); +static int exitcmd(int, char **); +static int exportcmd(int, char **); +static int falsecmd(int, char **); +#ifdef JOBS +static int fgcmd(int, char **); +#endif +#ifdef BB_ASH_GETOPTS +static int getoptscmd(int, char **); +#endif +static int hashcmd(int, char **); +#ifndef BB_FEATURE_SH_EXTRA_QUIET +static int helpcmd(int argc, char **argv); +#endif +#ifdef JOBS +static int jobscmd(int, char **); +#endif +#ifdef BB_ASH_MATH_SUPPORT +static int letcmd(int, char **); +#endif +static int localcmd(int, char **); +static int pwdcmd(int, char **); +static int readcmd(int, char **); +static int returncmd(int, char **); +static int setcmd(int, char **); +static int shiftcmd(int, char **); +static int timescmd(int, char **); +static int trapcmd(int, char **); +static int truecmd(int, char **); +static int typecmd(int, char **); +static int umaskcmd(int, char **); +static int unsetcmd(int, char **); +static int waitcmd(int, char **); +static int ulimitcmd(int, char **); +#ifdef JOBS +static int killcmd(int, char **); +#endif + +/* $NetBSD: mail.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */ + +#ifdef BB_ASH_MAIL +static void chkmail(void); +static void changemail(const char *); +#endif + +/* $NetBSD: exec.h,v 1.20 2003/01/22 20:36:04 dsl Exp $ */ + +/* values of cmdtype */ +#define CMDUNKNOWN -1 /* no entry in table for command */ +#define CMDNORMAL 0 /* command is an executable program */ +#define CMDFUNCTION 1 /* command is a shell function */ +#define CMDBUILTIN 2 /* command is a shell builtin */ + +struct builtincmd { + const char *name; + int (*builtin)(int, char **); + /* unsigned flags; */ +}; + +#ifdef BB_ASH_CMDCMD +# ifdef JOBS +# ifdef BB_ASH_ALIAS +# define COMMANDCMD (builtincmd + 7) +# define EXECCMD (builtincmd + 10) +# else +# define COMMANDCMD (builtincmd + 6) +# define EXECCMD (builtincmd + 9) +# endif +# else /* ! JOBS */ +# ifdef BB_ASH_ALIAS +# define COMMANDCMD (builtincmd + 6) +# define EXECCMD (builtincmd + 9) +# else +# define COMMANDCMD (builtincmd + 5) +# define EXECCMD (builtincmd + 8) +# endif +# endif /* JOBS */ +#else /* ! BB_ASH_CMDCMD */ +# ifdef JOBS +# ifdef BB_ASH_ALIAS +# define EXECCMD (builtincmd + 9) +# else +# define EXECCMD (builtincmd + 8) +# endif +# else /* ! JOBS */ +# ifdef BB_ASH_ALIAS +# define EXECCMD (builtincmd + 8) +# else +# define EXECCMD (builtincmd + 7) +# endif +# endif /* JOBS */ +#endif /* BB_ASH_CMDCMD */ + +#define BUILTIN_NOSPEC "0" +#define BUILTIN_SPECIAL "1" +#define BUILTIN_REGULAR "2" +#define BUILTIN_SPEC_REG "3" +#define BUILTIN_ASSIGN "4" +#define BUILTIN_SPEC_ASSG "5" +#define BUILTIN_REG_ASSG "6" +#define BUILTIN_SPEC_REG_ASSG "7" + +#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1) +#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2) + +static const struct builtincmd builtincmd[] = { + { BUILTIN_SPEC_REG ".", dotcmd }, + { BUILTIN_SPEC_REG ":", truecmd }, +#ifdef BB_ASH_ALIAS + { BUILTIN_REG_ASSG "alias", aliascmd }, +#endif +#ifdef JOBS + { BUILTIN_REGULAR "bg", bgcmd }, +#endif + { BUILTIN_SPEC_REG "break", breakcmd }, + { BUILTIN_REGULAR "cd", cdcmd }, + { BUILTIN_NOSPEC "chdir", cdcmd }, +#ifdef BB_ASH_CMDCMD + { BUILTIN_REGULAR "command", commandcmd }, +#endif + { BUILTIN_SPEC_REG "continue", breakcmd }, + { BUILTIN_SPEC_REG "eval", evalcmd }, + { BUILTIN_SPEC_REG "exec", execcmd }, + { BUILTIN_SPEC_REG "exit", exitcmd }, + { BUILTIN_SPEC_REG_ASSG "export", exportcmd }, + { BUILTIN_REGULAR "false", falsecmd }, +#ifdef JOBS + { BUILTIN_REGULAR "fg", fgcmd }, +#endif +#ifdef BB_ASH_GETOPTS + { BUILTIN_REGULAR "getopts", getoptscmd }, +#endif + { BUILTIN_NOSPEC "hash", hashcmd }, +#ifndef BB_FEATURE_SH_EXTRA_QUIET + { BUILTIN_NOSPEC "help", helpcmd }, +#endif +#ifdef JOBS + { BUILTIN_REGULAR "jobs", jobscmd }, + { BUILTIN_REGULAR "kill", killcmd }, +#endif +#ifdef BB_ASH_MATH_SUPPORT + { BUILTIN_NOSPEC "let", letcmd }, +#endif + { BUILTIN_ASSIGN "local", localcmd }, + { BUILTIN_NOSPEC "pwd", pwdcmd }, + { BUILTIN_REGULAR "read", readcmd }, + { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd }, + { BUILTIN_SPEC_REG "return", returncmd }, + { BUILTIN_SPEC_REG "set", setcmd }, + { BUILTIN_SPEC_REG "shift", shiftcmd }, + { BUILTIN_SPEC_REG "times", timescmd }, + { BUILTIN_SPEC_REG "trap", trapcmd }, + { BUILTIN_REGULAR "true", truecmd }, + { BUILTIN_NOSPEC "type", typecmd }, + { BUILTIN_NOSPEC "ulimit", ulimitcmd }, + { BUILTIN_REGULAR "umask", umaskcmd }, +#ifdef BB_ASH_ALIAS + { BUILTIN_REGULAR "unalias", unaliascmd }, +#endif + { BUILTIN_SPEC_REG "unset", unsetcmd }, + { BUILTIN_REGULAR "wait", waitcmd }, +}; + +#define NUMBUILTINS (sizeof (builtincmd) / sizeof (struct builtincmd) ) + + + +struct cmdentry { + int cmdtype; + union param { + int index; + const struct builtincmd *cmd; + struct funcnode *func; + } u; +}; + + +/* action to find_command() */ +#define DO_ERR 0x01 /* prints errors */ +#define DO_ABS 0x02 /* checks absolute paths */ +#define DO_NOFUNC 0x04 /* don't return shell functions, for command */ +#define DO_ALTPATH 0x08 /* using alternate path */ +#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */ + +static const char *pathopt; /* set by padvance */ + +static void shellexec(char **, const char *, int) + __attribute__((__noreturn__)); +static char *padvance(const char **, const char *); +static void find_command(char *, struct cmdentry *, int, const char *); +static struct builtincmd *find_builtin(const char *); +static void hashcd(void); +static void changepath(const char *); +static void defun(char *, union node *); +static void unsetfunc(const char *); + +#ifdef BB_ASH_MATH_SUPPORT +static int dash_arith(const char *); +#endif + +/* $NetBSD: init.h,v 1.9 2002/11/24 22:35:40 christos Exp $ */ + +static void reset(void); + +/* $NetBSD: var.h,v 1.21 2003/01/22 20:36:04 dsl Exp $ */ + +/* + * Shell variables. + */ + +/* flags */ +#define VEXPORT 0x01 /* variable is exported */ +#define VREADONLY 0x02 /* variable cannot be modified */ +#define VSTRFIXED 0x04 /* variable struct is statically allocated */ +#define VTEXTFIXED 0x08 /* text is statically allocated */ +#define VSTACK 0x10 /* text is allocated on the stack */ +#define VUNSET 0x20 /* the variable is not set */ +#define VNOFUNC 0x40 /* don't call the callback function */ +#define VNOSET 0x80 /* do not set variable - just readonly test */ +#define VNOSAVE 0x100 /* when text is on the heap before setvareq */ + + +struct var { + struct var *next; /* next entry in hash list */ + int flags; /* flags are defined above */ + const char *text; /* name=value */ + void (*func)(const char *); + /* function to be called when */ + /* the variable gets set/unset */ +}; + +struct localvar { + struct localvar *next; /* next local variable in list */ + struct var *vp; /* the variable that was made local */ + int flags; /* saved flags */ + const char *text; /* saved text */ +}; + + +static struct localvar *localvars; + +/* + * Shell variables. + */ + +#ifdef BB_ASH_GETOPTS +static void getoptsreset(const char *); +#endif + +#ifdef BB_LOCALE_SUPPORT +#include +static void change_lc_all(const char *value); +static void change_lc_ctype(const char *value); +#endif + +#define VTABSIZE 39 + +static const char defpathvar[] = "PATH=/usr/local/bin:/usr/bin:/sbin:/bin"; +#ifdef IFS_BROKEN +static const char defifsvar[] = "IFS= \t\n"; +#define defifs (defifsvar + 4) +#else +static const char defifs[] = " \t\n"; +#endif + + +static struct var varinit[] = { +#ifdef IFS_BROKEN + { 0, VSTRFIXED|VTEXTFIXED, defifsvar, 0 }, +#else + { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", 0 }, +#endif + +#ifdef BB_ASH_MAIL + { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail }, + { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, +#endif + + { 0, VSTRFIXED|VTEXTFIXED, defpathvar, changepath }, + { 0, VSTRFIXED|VTEXTFIXED, "PS1=$ ", 0 }, + { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 }, + { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 }, +#ifdef BB_ASH_GETOPTS + { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, +#endif +#ifdef BB_LOCALE_SUPPORT + {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL=", change_lc_all}, + {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE=", change_lc_ctype}, +#endif +#ifdef BB_FEATURE_COMMAND_SAVEHISTORY + {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE=", NULL}, +#endif +}; + +#define vifs varinit[0] +#ifdef BB_ASH_MAIL +#define vmail (&vifs)[1] +#define vmpath (&vmail)[1] +#else +#define vmpath vifs +#endif +#define vpath (&vmpath)[1] +#define vps1 (&vpath)[1] +#define vps2 (&vps1)[1] +#define vps4 (&vps2)[1] +#define voptind (&vps4)[1] + +#define defpath (defpathvar + 5) + +/* + * The following macros access the values of the above variables. + * They have to skip over the name. They return the null string + * for unset variables. + */ + +#define ifsval() (vifs.text + 4) +#define ifsset() ((vifs.flags & VUNSET) == 0) +#define mailval() (vmail.text + 5) +#define mpathval() (vmpath.text + 9) +#define pathval() (vpath.text + 5) +#define ps1val() (vps1.text + 4) +#define ps2val() (vps2.text + 4) +#define ps4val() (vps4.text + 4) +#define optindval() (voptind.text + 7) + +#define mpathset() ((vmpath.flags & VUNSET) == 0) + +static void setvar(const char *, const char *, int); +static void setvareq(char *, int); +static void listsetvar(struct strlist *, int); +static char *lookupvar(const char *); +static char *bltinlookup(const char *); +static char **listvars(int, int, char ***); +#define environment() listvars(VEXPORT, VUNSET, 0) +static int showvars(const char *, int, int); +static void poplocalvars(void); +static int unsetvar(const char *); +#ifdef BB_ASH_GETOPTS +static int setvarsafe(const char *, const char *, int); +#endif +static int varcmp(const char *, const char *); +static struct var **hashvar(const char *); + + +static inline int varequal(const char *a, const char *b) { + return !varcmp(a, b); +} + + +static int loopnest; /* current loop nesting level */ + +/* + * The parsefile structure pointed to by the global variable parsefile + * contains information about the current file being read. + */ + + +struct redirtab { + struct redirtab *next; + int renamed[10]; + int nullredirs; +}; + +static struct redirtab *redirlist; +static int nullredirs; + +extern char **environ; + +/* $NetBSD: output.h,v 1.16 2002/11/24 22:35:42 christos Exp $ */ + + +static void outstr(const char *, FILE *); +static void outcslow(int, FILE *); +static void flushall(void); +static void flushout(FILE *); +static int out1fmt(const char *, ...) + __attribute__((__format__(__printf__,1,2))); +static int fmtstr(char *, size_t, const char *, ...) + __attribute__((__format__(__printf__,3,4))); +static void xwrite(int, const void *, size_t); + +static int preverrout_fd; /* save fd2 before print debug if xflag is set. */ + + +static void out1str(const char *p) +{ + outstr(p, stdout); +} + +static void out2str(const char *p) +{ + outstr(p, stderr); + flushout(stderr); +} + +/* + * Initialization code. + */ + +/* + * This routine initializes the builtin variables. + */ + +static inline void +initvar(void) +{ + struct var *vp; + struct var *end; + struct var **vpp; + + /* + * PS1 depends on uid + */ +#if defined(BB_FEATURE_COMMAND_EDITING) && defined(BB_FEATURE_SH_FANCY_PROMPT) + vps1.text = "PS1=\\w \\$ "; +#else + if (!geteuid()) + vps1.text = "PS1=# "; +#endif + vp = varinit; + end = vp + sizeof(varinit) / sizeof(varinit[0]); + do { + vpp = hashvar(vp->text); + vp->next = *vpp; + *vpp = vp; + } while (++vp < end); +} + +static inline void +init(void) +{ + + /* from input.c: */ + { + basepf.nextc = basepf.buf = basebuf; + } + + /* from trap.c: */ + { + signal(SIGCHLD, SIG_DFL); + } + + /* from var.c: */ + { + char **envp; + char ppid[32]; + + initvar(); + for (envp = environ ; *envp ; envp++) { + if (strchr(*envp, '=')) { + setvareq(*envp, VEXPORT|VTEXTFIXED); + } + } + + snprintf(ppid, sizeof(ppid), "%d", (int) getppid()); + setvar("PPID", ppid, 0); + setpwd(0, 0); + } +} + +/* PEOF (the end of file marker) */ + +/* + * The input line number. Input.c just defines this variable, and saves + * and restores it when files are pushed and popped. The user of this + * package must set its value. + */ + +static int pgetc(void); +static int pgetc2(void); +static int preadbuffer(void); +static void pungetc(void); +static void pushstring(char *, void *); +static void popstring(void); +static void setinputfile(const char *, int); +static void setinputfd(int, int); +static void setinputstring(char *); +static void popfile(void); +static void popallfiles(void); +static void closescript(void); + + +/* $NetBSD: jobs.h,v 1.17 2003/01/22 20:36:04 dsl Exp $ */ + + +/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ +#define FORK_FG 0 +#define FORK_BG 1 +#define FORK_NOJOB 2 + +/* mode flags for showjob(s) */ +#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */ +#define SHOW_PID 0x04 /* include process pid */ +#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */ + + +/* + * A job structure contains information about a job. A job is either a + * single process or a set of processes contained in a pipeline. In the + * latter case, pidlist will be non-NULL, and will point to a -1 terminated + * array of pids. + */ + +struct procstat { + pid_t pid; /* process id */ + int status; /* last process status from wait() */ + char *cmd; /* text of command being run */ +}; + +struct job { + struct procstat ps0; /* status of process */ + struct procstat *ps; /* status or processes when more than one */ +#if JOBS + int stopstatus; /* status of a stopped job */ +#endif + uint32_t + nprocs: 16, /* number of processes */ + state: 8, +#define JOBRUNNING 0 /* at least one proc running */ +#define JOBSTOPPED 1 /* all procs are stopped */ +#define JOBDONE 2 /* all procs are completed */ +#if JOBS + sigint: 1, /* job was killed by SIGINT */ + jobctl: 1, /* job running under job control */ +#endif + waited: 1, /* true if this entry has been waited for */ + used: 1, /* true if this entry is in used */ + changed: 1; /* true if status has changed */ + struct job *prev_job; /* previous job */ +}; + +static pid_t backgndpid; /* pid of last background process */ +static int job_warning; /* user was warned about stopped jobs */ +#if JOBS +static int jobctl; /* true if doing job control */ +#endif + +static struct job *makejob(union node *, int); +static int forkshell(struct job *, union node *, int); +static int waitforjob(struct job *); +static int stoppedjobs(void); + +#if ! JOBS +#define setjobctl(on) /* do nothing */ +#else +static void setjobctl(int); +static void showjobs(FILE *, int); +#endif + +/* $NetBSD: main.h,v 1.9 2002/11/24 22:35:41 christos Exp $ */ + + +/* pid of main shell */ +static int rootpid; +/* true if we aren't a child of the main shell */ +static int rootshell; + +static void readcmdfile(char *); +static void cmdloop(int); + +/* $NetBSD: memalloc.h,v 1.13 2003/01/22 20:36:04 dsl Exp $ */ + + +struct stackmark { + struct stack_block *stackp; + char *stacknxt; + size_t stacknleft; + struct stackmark *marknext; +}; + +/* minimum size of a block */ +#define MINSIZE SHELL_ALIGN(504) + +struct stack_block { + struct stack_block *prev; + char space[MINSIZE]; +}; + +static struct stack_block stackbase; +static struct stack_block *stackp = &stackbase; +static struct stackmark *markp; +static char *stacknxt = stackbase.space; +static size_t stacknleft = MINSIZE; +static char *sstrend = stackbase.space + MINSIZE; +static int herefd = -1; + + +static pointer ckmalloc(size_t); +static pointer ckrealloc(pointer, size_t); +static char *savestr(const char *); +static pointer stalloc(size_t); +static void stunalloc(pointer); +static void setstackmark(struct stackmark *); +static void popstackmark(struct stackmark *); +static void growstackblock(void); +static void *growstackstr(void); +static char *makestrspace(size_t, char *); +static char *stnputs(const char *, size_t, char *); +static char *stputs(const char *, char *); + + +static inline char *_STPUTC(char c, char *p) { + if (p == sstrend) + p = growstackstr(); + *p++ = c; + return p; +} + +#define stackblock() ((void *)stacknxt) +#define stackblocksize() stacknleft +#define STARTSTACKSTR(p) ((p) = stackblock()) +#define STPUTC(c, p) ((p) = _STPUTC((c), (p))) +#define CHECKSTRSPACE(n, p) \ + ({ \ + char *q = (p); \ + size_t l = (n); \ + size_t m = sstrend - q; \ + if (l > m) \ + (p) = makestrspace(l, q); \ + 0; \ + }) +#define USTPUTC(c, p) (*p++ = (c)) +#define STACKSTRNUL(p) ((p) == sstrend? (p = growstackstr(), *p = '\0') : (*p = '\0')) +#define STUNPUTC(p) (--p) +#define STTOPC(p) p[-1] +#define STADJUST(amount, p) (p += (amount)) + +#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock()) +#define ungrabstackstr(s, p) stunalloc((s)) +#define stackstrend() ((void *)sstrend) + +#define ckfree(p) free((pointer)(p)) + +/* $NetBSD: mystring.h,v 1.10 2002/11/24 22:35:42 christos Exp $ */ + + +#define DOLATSTRLEN 4 + +static char *prefix(const char *, const char *); +static int number(const char *); +static int is_number(const char *); +static char *single_quote(const char *); +static char *sstrdup(const char *); + +#define equal(s1, s2) (strcmp(s1, s2) == 0) +#define scopy(s1, s2) ((void)strcpy(s2, s1)) + +/* $NetBSD: options.h,v 1.16 2003/01/22 20:36:04 dsl Exp $ */ + +struct shparam { + int nparam; /* # of positional parameters (without $0) */ + unsigned char malloc; /* if parameter list dynamically allocated */ + char **p; /* parameter list */ +#ifdef BB_ASH_GETOPTS + int optind; /* next parameter to be processed by getopts */ + int optoff; /* used by getopts */ +#endif +}; + + +#define eflag optlist[0] +#define fflag optlist[1] +#define Iflag optlist[2] +#define iflag optlist[3] +#define mflag optlist[4] +#define nflag optlist[5] +#define sflag optlist[6] +#define xflag optlist[7] +#define vflag optlist[8] +#define Cflag optlist[9] +#define aflag optlist[10] +#define bflag optlist[11] +#define uflag optlist[12] +#define qflag optlist[13] + +#ifdef DEBUG +#define nolog optlist[14] +#define debug optlist[15] +#define NOPTS 16 +#else +#define NOPTS 14 +#endif + +/* $NetBSD: options.c,v 1.33 2003/01/22 20:36:04 dsl Exp $ */ + + +static const char *const optletters_optnames[NOPTS] = { + "e" "errexit", + "f" "noglob", + "I" "ignoreeof", + "i" "interactive", + "m" "monitor", + "n" "noexec", + "s" "stdin", + "x" "xtrace", + "v" "verbose", + "C" "noclobber", + "a" "allexport", + "b" "notify", + "u" "nounset", + "q" "quietprofile", +#ifdef DEBUG + "\0" "nolog", + "\0" "debug", +#endif +}; + +#define optletters(n) optletters_optnames[(n)][0] +#define optnames(n) (&optletters_optnames[(n)][1]) + + +static char optlist[NOPTS]; + + +static char *arg0; /* value of $0 */ +static struct shparam shellparam; /* $@ current positional parameters */ +static char **argptr; /* argument list for builtin commands */ +static char *optionarg; /* set by nextopt (like getopt) */ +static char *optptr; /* used by nextopt */ + +static char *minusc; /* argument to -c option */ + + +static void procargs(int, char **); +static void optschanged(void); +static void setparam(char **); +static void freeparam(volatile struct shparam *); +static int shiftcmd(int, char **); +static int setcmd(int, char **); +static int nextopt(const char *); + +/* $NetBSD: redir.h,v 1.14 2002/11/24 22:35:43 christos Exp $ */ + +/* flags passed to redirect */ +#define REDIR_PUSH 01 /* save previous values of file descriptors */ +#define REDIR_SAVEFD2 03 /* set preverrout */ + +union node; +static void redirect(union node *, int); +static void popredir(int); +static void clearredir(int); +static int ash_copyfd(int, int); +static int redirectsafe(union node *, int); + +/* $NetBSD: show.h,v 1.6 2003/01/22 20:36:04 dsl Exp $ */ + + +#ifdef DEBUG +static void showtree(union node *); +static void trace(const char *, ...); +static void tracev(const char *, va_list); +static void trargs(char **); +static void trputc(int); +static void trputs(const char *); +static void opentrace(void); +#endif + +/* $NetBSD: trap.h,v 1.16 2002/11/24 22:35:43 christos Exp $ */ + + +/* trap handler commands */ +static char *trap[NSIG]; +/* current value of signal */ +static char sigmode[NSIG - 1]; +/* indicates specified signal received */ +static char gotsig[NSIG - 1]; + +static void clear_traps(void); +static void setsignal(int); +static void ignoresig(int); +static void onsig(int); +static void dotrap(void); +static void setinteractive(int); +static void exitshell(void) __attribute__((__noreturn__)); +static int decode_signal(const char *, int); + +/* + * This routine is called when an error or an interrupt occurs in an + * interactive shell and control is returned to the main command loop. + */ + +static void +reset(void) +{ + /* from eval.c: */ + { + evalskip = 0; + loopnest = 0; + funcnest = 0; + } + + /* from input.c: */ + { + parselleft = parsenleft = 0; /* clear input buffer */ + popallfiles(); + } + + /* from parser.c: */ + { + tokpushback = 0; + checkkwd = 0; + } + + /* from redir.c: */ + { + clearredir(0); + } + +} + +#ifdef BB_ASH_ALIAS +static struct alias *atab[ATABSIZE]; + +static void setalias(const char *, const char *); +static struct alias *freealias(struct alias *); +static struct alias **__lookupalias(const char *); + +static void +setalias(const char *name, const char *val) +{ + struct alias *ap, **app; + + app = __lookupalias(name); + ap = *app; + INTOFF; + if (ap) { + if (!(ap->flag & ALIASINUSE)) { + ckfree(ap->val); + } + ap->val = savestr(val); + ap->flag &= ~ALIASDEAD; + } else { + /* not found */ + ap = ckmalloc(sizeof (struct alias)); + ap->name = savestr(name); + ap->val = savestr(val); + ap->flag = 0; + ap->next = 0; + *app = ap; + } + INTON; +} + +static int +unalias(const char *name) +{ + struct alias **app; + + app = __lookupalias(name); + + if (*app) { + INTOFF; + *app = freealias(*app); + INTON; + return (0); + } + + return (1); +} + +static void +rmaliases(void) +{ + struct alias *ap, **app; + int i; + + INTOFF; + for (i = 0; i < ATABSIZE; i++) { + app = &atab[i]; + for (ap = *app; ap; ap = *app) { + *app = freealias(*app); + if (ap == *app) { + app = &ap->next; + } + } + } + INTON; +} + +static struct alias * +lookupalias(const char *name, int check) +{ + struct alias *ap = *__lookupalias(name); + + if (check && ap && (ap->flag & ALIASINUSE)) + return (NULL); + return (ap); +} + +/* + * TODO - sort output + */ +static int +aliascmd(int argc, char **argv) +{ + char *n, *v; + int ret = 0; + struct alias *ap; + + if (argc == 1) { + int i; + + for (i = 0; i < ATABSIZE; i++) + for (ap = atab[i]; ap; ap = ap->next) { + printalias(ap); + } + return (0); + } + while ((n = *++argv) != NULL) { + if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */ + if ((ap = *__lookupalias(n)) == NULL) { + fprintf(stderr, "%s: %s not found\n", "alias", n); + ret = 1; + } else + printalias(ap); + } else { + *v++ = '\0'; + setalias(n, v); + } + } + + return (ret); +} + +static int +unaliascmd(int argc, char **argv) +{ + int i; + + while ((i = nextopt("a")) != '\0') { + if (i == 'a') { + rmaliases(); + return (0); + } + } + for (i = 0; *argptr; argptr++) { + if (unalias(*argptr)) { + fprintf(stderr, "%s: %s not found\n", "unalias", *argptr); + i = 1; + } + } + + return (i); +} + +static struct alias * +freealias(struct alias *ap) { + struct alias *next; + + if (ap->flag & ALIASINUSE) { + ap->flag |= ALIASDEAD; + return ap; + } + + next = ap->next; + ckfree(ap->name); + ckfree(ap->val); + ckfree(ap); + return next; +} + +static void +printalias(const struct alias *ap) { + out1fmt("%s=%s\n", ap->name, single_quote(ap->val)); +} + +static struct alias ** +__lookupalias(const char *name) { + unsigned int hashval; + struct alias **app; + const char *p; + unsigned int ch; + + p = name; + + ch = (unsigned char)*p; + hashval = ch << 4; + while (ch) { + hashval += ch; + ch = (unsigned char)*++p; + } + app = &atab[hashval % ATABSIZE]; + + for (; *app; app = &(*app)->next) { + if (equal(name, (*app)->name)) { + break; + } + } + + return app; +} +#endif /* BB_ASH_ALIAS */ + + +/* $NetBSD: cd.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */ + +/* + * The cd and pwd commands. + */ + +#define CD_PHYSICAL 1 +#define CD_PRINT 2 + +static int docd(const char *, int); +static int cdopt(void); + +static char *curdir = nullstr; /* current working directory */ +static char *physdir = nullstr; /* physical working directory */ + +static int +cdopt(void) +{ + int flags = 0; + int i, j; + + j = 'L'; + while ((i = nextopt("LP"))) { + if (i != j) { + flags ^= CD_PHYSICAL; + j = i; + } + } + + return flags; +} + +static int +cdcmd(int argc, char **argv) +{ + const char *dest; + const char *path; + const char *p; + char c; + struct stat statb; + int flags; + + flags = cdopt(); + dest = *argptr; + if (!dest) + dest = bltinlookup(homestr); + else if (dest[0] == '-' && dest[1] == '\0') { + dest = bltinlookup("OLDPWD"); + flags |= CD_PRINT; + goto step7; + } + if (!dest) + dest = nullstr; + if (*dest == '/') + goto step7; + if (*dest == '.') { + c = dest[1]; +dotdot: + switch (c) { + case '\0': + case '/': + goto step6; + case '.': + c = dest[2]; + if (c != '.') + goto dotdot; + } + } + if (!*dest) + dest = "."; + if (!(path = bltinlookup("CDPATH"))) { +step6: +step7: + p = dest; + goto docd; + } + do { + c = *path; + p = padvance(&path, dest); + if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { + if (c && c != ':') + flags |= CD_PRINT; +docd: + if (!docd(p, flags)) + goto out; + break; + } + } while (path); + error("can't cd to %s", dest); + /* NOTREACHED */ +out: + if (flags & CD_PRINT) + out1fmt(snlfmt, curdir); + return 0; +} + + +/* + * Update curdir (the name of the current directory) in response to a + * cd command. + */ + +static inline const char * +updatepwd(const char *dir) +{ + char *new; + char *p; + char *cdcomppath; + const char *lim; + + cdcomppath = sstrdup(dir); + STARTSTACKSTR(new); + if (*dir != '/') { + if (curdir == nullstr) + return 0; + new = stputs(curdir, new); + } + new = makestrspace(strlen(dir) + 2, new); + lim = stackblock() + 1; + if (*dir != '/') { + if (new[-1] != '/') + USTPUTC('/', new); + if (new > lim && *lim == '/') + lim++; + } else { + USTPUTC('/', new); + cdcomppath++; + if (dir[1] == '/' && dir[2] != '/') { + USTPUTC('/', new); + cdcomppath++; + lim++; + } + } + p = strtok(cdcomppath, "/"); + while (p) { + switch(*p) { + case '.': + if (p[1] == '.' && p[2] == '\0') { + while (new > lim) { + STUNPUTC(new); + if (new[-1] == '/') + break; + } + break; + } else if (p[1] == '\0') + break; + /* fall through */ + default: + new = stputs(p, new); + USTPUTC('/', new); + } + p = strtok(0, "/"); + } + if (new > lim) + STUNPUTC(new); + *new = 0; + return stackblock(); +} + +/* + * Actually do the chdir. We also call hashcd to let the routines in exec.c + * know that the current directory has changed. + */ + +static int +docd(const char *dest, int flags) +{ + const char *dir = 0; + int err; + + TRACE(("docd(\"%s\", %d) called\n", dest, flags)); + + INTOFF; + if (!(flags & CD_PHYSICAL)) { + dir = updatepwd(dest); + if (dir) + dest = dir; + } + err = chdir(dest); + if (err) + goto out; + setpwd(dir, 1); + hashcd(); +out: + INTON; + return err; +} + +/* + * Find out what the current directory is. If we already know the current + * directory, this routine returns immediately. + */ +static inline char * +getpwd(void) +{ + char *dir = getcwd(0, 0); + return dir ? dir : nullstr; +} + +static int +pwdcmd(int argc, char **argv) +{ + int flags; + const char *dir = curdir; + + flags = cdopt(); + if (flags) { + if (physdir == nullstr) + setpwd(dir, 0); + dir = physdir; + } + out1fmt(snlfmt, dir); + return 0; +} + +static void +setpwd(const char *val, int setold) +{ + char *oldcur, *dir; + + oldcur = dir = curdir; + + if (setold) { + setvar("OLDPWD", oldcur, VEXPORT); + } + INTOFF; + if (physdir != nullstr) { + if (physdir != oldcur) + free(physdir); + physdir = nullstr; + } + if (oldcur == val || !val) { + char *s = getpwd(); + physdir = s; + if (!val) + dir = s; + } else + dir = savestr(val); + if (oldcur != dir && oldcur != nullstr) { + free(oldcur); + } + curdir = dir; + INTON; + setvar("PWD", dir, VEXPORT); +} + +/* $NetBSD: error.c,v 1.30 2003/01/22 20:36:03 dsl Exp $ */ + +/* + * Errors and exceptions. + */ + +/* + * Code to handle exceptions in C. + */ + + + +static void exverror(int, const char *, va_list) + __attribute__((__noreturn__)); + +/* + * Called to raise an exception. Since C doesn't include exceptions, we + * just do a longjmp to the exception handler. The type of exception is + * stored in the global variable "exception". + */ + +static void +exraise(int e) +{ +#ifdef DEBUG + if (handler == NULL) + abort(); +#endif + INTOFF; + + exception = e; + longjmp(handler->loc, 1); +} + + +/* + * Called from trap.c when a SIGINT is received. (If the user specifies + * that SIGINT is to be trapped or ignored using the trap builtin, then + * this routine is not called.) Suppressint is nonzero when interrupts + * are held using the INTOFF macro. (The test for iflag is just + * defensive programming.) + */ + +static void +onint(void) { + int i; + + intpending = 0; + sigsetmask(0); + i = EXSIG; + if (gotsig[SIGINT - 1] && !trap[SIGINT]) { + if (!(rootshell && iflag)) { + signal(SIGINT, SIG_DFL); + raise(SIGINT); + } + i = EXINT; + } + exraise(i); + /* NOTREACHED */ +} + +static void +exvwarning(const char *msg, va_list ap) +{ + FILE *errs; + const char *name; + const char *fmt; + + errs = stderr; + name = arg0; + fmt = "%s: "; + if (commandname) { + name = commandname; + fmt = "%s: %d: "; + } + fprintf(errs, fmt, name, startlinno); + vfprintf(errs, msg, ap); + outcslow('\n', errs); +} + +/* + * Exverror is called to raise the error exception. If the second argument + * is not NULL then error prints an error message using printf style + * formatting. It then raises the error exception. + */ +static void +exverror(int cond, const char *msg, va_list ap) +{ +#ifdef DEBUG + if (msg) { + TRACE(("exverror(%d, \"", cond)); + TRACEV((msg, ap)); + TRACE(("\") pid=%d\n", getpid())); + } else + TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid())); + if (msg) +#endif + exvwarning(msg, ap); + + flushall(); + exraise(cond); + /* NOTREACHED */ +} + + +static void +error(const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + exverror(EXERROR, msg, ap); + /* NOTREACHED */ + va_end(ap); +} + + +static void +exerror(int cond, const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + exverror(cond, msg, ap); + /* NOTREACHED */ + va_end(ap); +} + +/* + * error/warning routines for external builtins + */ + +static void +sh_warnx(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + exvwarning(fmt, ap); + va_end(ap); +} + + +/* + * Return a string describing an error. The returned string may be a + * pointer to a static buffer that will be overwritten on the next call. + * Action describes the operation that got the error. + */ + +static const char * +errmsg(int e, const char *em) +{ + if(e == ENOENT || e == ENOTDIR) { + + return em; + } + return strerror(e); +} + + +/* $NetBSD: eval.c,v 1.71 2003/01/23 03:33:16 rafal Exp $ */ + +/* + * Evaluate a command. + */ + +/* flags in argument to evaltree */ +#define EV_EXIT 01 /* exit after evaluating tree */ +#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ +#define EV_BACKCMD 04 /* command executing within back quotes */ + + +static void evalloop(union node *, int); +static void evalfor(union node *, int); +static void evalcase(union node *, int); +static void evalsubshell(union node *, int); +static void expredir(union node *); +static void evalpipe(union node *, int); +static void evalcommand(union node *, int); +static int evalbltin(const struct builtincmd *, int, char **); +static int evalfun(struct funcnode *, int, char **, int); +static void prehash(union node *); +static int bltincmd(int, char **); + + +static const struct builtincmd bltin = { + "\0\0", bltincmd +}; + + +/* + * Called to reset things after an exception. + */ + +/* + * The eval commmand. + */ + +static int +evalcmd(int argc, char **argv) +{ + char *p; + char *concat; + char **ap; + + if (argc > 1) { + p = argv[1]; + if (argc > 2) { + STARTSTACKSTR(concat); + ap = argv + 2; + for (;;) { + concat = stputs(p, concat); + if ((p = *ap++) == NULL) + break; + STPUTC(' ', concat); + } + STPUTC('\0', concat); + p = grabstackstr(concat); + } + evalstring(p, EV_TESTED); + } + return exitstatus; +} + + +/* + * Execute a command or commands contained in a string. + */ + +static void +evalstring(char *s, int flag) +{ + union node *n; + struct stackmark smark; + + setstackmark(&smark); + setinputstring(s); + + while ((n = parsecmd(0)) != NEOF) { + evaltree(n, flag); + popstackmark(&smark); + if (evalskip) + break; + } + popfile(); + popstackmark(&smark); +} + + + +/* + * Evaluate a parse tree. The value is left in the global variable + * exitstatus. + */ + +static void +evaltree(union node *n, int flags) +{ + int checkexit = 0; + void (*evalfn)(union node *, int); + unsigned isor; + int status; + if (n == NULL) { + TRACE(("evaltree(NULL) called\n")); + goto out; + } + TRACE(("pid %d, evaltree(%p: %d, %d) called\n", + getpid(), n, n->type, flags)); + switch (n->type) { + default: +#ifdef DEBUG + out1fmt("Node type = %d\n", n->type); + fflush(stdout); + break; +#endif + case NNOT: + evaltree(n->nnot.com, EV_TESTED); + status = !exitstatus; + goto setstatus; + case NREDIR: + expredir(n->nredir.redirect); + status = redirectsafe(n->nredir.redirect, REDIR_PUSH); + if (!status) { + evaltree(n->nredir.n, flags & EV_TESTED); + status = exitstatus; + } + popredir(0); + goto setstatus; + case NCMD: + evalfn = evalcommand; +checkexit: + if (eflag && !(flags & EV_TESTED)) + checkexit = ~0; + goto calleval; + case NFOR: + evalfn = evalfor; + goto calleval; + case NWHILE: + case NUNTIL: + evalfn = evalloop; + goto calleval; + case NSUBSHELL: + case NBACKGND: + evalfn = evalsubshell; + goto calleval; + case NPIPE: + evalfn = evalpipe; + goto checkexit; + case NCASE: + evalfn = evalcase; + goto calleval; + case NAND: + case NOR: + case NSEMI: +#if NAND + 1 != NOR +#error NAND + 1 != NOR +#endif +#if NOR + 1 != NSEMI +#error NOR + 1 != NSEMI +#endif + isor = n->type - NAND; + evaltree( + n->nbinary.ch1, + (flags | ((isor >> 1) - 1)) & EV_TESTED + ); + if (!exitstatus == isor) + break; + if (!evalskip) { + n = n->nbinary.ch2; +evaln: + evalfn = evaltree; +calleval: + evalfn(n, flags); + break; + } + break; + case NIF: + evaltree(n->nif.test, EV_TESTED); + if (evalskip) + break; + if (exitstatus == 0) { + n = n->nif.ifpart; + goto evaln; + } else if (n->nif.elsepart) { + n = n->nif.elsepart; + goto evaln; + } + goto success; + case NDEFUN: + defun(n->narg.text, n->narg.next); +success: + status = 0; +setstatus: + exitstatus = status; + break; + } +out: + if (pendingsigs) + dotrap(); + if (flags & EV_EXIT || checkexit & exitstatus) + exraise(EXEXIT); +} + + +#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3) +static +#endif +void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__)); + + +static void +evalloop(union node *n, int flags) +{ + int status; + + loopnest++; + status = 0; + flags &= EV_TESTED; + for (;;) { + int i; + + evaltree(n->nbinary.ch1, EV_TESTED); + if (evalskip) { +skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { + evalskip = 0; + continue; + } + if (evalskip == SKIPBREAK && --skipcount <= 0) + evalskip = 0; + break; + } + i = exitstatus; + if (n->type != NWHILE) + i = !i; + if (i != 0) + break; + evaltree(n->nbinary.ch2, flags); + status = exitstatus; + if (evalskip) + goto skipping; + } + loopnest--; + exitstatus = status; +} + + + +static void +evalfor(union node *n, int flags) +{ + struct arglist arglist; + union node *argp; + struct strlist *sp; + struct stackmark smark; + + setstackmark(&smark); + arglist.lastp = &arglist.list; + for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { + expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); + /* XXX */ + if (evalskip) + goto out; + } + *arglist.lastp = NULL; + + exitstatus = 0; + loopnest++; + flags &= EV_TESTED; + for (sp = arglist.list ; sp ; sp = sp->next) { + setvar(n->nfor.var, sp->text, 0); + evaltree(n->nfor.body, flags); + if (evalskip) { + if (evalskip == SKIPCONT && --skipcount <= 0) { + evalskip = 0; + continue; + } + if (evalskip == SKIPBREAK && --skipcount <= 0) + evalskip = 0; + break; + } + } + loopnest--; +out: + popstackmark(&smark); +} + + + +static void +evalcase(union node *n, int flags) +{ + union node *cp; + union node *patp; + struct arglist arglist; + struct stackmark smark; + + setstackmark(&smark); + arglist.lastp = &arglist.list; + expandarg(n->ncase.expr, &arglist, EXP_TILDE); + exitstatus = 0; + for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { + for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { + if (casematch(patp, arglist.list->text)) { + if (evalskip == 0) { + evaltree(cp->nclist.body, flags); + } + goto out; + } + } + } +out: + popstackmark(&smark); +} + + + +/* + * Kick off a subshell to evaluate a tree. + */ + +static void +evalsubshell(union node *n, int flags) +{ + struct job *jp; + int backgnd = (n->type == NBACKGND); + int status; + + expredir(n->nredir.redirect); + if (!backgnd && flags & EV_EXIT && !trap[0]) + goto nofork; + INTOFF; + jp = makejob(n, 1); + if (forkshell(jp, n, backgnd) == 0) { + INTON; + flags |= EV_EXIT; + if (backgnd) + flags &=~ EV_TESTED; +nofork: + redirect(n->nredir.redirect, 0); + evaltreenr(n->nredir.n, flags); + /* never returns */ + } + status = 0; + if (! backgnd) + status = waitforjob(jp); + exitstatus = status; + INTON; +} + + + +/* + * Compute the names of the files in a redirection list. + */ + +static void +expredir(union node *n) +{ + union node *redir; + + for (redir = n ; redir ; redir = redir->nfile.next) { + struct arglist fn; + fn.lastp = &fn.list; + switch (redir->type) { + case NFROMTO: + case NFROM: + case NTO: + case NCLOBBER: + case NAPPEND: + expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); + redir->nfile.expfname = fn.list->text; + break; + case NFROMFD: + case NTOFD: + if (redir->ndup.vname) { + expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); + fixredir(redir, fn.list->text, 1); + } + break; + } + } +} + + + +/* + * Evaluate a pipeline. All the processes in the pipeline are children + * of the process creating the pipeline. (This differs from some versions + * of the shell, which make the last process in a pipeline the parent + * of all the rest.) + */ + +static void +evalpipe(union node *n, int flags) +{ + struct job *jp; + struct nodelist *lp; + int pipelen; + int prevfd; + int pip[2]; + + TRACE(("evalpipe(0x%lx) called\n", (long)n)); + pipelen = 0; + for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) + pipelen++; + flags |= EV_EXIT; + INTOFF; + jp = makejob(n, pipelen); + prevfd = -1; + for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { + prehash(lp->n); + pip[1] = -1; + if (lp->next) { + if (pipe(pip) < 0) { + close(prevfd); + error("Pipe call failed"); + } + } + if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { + INTON; + if (pip[1] >= 0) { + close(pip[0]); + } + if (prevfd > 0) { + dup2(prevfd, 0); + close(prevfd); + } + if (pip[1] > 1) { + dup2(pip[1], 1); + close(pip[1]); + } + evaltreenr(lp->n, flags); + /* never returns */ + } + if (prevfd >= 0) + close(prevfd); + prevfd = pip[0]; + close(pip[1]); + } + if (n->npipe.backgnd == 0) { + exitstatus = waitforjob(jp); + TRACE(("evalpipe: job done exit status %d\n", exitstatus)); + } + INTON; +} + + + +/* + * Execute a command inside back quotes. If it's a builtin command, we + * want to save its output in a block obtained from malloc. Otherwise + * we fork off a subprocess and get the output of the command via a pipe. + * Should be called with interrupts off. + */ + +static void +evalbackcmd(union node *n, struct backcmd *result) +{ + int saveherefd; + + result->fd = -1; + result->buf = NULL; + result->nleft = 0; + result->jp = NULL; + if (n == NULL) { + goto out; + } + + saveherefd = herefd; + herefd = -1; + + { + int pip[2]; + struct job *jp; + + if (pipe(pip) < 0) + error("Pipe call failed"); + jp = makejob(n, 1); + if (forkshell(jp, n, FORK_NOJOB) == 0) { + FORCEINTON; + close(pip[0]); + if (pip[1] != 1) { + close(1); + ash_copyfd(pip[1], 1); + close(pip[1]); + } + eflag = 0; + evaltreenr(n, EV_EXIT); + /* NOTREACHED */ + } + close(pip[1]); + result->fd = pip[0]; + result->jp = jp; + } + herefd = saveherefd; +out: + TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", + result->fd, result->buf, result->nleft, result->jp)); +} + +#ifdef BB_ASH_CMDCMD +static inline char ** +parse_command_args(char **argv, const char **path) +{ + char *cp, c; + + for (;;) { + cp = *++argv; + if (!cp) + return 0; + if (*cp++ != '-') + break; + if (!(c = *cp++)) + break; + if (c == '-' && !*cp) { + argv++; + break; + } + do { + switch (c) { + case 'p': + *path = defpath; + break; + default: + /* run 'typecmd' for other options */ + return 0; + } + } while ((c = *cp++)); + } + return argv; +} +#endif + + + +/* + * Execute a simple command. + */ + +static void +evalcommand(union node *cmd, int flags) +{ + struct stackmark smark; + union node *argp; + struct arglist arglist; + struct arglist varlist; + char **argv; + int argc; + const struct strlist *sp; + struct cmdentry cmdentry; + struct job *jp; + char *lastarg; + const char *path; + int spclbltin; + int cmd_is_exec; + int status; + char **nargv; + + /* First expand the arguments. */ + TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); + setstackmark(&smark); + back_exitstatus = 0; + + cmdentry.cmdtype = CMDBUILTIN; + cmdentry.u.cmd = &bltin; + varlist.lastp = &varlist.list; + *varlist.lastp = NULL; + arglist.lastp = &arglist.list; + *arglist.lastp = NULL; + + argc = 0; + for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) { + struct strlist **spp; + + spp = arglist.lastp; + expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); + for (sp = *spp; sp; sp = sp->next) + argc++; + } + + argv = nargv = stalloc(sizeof (char *) * (argc + 1)); + for (sp = arglist.list ; sp ; sp = sp->next) { + TRACE(("evalcommand arg: %s\n", sp->text)); + *nargv++ = sp->text; + } + *nargv = NULL; + + lastarg = NULL; + if (iflag && funcnest == 0 && argc > 0) + lastarg = nargv[-1]; + + preverrout_fd = 2; + expredir(cmd->ncmd.redirect); + status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH|REDIR_SAVEFD2); + + path = vpath.text; + for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { + struct strlist **spp; + char *p; + + spp = varlist.lastp; + expandarg(argp, &varlist, EXP_VARTILDE); + + /* + * Modify the command lookup path, if a PATH= assignment + * is present + */ + p = (*spp)->text; + if (varequal(p, path)) + path = p; + } + + /* Print the command if xflag is set. */ + if (xflag) { + int n; + const char *p = " %s"; + + p++; + dprintf(preverrout_fd, p, ps4val()); + + sp = varlist.list; + for(n = 0; n < 2; n++) { + while (sp) { + dprintf(preverrout_fd, p, sp->text); + sp = sp->next; + if(*p == '%') { + p--; + } + } + sp = arglist.list; + } + xwrite(preverrout_fd, "\n", 1); + } + + cmd_is_exec = 0; + spclbltin = -1; + + /* Now locate the command. */ + if (argc) { + const char *oldpath; + int cmd_flag = DO_ERR; + + path += 5; + oldpath = path; + for (;;) { + find_command(argv[0], &cmdentry, cmd_flag, path); + if (cmdentry.cmdtype == CMDUNKNOWN) { + status = 127; + flushout(stderr); + goto bail; + } + + /* implement bltin and command here */ + if (cmdentry.cmdtype != CMDBUILTIN) + break; + if (spclbltin < 0) + spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd); + if (cmdentry.u.cmd == EXECCMD) + cmd_is_exec++; +#ifdef BB_ASH_CMDCMD + if (cmdentry.u.cmd == COMMANDCMD) { + + path = oldpath; + nargv = parse_command_args(argv, &path); + if (!nargv) + break; + argc -= nargv - argv; + argv = nargv; + cmd_flag |= DO_NOFUNC; + } else +#endif + break; + } + } + + if (status) { + /* We have a redirection error. */ + if (spclbltin > 0) + exraise(EXERROR); +bail: + exitstatus = status; + goto out; + } + + /* Execute the command. */ + switch (cmdentry.cmdtype) { + default: + /* Fork off a child process if necessary. */ + if (!(flags & EV_EXIT) || trap[0]) { + INTOFF; + jp = makejob(cmd, 1); + if (forkshell(jp, cmd, FORK_FG) != 0) { + exitstatus = waitforjob(jp); + INTON; + break; + } + FORCEINTON; + } + listsetvar(varlist.list, VEXPORT|VSTACK); + shellexec(argv, path, cmdentry.u.index); + /* NOTREACHED */ + + case CMDBUILTIN: + cmdenviron = varlist.list; + if (cmdenviron) { + struct strlist *list = cmdenviron; + int i = VNOSET; + if (spclbltin > 0 || argc == 0) { + i = 0; + if (cmd_is_exec && argc > 1) + i = VEXPORT; + } + listsetvar(list, i); + } + if (evalbltin(cmdentry.u.cmd, argc, argv)) { + int exit_status; + int i, j; + + i = exception; + if (i == EXEXIT) + goto raise; + + exit_status = 2; + j = 0; + if (i == EXINT) + j = SIGINT; + if (i == EXSIG) + j = pendingsigs; + if (j) + exit_status = j + 128; + exitstatus = exit_status; + + if (i == EXINT || spclbltin > 0) { +raise: + longjmp(handler->loc, 1); + } + FORCEINTON; + } + break; + + case CMDFUNCTION: + listsetvar(varlist.list, 0); + if (evalfun(cmdentry.u.func, argc, argv, flags)) + goto raise; + break; + } + +out: + popredir(cmd_is_exec); + if (lastarg) + /* dsl: I think this is intended to be used to support + * '_' in 'vi' command mode during line editing... + * However I implemented that within libedit itself. + */ + setvar("_", lastarg, 0); + popstackmark(&smark); +} + +static int +evalbltin(const struct builtincmd *cmd, int argc, char **argv) { + char *volatile savecmdname; + struct jmploc *volatile savehandler; + struct jmploc jmploc; + int i; + + savecmdname = commandname; + if ((i = setjmp(jmploc.loc))) + goto cmddone; + savehandler = handler; + handler = &jmploc; + commandname = argv[0]; + argptr = argv + 1; + optptr = NULL; /* initialize nextopt */ + exitstatus = (*cmd->builtin)(argc, argv); + flushall(); +cmddone: + exitstatus |= ferror(stdout); + commandname = savecmdname; + exsig = 0; + handler = savehandler; + + return i; +} + +static int +evalfun(struct funcnode *func, int argc, char **argv, int flags) +{ + volatile struct shparam saveparam; + struct localvar *volatile savelocalvars; + struct jmploc *volatile savehandler; + struct jmploc jmploc; + int e; + + saveparam = shellparam; + savelocalvars = localvars; + if ((e = setjmp(jmploc.loc))) { + goto funcdone; + } + INTOFF; + savehandler = handler; + handler = &jmploc; + localvars = NULL; + shellparam.malloc = 0; + func->count++; + INTON; + shellparam.nparam = argc - 1; + shellparam.p = argv + 1; +#ifdef BB_ASH_GETOPTS + shellparam.optind = 1; + shellparam.optoff = -1; +#endif + funcnest++; + evaltree(&func->n, flags & EV_TESTED); + funcnest--; +funcdone: + INTOFF; + freefunc(func); + poplocalvars(); + localvars = savelocalvars; + freeparam(&shellparam); + shellparam = saveparam; + handler = savehandler; + INTON; + if (evalskip == SKIPFUNC) { + evalskip = 0; + skipcount = 0; + } + return e; +} + + +/* + * Search for a command. This is called before we fork so that the + * location of the command will be available in the parent as well as + * the child. + */ + +static void +prehash(union node *n) +{ + struct cmdentry entry; + + if (n->type == NCMD && n->ncmd.args) + find_command(n->ncmd.args->narg.text, &entry, 0, pathval()); +} + + + +/* + * Builtin commands. Builtin commands whose functions are closely + * tied to evaluation are implemented here. + */ + +/* + * No command given. + */ + +static int +bltincmd(int argc, char **argv) +{ + /* + * Preserve exitstatus of a previous possible redirection + * as POSIX mandates + */ + return back_exitstatus; +} + + +/* + * Handle break and continue commands. Break, continue, and return are + * all handled by setting the evalskip flag. The evaluation routines + * above all check this flag, and if it is set they start skipping + * commands rather than executing them. The variable skipcount is + * the number of loops to break/continue, or the number of function + * levels to return. (The latter is always 1.) It should probably + * be an error to break out of more loops than exist, but it isn't + * in the standard shell so we don't make it one here. + */ + +static int +breakcmd(int argc, char **argv) +{ + int n = argc > 1 ? number(argv[1]) : 1; + + if (n <= 0) + error(illnum, argv[1]); + if (n > loopnest) + n = loopnest; + if (n > 0) { + evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; + skipcount = n; + } + return 0; +} + + +/* + * The return command. + */ + +static int +returncmd(int argc, char **argv) +{ + int ret = argc > 1 ? number(argv[1]) : exitstatus; + + if (funcnest) { + evalskip = SKIPFUNC; + skipcount = 1; + return ret; + } + else { + /* Do what ksh does; skip the rest of the file */ + evalskip = SKIPFILE; + skipcount = 1; + return ret; + } +} + + +static int +falsecmd(int argc, char **argv) +{ + return 1; +} + + +static int +truecmd(int argc, char **argv) +{ + return 0; +} + + +static int +execcmd(int argc, char **argv) +{ + if (argc > 1) { + iflag = 0; /* exit on error */ + mflag = 0; + optschanged(); + shellexec(argv + 1, pathval(), 0); + } + return 0; +} + + +/* $NetBSD: exec.c,v 1.35 2003/01/22 20:36:04 dsl Exp $ */ + +/* + * When commands are first encountered, they are entered in a hash table. + * This ensures that a full path search will not have to be done for them + * on each invocation. + * + * We should investigate converting to a linear search, even though that + * would make the command name "hash" a misnomer. + */ + +#define CMDTABLESIZE 31 /* should be prime */ +#define ARB 1 /* actual size determined at run time */ + + + +struct tblentry { + struct tblentry *next; /* next entry in hash chain */ + union param param; /* definition of builtin function */ + short cmdtype; /* index identifying command */ + char rehash; /* if set, cd done since entry created */ + char cmdname[ARB]; /* name of command */ +}; + + +static struct tblentry *cmdtable[CMDTABLESIZE]; +static int builtinloc = -1; /* index in path of %builtin, or -1 */ + + +static void tryexec(char *, char **, char **); +static void clearcmdentry(int); +static struct tblentry *cmdlookup(const char *, int); +static void delete_cmd_entry(void); + + +/* + * Exec a program. Never returns. If you change this routine, you may + * have to change the find_command routine as well. + */ + +static void +shellexec(char **argv, const char *path, int idx) +{ + char *cmdname; + int e; + char **envp; + + clearredir(1); + envp = environment(); + if (strchr(argv[0], '/') != NULL +#ifdef BB_FEATURE_SH_STANDALONE_SHELL + || find_applet_by_name(argv[0]) +#endif + ) { + tryexec(argv[0], argv, envp); + e = errno; + } else { + e = ENOENT; + while ((cmdname = padvance(&path, argv[0])) != NULL) { + if (--idx < 0 && pathopt == NULL) { + tryexec(cmdname, argv, envp); + if (errno != ENOENT && errno != ENOTDIR) + e = errno; + } + stunalloc(cmdname); + } + } + + /* Map to POSIX errors */ + switch (e) { + case EACCES: + exerrno = 126; + break; + case ENOENT: + exerrno = 127; + break; + default: + exerrno = 2; + break; + } + TRACE(("shellexec failed for %s, errno %d, suppressint %d\n", + argv[0], e, suppressint )); + exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC)); + /* NOTREACHED */ +} + + +static void +tryexec(char *cmd, char **argv, char **envp) +{ + int repeated = 0; +#ifdef BB_FEATURE_SH_STANDALONE_SHELL + int flg_bb = 0; + char *name = cmd; + +#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN + name = bb_get_last_path_component(name); + if(find_applet_by_name(name) != NULL) + flg_bb = 1; +#else + if(strchr(name, '/') == NULL && find_applet_by_name(name) != NULL) { + flg_bb = 1; + } +#endif + if(flg_bb) { + char **ap; + char **new; + + *argv = name; + if(strcmp(name, "busybox")) { + for (ap = argv; *ap; ap++); + ap = new = xmalloc((ap - argv + 2) * sizeof(char *)); + *ap++ = cmd = "/bin/busybox"; + while ((*ap++ = *argv++)); + argv = new; + repeated++; + } else { + cmd = "/bin/busybox"; + } + } +#endif + +repeat: +#ifdef SYSV + do { + execve(cmd, argv, envp); + } while (errno == EINTR); +#else + execve(cmd, argv, envp); +#endif + if (repeated++) { + ckfree(argv); + } else if (errno == ENOEXEC) { + char **ap; + char **new; + + for (ap = argv; *ap; ap++) + ; + ap = new = ckmalloc((ap - argv + 2) * sizeof(char *)); + ap[1] = cmd; + *ap = cmd = (char *)"/bin/sh"; + ap += 2; + argv++; + while ((*ap++ = *argv++)) + ; + argv = new; + goto repeat; + } +} + + + +/* + * Do a path search. The variable path (passed by reference) should be + * set to the start of the path before the first call; padvance will update + * this value as it proceeds. Successive calls to padvance will return + * the possible path expansions in sequence. If an option (indicated by + * a percent sign) appears in the path entry then the global variable + * pathopt will be set to point to it; otherwise pathopt will be set to + * NULL. + */ + +static char * +padvance(const char **path, const char *name) +{ + const char *p; + char *q; + const char *start; + size_t len; + + if (*path == NULL) + return NULL; + start = *path; + for (p = start ; *p && *p != ':' && *p != '%' ; p++); + len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ + while (stackblocksize() < len) + growstackblock(); + q = stackblock(); + if (p != start) { + memcpy(q, start, p - start); + q += p - start; + *q++ = '/'; + } + strcpy(q, name); + pathopt = NULL; + if (*p == '%') { + pathopt = ++p; + while (*p && *p != ':') p++; + } + if (*p == ':') + *path = p + 1; + else + *path = NULL; + return stalloc(len); +} + + +/*** Command hashing code ***/ + +static void +printentry(struct tblentry *cmdp) +{ + int idx; + const char *path; + char *name; + + idx = cmdp->param.index; + path = pathval(); + do { + name = padvance(&path, cmdp->cmdname); + stunalloc(name); + } while (--idx >= 0); + out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr)); +} + + +static int +hashcmd(int argc, char **argv) +{ + struct tblentry **pp; + struct tblentry *cmdp; + int c; + struct cmdentry entry; + char *name; + + while ((c = nextopt("r")) != '\0') { + clearcmdentry(0); + return 0; + } + if (*argptr == NULL) { + for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { + for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { + if (cmdp->cmdtype == CMDNORMAL) + printentry(cmdp); + } + } + return 0; + } + c = 0; + while ((name = *argptr) != NULL) { + if ((cmdp = cmdlookup(name, 0)) != NULL + && (cmdp->cmdtype == CMDNORMAL + || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) + delete_cmd_entry(); + find_command(name, &entry, DO_ERR, pathval()); + if (entry.cmdtype == CMDUNKNOWN) + c = 1; + argptr++; + } + return c; +} + + +/* + * Resolve a command name. If you change this routine, you may have to + * change the shellexec routine as well. + */ + +static void +find_command(char *name, struct cmdentry *entry, int act, const char *path) +{ + struct tblentry *cmdp; + int idx; + int prev; + char *fullname; + struct stat statb; + int e; + int updatetbl; + struct builtincmd *bcmd; + + /* If name contains a slash, don't use PATH or hash table */ + if (strchr(name, '/') != NULL) { + entry->u.index = -1; + if (act & DO_ABS) { + while (stat(name, &statb) < 0) { +#ifdef SYSV + if (errno == EINTR) + continue; +#endif + entry->cmdtype = CMDUNKNOWN; + return; + } + } + entry->cmdtype = CMDNORMAL; + return; + } + +#ifdef BB_FEATURE_SH_STANDALONE_SHELL + if (find_applet_by_name(name)) { + entry->cmdtype = CMDNORMAL; + entry->u.index = -1; + return; + } +#endif + + updatetbl = (path == pathval()); + if (!updatetbl) { + act |= DO_ALTPATH; + if (strstr(path, "%builtin") != NULL) + act |= DO_ALTBLTIN; + } + + /* If name is in the table, check answer will be ok */ + if ((cmdp = cmdlookup(name, 0)) != NULL) { + int bit; + + switch (cmdp->cmdtype) { + default: +#if DEBUG + abort(); +#endif + case CMDNORMAL: + bit = DO_ALTPATH; + break; + case CMDFUNCTION: + bit = DO_NOFUNC; + break; + case CMDBUILTIN: + bit = DO_ALTBLTIN; + break; + } + if (act & bit) { + updatetbl = 0; + cmdp = NULL; + } else if (cmdp->rehash == 0) + /* if not invalidated by cd, we're done */ + goto success; + } + + /* If %builtin not in path, check for builtin next */ + bcmd = find_builtin(name); + if (bcmd && (IS_BUILTIN_REGULAR(bcmd) || ( + act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc <= 0 + ))) + goto builtin_success; + + /* We have to search path. */ + prev = -1; /* where to start */ + if (cmdp && cmdp->rehash) { /* doing a rehash */ + if (cmdp->cmdtype == CMDBUILTIN) + prev = builtinloc; + else + prev = cmdp->param.index; + } + + e = ENOENT; + idx = -1; +loop: + while ((fullname = padvance(&path, name)) != NULL) { + stunalloc(fullname); + idx++; + if (pathopt) { + if (prefix(pathopt, "builtin")) { + if (bcmd) + goto builtin_success; + continue; + } else if (!(act & DO_NOFUNC) && + prefix(pathopt, "func")) { + /* handled below */ + } else { + /* ignore unimplemented options */ + continue; + } + } + /* if rehash, don't redo absolute path names */ + if (fullname[0] == '/' && idx <= prev) { + if (idx < prev) + continue; + TRACE(("searchexec \"%s\": no change\n", name)); + goto success; + } + while (stat(fullname, &statb) < 0) { +#ifdef SYSV + if (errno == EINTR) + continue; +#endif + if (errno != ENOENT && errno != ENOTDIR) + e = errno; + goto loop; + } + e = EACCES; /* if we fail, this will be the error */ + if (!S_ISREG(statb.st_mode)) + continue; + if (pathopt) { /* this is a %func directory */ + stalloc(strlen(fullname) + 1); + readcmdfile(fullname); + if ((cmdp = cmdlookup(name, 0)) == NULL || + cmdp->cmdtype != CMDFUNCTION) + error("%s not defined in %s", name, fullname); + stunalloc(fullname); + goto success; + } + TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); + if (!updatetbl) { + entry->cmdtype = CMDNORMAL; + entry->u.index = idx; + return; + } + INTOFF; + cmdp = cmdlookup(name, 1); + cmdp->cmdtype = CMDNORMAL; + cmdp->param.index = idx; + INTON; + goto success; + } + + /* We failed. If there was an entry for this command, delete it */ + if (cmdp && updatetbl) + delete_cmd_entry(); + if (act & DO_ERR) + sh_warnx("%s: %s", name, errmsg(e, E_EXEC)); + entry->cmdtype = CMDUNKNOWN; + return; + +builtin_success: + if (!updatetbl) { + entry->cmdtype = CMDBUILTIN; + entry->u.cmd = bcmd; + return; + } + INTOFF; + cmdp = cmdlookup(name, 1); + cmdp->cmdtype = CMDBUILTIN; + cmdp->param.cmd = bcmd; + INTON; +success: + cmdp->rehash = 0; + entry->cmdtype = cmdp->cmdtype; + entry->u = cmdp->param; +} + + +/* + * Wrapper around strcmp for qsort/bsearch/... + */ +static int pstrcmp(const void *a, const void *b) +{ + return strcmp((const char *) a, (*(const char *const *) b) + 1); +} + +/* + * Search the table of builtin commands. + */ + +static struct builtincmd * +find_builtin(const char *name) +{ + struct builtincmd *bp; + + bp = bsearch( + name, builtincmd, NUMBUILTINS, sizeof(struct builtincmd), + pstrcmp + ); + return bp; +} + + + +/* + * Called when a cd is done. Marks all commands so the next time they + * are executed they will be rehashed. + */ + +static void +hashcd(void) +{ + struct tblentry **pp; + struct tblentry *cmdp; + + for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { + for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { + if (cmdp->cmdtype == CMDNORMAL || ( + cmdp->cmdtype == CMDBUILTIN && + !(IS_BUILTIN_REGULAR(cmdp->param.cmd)) && + builtinloc > 0 + )) + cmdp->rehash = 1; + } + } +} + + + +/* + * Fix command hash table when PATH changed. + * Called before PATH is changed. The argument is the new value of PATH; + * pathval() still returns the old value at this point. + * Called with interrupts off. + */ + +static void +changepath(const char *newval) +{ + const char *old, *new; + int idx; + int firstchange; + int idx_bltin; + + old = pathval(); + new = newval; + firstchange = 9999; /* assume no change */ + idx = 0; + idx_bltin = -1; + for (;;) { + if (*old != *new) { + firstchange = idx; + if ((*old == '\0' && *new == ':') + || (*old == ':' && *new == '\0')) + firstchange++; + old = new; /* ignore subsequent differences */ + } + if (*new == '\0') + break; + if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin")) + idx_bltin = idx; + if (*new == ':') { + idx++; + } + new++, old++; + } + if (builtinloc < 0 && idx_bltin >= 0) + builtinloc = idx_bltin; /* zap builtins */ + if (builtinloc >= 0 && idx_bltin < 0) + firstchange = 0; + clearcmdentry(firstchange); + builtinloc = idx_bltin; +} + + +/* + * Clear out command entries. The argument specifies the first entry in + * PATH which has changed. + */ + +static void +clearcmdentry(int firstchange) +{ + struct tblentry **tblp; + struct tblentry **pp; + struct tblentry *cmdp; + + INTOFF; + for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) { + pp = tblp; + while ((cmdp = *pp) != NULL) { + if ((cmdp->cmdtype == CMDNORMAL && + cmdp->param.index >= firstchange) + || (cmdp->cmdtype == CMDBUILTIN && + builtinloc >= firstchange)) { + *pp = cmdp->next; + ckfree(cmdp); + } else { + pp = &cmdp->next; + } + } + } + INTON; +} + + + +/* + * Locate a command in the command hash table. If "add" is nonzero, + * add the command to the table if it is not already present. The + * variable "lastcmdentry" is set to point to the address of the link + * pointing to the entry, so that delete_cmd_entry can delete the + * entry. + * + * Interrupts must be off if called with add != 0. + */ + +static struct tblentry **lastcmdentry; + + +static struct tblentry * +cmdlookup(const char *name, int add) +{ + unsigned int hashval; + const char *p; + struct tblentry *cmdp; + struct tblentry **pp; + + p = name; + hashval = (unsigned char)*p << 4; + while (*p) + hashval += (unsigned char)*p++; + hashval &= 0x7FFF; + pp = &cmdtable[hashval % CMDTABLESIZE]; + for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { + if (equal(cmdp->cmdname, name)) + break; + pp = &cmdp->next; + } + if (add && cmdp == NULL) { + cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB + + strlen(name) + 1); + cmdp->next = NULL; + cmdp->cmdtype = CMDUNKNOWN; + strcpy(cmdp->cmdname, name); + } + lastcmdentry = pp; + return cmdp; +} + +/* + * Delete the command entry returned on the last lookup. + */ + +static void +delete_cmd_entry(void) +{ + struct tblentry *cmdp; + + INTOFF; + cmdp = *lastcmdentry; + *lastcmdentry = cmdp->next; + if (cmdp->cmdtype == CMDFUNCTION) + freefunc(cmdp->param.func); + ckfree(cmdp); + INTON; +} + + +/* + * Add a new command entry, replacing any existing command entry for + * the same name - except special builtins. + */ + +static inline void +addcmdentry(char *name, struct cmdentry *entry) +{ + struct tblentry *cmdp; + + cmdp = cmdlookup(name, 1); + if (cmdp->cmdtype == CMDFUNCTION) { + freefunc(cmdp->param.func); + } + cmdp->cmdtype = entry->cmdtype; + cmdp->param = entry->u; + cmdp->rehash = 0; +} + +/* + * Make a copy of a parse tree. + */ + +static inline struct funcnode * +copyfunc(union node *n) +{ + struct funcnode *f; + size_t blocksize; + + funcblocksize = offsetof(struct funcnode, n); + funcstringsize = 0; + calcsize(n); + blocksize = funcblocksize; + f = ckmalloc(blocksize + funcstringsize); + funcblock = (char *) f + offsetof(struct funcnode, n); + funcstring = (char *) f + blocksize; + copynode(n); + f->count = 0; + return f; +} + +/* + * Define a shell function. + */ + +static void +defun(char *name, union node *func) +{ + struct cmdentry entry; + + INTOFF; + entry.cmdtype = CMDFUNCTION; + entry.u.func = copyfunc(func); + addcmdentry(name, &entry); + INTON; +} + + +/* + * Delete a function if it exists. + */ + +static void +unsetfunc(const char *name) +{ + struct tblentry *cmdp; + + if ((cmdp = cmdlookup(name, 0)) != NULL && + cmdp->cmdtype == CMDFUNCTION) + delete_cmd_entry(); +} + +/* + * Locate and print what a word is... + */ + + +#ifdef BB_ASH_CMDCMD +static int +describe_command(char *command, int describe_command_verbose) +#else +#define describe_command_verbose 1 +static int +describe_command(char *command) +#endif +{ + struct cmdentry entry; + struct tblentry *cmdp; +#ifdef BB_ASH_ALIAS + const struct alias *ap; +#endif + const char *path = pathval(); + + if (describe_command_verbose) { + out1str(command); + } + + /* First look at the keywords */ + if (findkwd(command)) { + out1str(describe_command_verbose ? " is a shell keyword" : command); + goto out; + } + +#ifdef BB_ASH_ALIAS + /* Then look at the aliases */ + if ((ap = lookupalias(command, 0)) != NULL) { + if (describe_command_verbose) { + out1fmt(" is an alias for %s", ap->val); + } else { + out1str("alias "); + printalias(ap); + return 0; + } + goto out; + } +#endif + /* Then check if it is a tracked alias */ + if ((cmdp = cmdlookup(command, 0)) != NULL) { + entry.cmdtype = cmdp->cmdtype; + entry.u = cmdp->param; + } else { + /* Finally use brute force */ + find_command(command, &entry, DO_ABS, path); + } + + switch (entry.cmdtype) { + case CMDNORMAL: { + int j = entry.u.index; + char *p; + if (j == -1) { + p = command; + } else { + do { + p = padvance(&path, command); + stunalloc(p); + } while (--j >= 0); + } + if (describe_command_verbose) { + out1fmt(" is%s %s", + (cmdp ? " a tracked alias for" : nullstr), p + ); + } else { + out1str(p); + } + break; + } + + case CMDFUNCTION: + if (describe_command_verbose) { + out1str(" is a shell function"); + } else { + out1str(command); + } + break; + + case CMDBUILTIN: + if (describe_command_verbose) { + out1fmt(" is a %sshell builtin", + IS_BUILTIN_SPECIAL(entry.u.cmd) ? + "special " : nullstr + ); + } else { + out1str(command); + } + break; + + default: + if (describe_command_verbose) { + out1str(": not found\n"); + } + return 127; + } + +out: + outstr("\n", stdout); + return 0; +} + +static int +typecmd(int argc, char **argv) +{ + int i; + int err = 0; + + for (i = 1; i < argc; i++) { +#ifdef BB_ASH_CMDCMD + err |= describe_command(argv[i], 1); +#else + err |= describe_command(argv[i]); +#endif + } + return err; +} + +#ifdef BB_ASH_CMDCMD +static int +commandcmd(int argc, char **argv) +{ + int c; + int default_path = 0; + int verify_only = 0; + int verbose_verify_only = 0; + + while ((c = nextopt("pvV")) != '\0') + switch (c) { + default: +#ifdef DEBUG + fprintf(stderr, +"command: nextopt returned character code 0%o\n", c); + return EX_SOFTWARE; +#endif + case 'p': + default_path = 1; + break; + case 'v': + verify_only = 1; + break; + case 'V': + verbose_verify_only = 1; + break; + } + + if (default_path + verify_only + verbose_verify_only > 1 || + !*argptr) { + fprintf(stderr, + "command [-p] command [arg ...]\n" + "command {-v|-V} command\n"); + return EX_USAGE; + } + + if (verify_only || verbose_verify_only) { + return describe_command(*argptr, verbose_verify_only); + } + + return 0; +} +#endif + +/* $NetBSD: expand.c,v 1.56 2002/11/24 22:35:39 christos Exp $ */ + +/* + * Routines to expand arguments to commands. We have to deal with + * backquotes, shell variables, and file metacharacters. + */ + +/* + * _rmescape() flags + */ +#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ +#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ +#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */ +#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ +#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ + +/* + * Structure specifying which parts of the string should be searched + * for IFS characters. + */ + +struct ifsregion { + struct ifsregion *next; /* next region in list */ + int begoff; /* offset of start of region */ + int endoff; /* offset of end of region */ + int nulonly; /* search for nul bytes only */ +}; + +/* output of current string */ +static char *expdest; +/* list of back quote expressions */ +static struct nodelist *argbackq; +/* first struct in list of ifs regions */ +static struct ifsregion ifsfirst; +/* last struct in list */ +static struct ifsregion *ifslastp; +/* holds expanded arg list */ +static struct arglist exparg; + +static void argstr(char *, int); +static char *exptilde(char *, char *, int); +static void expbackq(union node *, int, int); +static const char *subevalvar(char *, char *, int, int, int, int, int); +static char *evalvar(char *, int); +static int varisset(char *, int); +static void strtodest(const char *, int, int); +static void memtodest(const char *p, size_t len, int syntax, int quotes); +static void varvalue(char *, int, int); +static void recordregion(int, int, int); +static void removerecordregions(int); +static void ifsbreakup(char *, struct arglist *); +static void ifsfree(void); +static void expandmeta(struct strlist *, int); +static int patmatch(char *, const char *); + +static int cvtnum(long); +static size_t esclen(const char *, const char *); +static char *scanleft(char *, char *, char *, char *, int, int); +static char *scanright(char *, char *, char *, char *, int, int); +static void varunset(const char *, const char *, const char *, int) + __attribute__((__noreturn__)); + + +#define pmatch(a, b) !fnmatch((a), (b), 0) +/* + * Prepare a pattern for a expmeta (internal glob(3)) call. + * + * Returns an stalloced string. + */ + +static inline char * +preglob(const char *pattern, int quoted, int flag) { + flag |= RMESCAPE_GLOB; + if (quoted) { + flag |= RMESCAPE_QUOTED; + } + return _rmescapes((char *)pattern, flag); +} + + +static size_t +esclen(const char *start, const char *p) { + size_t esc = 0; + + while (p > start && *--p == CTLESC) { + esc++; + } + return esc; +} + + +/* + * Expand shell variables and backquotes inside a here document. + */ + +static inline void +expandhere(union node *arg, int fd) +{ + herefd = fd; + expandarg(arg, (struct arglist *)NULL, 0); + xwrite(fd, stackblock(), expdest - (char *)stackblock()); +} + + +/* + * Perform variable substitution and command substitution on an argument, + * placing the resulting list of arguments in arglist. If EXP_FULL is true, + * perform splitting and file name expansion. When arglist is NULL, perform + * here document expansion. + */ + +void +expandarg(union node *arg, struct arglist *arglist, int flag) +{ + struct strlist *sp; + char *p; + + argbackq = arg->narg.backquote; + STARTSTACKSTR(expdest); + ifsfirst.next = NULL; + ifslastp = NULL; + argstr(arg->narg.text, flag); + if (arglist == NULL) { + return; /* here document expanded */ + } + STPUTC('\0', expdest); + p = grabstackstr(expdest); + exparg.lastp = &exparg.list; + /* + * TODO - EXP_REDIR + */ + if (flag & EXP_FULL) { + ifsbreakup(p, &exparg); + *exparg.lastp = NULL; + exparg.lastp = &exparg.list; + expandmeta(exparg.list, flag); + } else { + if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ + rmescapes(p); + sp = (struct strlist *)stalloc(sizeof (struct strlist)); + sp->text = p; + *exparg.lastp = sp; + exparg.lastp = &sp->next; + } + if (ifsfirst.next) + ifsfree(); + *exparg.lastp = NULL; + if (exparg.list) { + *arglist->lastp = exparg.list; + arglist->lastp = exparg.lastp; + } +} + + +/* + * Perform variable and command substitution. If EXP_FULL is set, output CTLESC + * characters to allow for further processing. Otherwise treat + * $@ like $* since no splitting will be performed. + */ + +static void +argstr(char *p, int flag) +{ + static const char spclchars[] = { + '=', + ':', + CTLQUOTEMARK, + CTLENDVAR, + CTLESC, + CTLVAR, + CTLBACKQ, + CTLBACKQ | CTLQUOTE, +#ifdef BB_ASH_MATH_SUPPORT + CTLENDARI, +#endif + 0 + }; + const char *reject = spclchars; + int c; + int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ + int breakall = flag & EXP_WORD; + int inquotes; + size_t length; + int startloc; + + if (!(flag & EXP_VARTILDE)) { + reject += 2; + } else if (flag & EXP_VARTILDE2) { + reject++; + } + inquotes = 0; + length = 0; + if (flag & EXP_TILDE) { + char *q; + + flag &= ~EXP_TILDE; +tilde: + q = p; + if (*q == CTLESC && (flag & EXP_QWORD)) + q++; + if (*q == '~') + p = exptilde(p, q, flag); + } +start: + startloc = expdest - (char *)stackblock(); + for (;;) { + length += strcspn(p + length, reject); + c = p[length]; + if (c && (!(c & 0x80) +#ifdef BB_ASH_MATH_SUPPORT + || c == CTLENDARI +#endif + )) { + /* c == '=' || c == ':' || c == CTLENDARI */ + length++; + } + if (length > 0) { + int newloc; + expdest = stnputs(p, length, expdest); + newloc = expdest - (char *)stackblock(); + if (breakall && !inquotes && newloc > startloc) { + recordregion(startloc, newloc, 0); + } + startloc = newloc; + } + p += length + 1; + length = 0; + + switch (c) { + case '\0': + goto breakloop; + case '=': + if (flag & EXP_VARTILDE2) { + p--; + continue; + } + flag |= EXP_VARTILDE2; + reject++; + /* fall through */ + case ':': + /* + * sort of a hack - expand tildes in variable + * assignments (after the first '=' and after ':'s). + */ + if (*--p == '~') { + goto tilde; + } + continue; + } + + switch (c) { + case CTLENDVAR: /* ??? */ + goto breakloop; + case CTLQUOTEMARK: + /* "$@" syntax adherence hack */ + if ( + !inquotes && + !memcmp(p, dolatstr, DOLATSTRLEN) && + (p[4] == CTLQUOTEMARK || ( + p[4] == CTLENDVAR && + p[5] == CTLQUOTEMARK + )) + ) { + p = evalvar(p + 1, flag) + 1; + goto start; + } + inquotes = !inquotes; +addquote: + if (quotes) { + p--; + length++; + startloc++; + } + break; + case CTLESC: + startloc++; + length++; + goto addquote; + case CTLVAR: + p = evalvar(p, flag); + goto start; + case CTLBACKQ: + c = 0; + case CTLBACKQ|CTLQUOTE: + expbackq(argbackq->n, c, quotes); + argbackq = argbackq->next; + goto start; +#ifdef BB_ASH_MATH_SUPPORT + case CTLENDARI: + p--; + expari(quotes); + goto start; +#endif + } + } +breakloop: + ; +} + +static char * +exptilde(char *startp, char *p, int flag) +{ + char c; + char *name; + struct passwd *pw; + const char *home; + int quotes = flag & (EXP_FULL | EXP_CASE); + int startloc; + + name = p + 1; + + while ((c = *++p) != '\0') { + switch(c) { + case CTLESC: + return (startp); + case CTLQUOTEMARK: + return (startp); + case ':': + if (flag & EXP_VARTILDE) + goto done; + break; + case '/': + case CTLENDVAR: + goto done; + } + } +done: + *p = '\0'; + if (*name == '\0') { + if ((home = lookupvar(homestr)) == NULL) + goto lose; + } else { + if ((pw = getpwnam(name)) == NULL) + goto lose; + home = pw->pw_dir; + } + if (*home == '\0') + goto lose; + *p = c; + startloc = expdest - (char *)stackblock(); + strtodest(home, SQSYNTAX, quotes); + recordregion(startloc, expdest - (char *)stackblock(), 0); + return (p); +lose: + *p = c; + return (startp); +} + + +static void +removerecordregions(int endoff) +{ + if (ifslastp == NULL) + return; + + if (ifsfirst.endoff > endoff) { + while (ifsfirst.next != NULL) { + struct ifsregion *ifsp; + INTOFF; + ifsp = ifsfirst.next->next; + ckfree(ifsfirst.next); + ifsfirst.next = ifsp; + INTON; + } + if (ifsfirst.begoff > endoff) + ifslastp = NULL; + else { + ifslastp = &ifsfirst; + ifsfirst.endoff = endoff; + } + return; + } + + ifslastp = &ifsfirst; + while (ifslastp->next && ifslastp->next->begoff < endoff) + ifslastp=ifslastp->next; + while (ifslastp->next != NULL) { + struct ifsregion *ifsp; + INTOFF; + ifsp = ifslastp->next->next; + ckfree(ifslastp->next); + ifslastp->next = ifsp; + INTON; + } + if (ifslastp->endoff > endoff) + ifslastp->endoff = endoff; +} + + +#ifdef BB_ASH_MATH_SUPPORT +/* + * Expand arithmetic expression. Backup to start of expression, + * evaluate, place result in (backed up) result, adjust string position. + */ +void +expari(int quotes) +{ + char *p, *start; + int begoff; + int flag; + int len; + + /* ifsfree(); */ + + /* + * This routine is slightly over-complicated for + * efficiency. Next we scan backwards looking for the + * start of arithmetic. + */ + start = stackblock(); + p = expdest - 1; + *p = '\0'; + p--; + do { + int esc; + + while (*p != CTLARI) { + p--; +#ifdef DEBUG + if (p < start) { + error("missing CTLARI (shouldn't happen)"); + } +#endif + } + + esc = esclen(start, p); + if (!(esc % 2)) { + break; + } + + p -= esc + 1; + } while (1); + + begoff = p - start; + + removerecordregions(begoff); + + flag = p[1]; + + expdest = p; + + if (quotes) + rmescapes(p + 2); + + len = cvtnum(dash_arith(p + 2)); + + if (flag != '"') + recordregion(begoff, begoff + len, 0); +} +#endif + +/* + * Expand stuff in backwards quotes. + */ + +static void +expbackq(union node *cmd, int quoted, int quotes) +{ + struct backcmd in; + int i; + char buf[128]; + char *p; + char *dest; + int startloc; + int syntax = quoted? DQSYNTAX : BASESYNTAX; + struct stackmark smark; + + INTOFF; + setstackmark(&smark); + dest = expdest; + startloc = dest - (char *)stackblock(); + grabstackstr(dest); + evalbackcmd(cmd, (struct backcmd *) &in); + popstackmark(&smark); + + p = in.buf; + i = in.nleft; + if (i == 0) + goto read; + for (;;) { + memtodest(p, i, syntax, quotes); +read: + if (in.fd < 0) + break; + i = safe_read(in.fd, buf, sizeof buf); + TRACE(("expbackq: read returns %d\n", i)); + if (i <= 0) + break; + p = buf; + } + + if (in.buf) + ckfree(in.buf); + if (in.fd >= 0) { + close(in.fd); + back_exitstatus = waitforjob(in.jp); + } + INTON; + + /* Eat all trailing newlines */ + dest = expdest; + for (; dest > (char *)stackblock() && dest[-1] == '\n';) + STUNPUTC(dest); + expdest = dest; + + if (quoted == 0) + recordregion(startloc, dest - (char *)stackblock(), 0); + TRACE(("evalbackq: size=%d: \"%.*s\"\n", + (dest - (char *)stackblock()) - startloc, + (dest - (char *)stackblock()) - startloc, + stackblock() + startloc)); +} + + +static char * +scanleft(char *startp, char *rmesc, char *rmescend, char *str, int quotes, + int zero) +{ + char *loc; + char *loc2; + char c; + + loc = startp; + loc2 = rmesc; + do { + int match; + const char *s = loc2; + c = *loc2; + if (zero) { + *loc2 = '\0'; + s = rmesc; + } + match = pmatch(str, s); + *loc2 = c; + if (match) + return loc; + if (quotes && *loc == CTLESC) + loc++; + loc++; + loc2++; + } while (c); + return 0; +} + + +static char * +scanright(char *startp, char *rmesc, char *rmescend, char *str, int quotes, + int zero) +{ + int esc = 0; + char *loc; + char *loc2; + + for (loc = str - 1, loc2 = rmescend; loc >= startp; loc2--) { + int match; + char c = *loc2; + const char *s = loc2; + if (zero) { + *loc2 = '\0'; + s = rmesc; + } + match = pmatch(str, s); + *loc2 = c; + if (match) + return loc; + loc--; + if (quotes) { + if (--esc < 0) { + esc = esclen(startp, loc); + } + if (esc % 2) { + esc--; + loc--; + } + } + } + return 0; +} + +static const char * +subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes) +{ + char *startp; + char *loc; + int saveherefd = herefd; + struct nodelist *saveargbackq = argbackq; + int amount; + char *rmesc, *rmescend; + int zero; + char *(*scan)(char *, char *, char *, char *, int , int); + + herefd = -1; + argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); + STPUTC('\0', expdest); + herefd = saveherefd; + argbackq = saveargbackq; + startp = stackblock() + startloc; + + switch (subtype) { + case VSASSIGN: + setvar(str, startp, 0); + amount = startp - expdest; + STADJUST(amount, expdest); + return startp; + + case VSQUESTION: + varunset(p, str, startp, varflags); + /* NOTREACHED */ + } + + subtype -= VSTRIMRIGHT; +#ifdef DEBUG + if (subtype < 0 || subtype > 3) + abort(); +#endif + + rmesc = startp; + rmescend = stackblock() + strloc; + if (quotes) { + rmesc = _rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW); + if (rmesc != startp) { + rmescend = expdest; + startp = stackblock() + startloc; + } + } + rmescend--; + str = stackblock() + strloc; + preglob(str, varflags & VSQUOTE, 0); + + /* zero = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX */ + zero = subtype >> 1; + /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */ + scan = (subtype & 1) ^ zero ? scanleft : scanright; + + loc = scan(startp, rmesc, rmescend, str, quotes, zero); + if (loc) { + if (zero) { + memmove(startp, loc, str - loc); + loc = startp + (str - loc) - 1; + } + *loc = '\0'; + amount = loc - expdest; + STADJUST(amount, expdest); + } + return loc; +} + + +/* + * Expand a variable, and return a pointer to the next character in the + * input string. + */ +static char * +evalvar(char *p, int flag) +{ + int subtype; + int varflags; + char *var; + int patloc; + int c; + int set; + int startloc; + size_t varlen; + int easy; + int quotes; + int quoted; + + quotes = flag & (EXP_FULL | EXP_CASE); + varflags = *p++; + subtype = varflags & VSTYPE; + quoted = varflags & VSQUOTE; + var = p; + easy = (!quoted || (*var == '@' && shellparam.nparam)); + varlen = 0; + startloc = expdest - (char *)stackblock(); + p = strchr(p, '=') + 1; + + if (!is_name(*var)) { + set = varisset(var, varflags & VSNUL); + set--; + if (subtype == VSPLUS) + goto vsplus; + if (++set) { + varvalue(var, quoted, flag); + if (subtype == VSLENGTH) { + varlen = + expdest - (char *)stackblock() - + startloc; + STADJUST(-varlen, expdest); + goto vslen; + } + } + } else { + const char *val; +again: + /* jump here after setting a variable with ${var=text} */ + val = lookupvar(var); + set = !val || ((varflags & VSNUL) && !*val); + if (subtype == VSPLUS) + goto vsplus; + if (--set) { + varlen = strlen(val); + if (subtype == VSLENGTH) + goto vslen; + memtodest( + val, varlen, quoted ? DQSYNTAX : BASESYNTAX, + quotes + ); + } + } + + + if (subtype == VSMINUS) { +vsplus: + if (!set) { + argstr( + p, flag | EXP_TILDE | + (quoted ? EXP_QWORD : EXP_WORD) + ); + goto end; + } + if (easy) + goto record; + goto end; + } + + if (subtype == VSASSIGN || subtype == VSQUESTION) { + if (!set) { + if (subevalvar(p, var, 0, subtype, startloc, + varflags, 0)) { + varflags &= ~VSNUL; + /* + * Remove any recorded regions beyond + * start of variable + */ + removerecordregions(startloc); + goto again; + } + goto end; + } + if (easy) + goto record; + goto end; + } + + if (!set && uflag) + varunset(p, var, 0, 0); + + if (subtype == VSLENGTH) { +vslen: + cvtnum(varlen); + goto record; + } + + if (subtype == VSNORMAL) { + if (!easy) + goto end; +record: + recordregion(startloc, expdest - (char *)stackblock(), quoted); + goto end; + } + +#ifdef DEBUG + switch (subtype) { + case VSTRIMLEFT: + case VSTRIMLEFTMAX: + case VSTRIMRIGHT: + case VSTRIMRIGHTMAX: + break; + default: + abort(); + } +#endif + + if (set) { + /* + * Terminate the string and start recording the pattern + * right after it + */ + STPUTC('\0', expdest); + patloc = expdest - (char *)stackblock(); + if (subevalvar(p, NULL, patloc, subtype, + startloc, varflags, quotes) == 0) { + int amount = expdest - ( + (char *)stackblock() + patloc - 1 + ); + STADJUST(-amount, expdest); + } + /* Remove any recorded regions beyond start of variable */ + removerecordregions(startloc); + goto record; + } + +end: + if (subtype != VSNORMAL) { /* skip to end of alternative */ + int nesting = 1; + for (;;) { + if ((c = *p++) == CTLESC) + p++; + else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { + if (set) + argbackq = argbackq->next; + } else if (c == CTLVAR) { + if ((*p++ & VSTYPE) != VSNORMAL) + nesting++; + } else if (c == CTLENDVAR) { + if (--nesting == 0) + break; + } + } + } + return p; +} + + + +/* + * Test whether a specialized variable is set. + */ + +static int +varisset(char *name, int nulok) +{ + if (*name == '!') + return backgndpid != 0; + else if (*name == '@' || *name == '*') { + if (*shellparam.p == NULL) + return 0; + + if (nulok) { + char **av; + + for (av = shellparam.p; *av; av++) + if (**av != '\0') + return 1; + return 0; + } + } else if (is_digit(*name)) { + char *ap; + int num = atoi(name); + + if (num > shellparam.nparam) + return 0; + + if (num == 0) + ap = arg0; + else + ap = shellparam.p[num - 1]; + + if (nulok && (ap == NULL || *ap == '\0')) + return 0; + } + return 1; +} + + +/* + * Put a string on the stack. + */ + +static void +memtodest(const char *p, size_t len, int syntax, int quotes) { + char *q = expdest; + + q = makestrspace(len * 2, q); + + while (len--) { + int c = *p++; + if (!c) + continue; + if (quotes && (SIT(c, syntax) == CCTL || SIT(c, syntax) == CBACK)) + USTPUTC(CTLESC, q); + USTPUTC(c, q); + } + + expdest = q; +} + + +static void +strtodest(const char *p, int syntax, int quotes) +{ + memtodest(p, strlen(p), syntax, quotes); +} + + +/* + * Add the value of a specialized variable to the stack string. + */ + +static void +varvalue(char *name, int quoted, int flags) +{ + int num; + char *p; + int i; + int sep; + int sepq = 0; + char **ap; + int syntax; + int allow_split = flags & EXP_FULL; + int quotes = flags & (EXP_FULL | EXP_CASE); + + syntax = quoted ? DQSYNTAX : BASESYNTAX; + switch (*name) { + case '$': + num = rootpid; + goto numvar; + case '?': + num = exitstatus; + goto numvar; + case '#': + num = shellparam.nparam; + goto numvar; + case '!': + num = backgndpid; +numvar: + cvtnum(num); + break; + case '-': + for (i = 0 ; i < NOPTS ; i++) { + if (optlist[i]) + STPUTC(optletters(i), expdest); + } + break; + case '@': + if (allow_split && quoted) { + sep = 1 << CHAR_BIT; + goto param; + } + /* fall through */ + case '*': + sep = ifsset() ? ifsval()[0] : ' '; + if (quotes) { + sepq = (SIT(sep, syntax) == CCTL) || (SIT(sep, syntax) == CBACK); + } +param: + for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { + strtodest(p, syntax, quotes); + if (*ap && sep) { + p = expdest; + if (sepq) + STPUTC(CTLESC, p); + STPUTC(sep, p); + expdest = p; + } + } + break; + case '0': + strtodest(arg0, syntax, quotes); + break; + default: + num = atoi(name); + if (num > 0 && num <= shellparam.nparam) { + strtodest(shellparam.p[num - 1], syntax, quotes); + } + break; + } +} + + +/* + * Record the fact that we have to scan this region of the + * string for IFS characters. + */ + +static void +recordregion(int start, int end, int nulonly) +{ + struct ifsregion *ifsp; + + if (ifslastp == NULL) { + ifsp = &ifsfirst; + } else { + INTOFF; + ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); + ifsp->next = NULL; + ifslastp->next = ifsp; + INTON; + } + ifslastp = ifsp; + ifslastp->begoff = start; + ifslastp->endoff = end; + ifslastp->nulonly = nulonly; +} + + +/* + * Break the argument string into pieces based upon IFS and add the + * strings to the argument list. The regions of the string to be + * searched for IFS characters have been stored by recordregion. + */ +static void +ifsbreakup(char *string, struct arglist *arglist) +{ + struct ifsregion *ifsp; + struct strlist *sp; + char *start; + char *p; + char *q; + const char *ifs, *realifs; + int ifsspc; + int nulonly; + + + start = string; + if (ifslastp != NULL) { + ifsspc = 0; + nulonly = 0; + realifs = ifsset() ? ifsval() : defifs; + ifsp = &ifsfirst; + do { + p = string + ifsp->begoff; + nulonly = ifsp->nulonly; + ifs = nulonly ? nullstr : realifs; + ifsspc = 0; + while (p < string + ifsp->endoff) { + q = p; + if (*p == CTLESC) + p++; + if (strchr(ifs, *p)) { + if (!nulonly) + ifsspc = (strchr(defifs, *p) != NULL); + /* Ignore IFS whitespace at start */ + if (q == start && ifsspc) { + p++; + start = p; + continue; + } + *q = '\0'; + sp = (struct strlist *)stalloc(sizeof *sp); + sp->text = start; + *arglist->lastp = sp; + arglist->lastp = &sp->next; + p++; + if (!nulonly) { + for (;;) { + if (p >= string + ifsp->endoff) { + break; + } + q = p; + if (*p == CTLESC) + p++; + if (strchr(ifs, *p) == NULL ) { + p = q; + break; + } else if (strchr(defifs, *p) == NULL) { + if (ifsspc) { + p++; + ifsspc = 0; + } else { + p = q; + break; + } + } else + p++; + } + } + start = p; + } else + p++; + } + } while ((ifsp = ifsp->next) != NULL); + if (nulonly) + goto add; + } + + if (!*start) + return; + +add: + sp = (struct strlist *)stalloc(sizeof *sp); + sp->text = start; + *arglist->lastp = sp; + arglist->lastp = &sp->next; +} + +static void +ifsfree(void) +{ + struct ifsregion *p; + + INTOFF; + p = ifsfirst.next; + do { + struct ifsregion *ifsp; + ifsp = p->next; + ckfree(p); + p = ifsp; + } while (p); + ifslastp = NULL; + ifsfirst.next = NULL; + INTON; +} + +static void expmeta(char *, char *); +static struct strlist *expsort(struct strlist *); +static struct strlist *msort(struct strlist *, int); + +static char *expdir; + + +static void +expandmeta(struct strlist *str, int flag) +{ + static const char metachars[] = { + '*', '?', '[', 0 + }; + /* TODO - EXP_REDIR */ + + while (str) { + struct strlist **savelastp; + struct strlist *sp; + char *p; + + if (fflag) + goto nometa; + if (!strpbrk(str->text, metachars)) + goto nometa; + savelastp = exparg.lastp; + + INTOFF; + p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); + { + int i = strlen(str->text); + expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ + } + + expmeta(expdir, p); + ckfree(expdir); + if (p != str->text) + ckfree(p); + INTON; + if (exparg.lastp == savelastp) { + /* + * no matches + */ +nometa: + *exparg.lastp = str; + rmescapes(str->text); + exparg.lastp = &str->next; + } else { + *exparg.lastp = NULL; + *savelastp = sp = expsort(*savelastp); + while (sp->next != NULL) + sp = sp->next; + exparg.lastp = &sp->next; + } + str = str->next; + } +} + +/* + * Add a file name to the list. + */ + +static void +addfname(const char *name) +{ + struct strlist *sp; + + sp = (struct strlist *)stalloc(sizeof *sp); + sp->text = sstrdup(name); + *exparg.lastp = sp; + exparg.lastp = &sp->next; +} + + +/* + * Do metacharacter (i.e. *, ?, [...]) expansion. + */ + +static void +expmeta(char *enddir, char *name) +{ + char *p; + const char *cp; + char *start; + char *endname; + int metaflag; + struct stat statb; + DIR *dirp; + struct dirent *dp; + int atend; + int matchdot; + + metaflag = 0; + start = name; + for (p = name; *p; p++) { + if (*p == '*' || *p == '?') + metaflag = 1; + else if (*p == '[') { + char *q = p + 1; + if (*q == '!') + q++; + for (;;) { + if (*q == '\\') + q++; + if (*q == '/' || *q == '\0') + break; + if (*++q == ']') { + metaflag = 1; + break; + } + } + } else if (*p == '\\') + p++; + else if (*p == '/') { + if (metaflag) + goto out; + start = p + 1; + } + } +out: + if (metaflag == 0) { /* we've reached the end of the file name */ + if (enddir != expdir) + metaflag++; + p = name; + do { + if (*p == '\\') + p++; + *enddir++ = *p; + } while (*p++); + if (metaflag == 0 || lstat(expdir, &statb) >= 0) + addfname(expdir); + return; + } + endname = p; + if (name < start) { + p = name; + do { + if (*p == '\\') + p++; + *enddir++ = *p++; + } while (p < start); + } + if (enddir == expdir) { + cp = "."; + } else if (enddir == expdir + 1 && *expdir == '/') { + cp = "/"; + } else { + cp = expdir; + enddir[-1] = '\0'; + } + if ((dirp = opendir(cp)) == NULL) + return; + if (enddir != expdir) + enddir[-1] = '/'; + if (*endname == 0) { + atend = 1; + } else { + atend = 0; + *endname++ = '\0'; + } + matchdot = 0; + p = start; + if (*p == '\\') + p++; + if (*p == '.') + matchdot++; + while (! intpending && (dp = readdir(dirp)) != NULL) { + if (dp->d_name[0] == '.' && ! matchdot) + continue; + if (pmatch(start, dp->d_name)) { + if (atend) { + scopy(dp->d_name, enddir); + addfname(expdir); + } else { + for (p = enddir, cp = dp->d_name; + (*p++ = *cp++) != '\0';) + continue; + p[-1] = '/'; + expmeta(p, endname); + } + } + } + closedir(dirp); + if (! atend) + endname[-1] = '/'; +} + +/* + * Sort the results of file name expansion. It calculates the number of + * strings to sort and then calls msort (short for merge sort) to do the + * work. + */ + +static struct strlist * +expsort(struct strlist *str) +{ + int len; + struct strlist *sp; + + len = 0; + for (sp = str ; sp ; sp = sp->next) + len++; + return msort(str, len); +} + + +static struct strlist * +msort(struct strlist *list, int len) +{ + struct strlist *p, *q = NULL; + struct strlist **lpp; + int half; + int n; + + if (len <= 1) + return list; + half = len >> 1; + p = list; + for (n = half ; --n >= 0 ; ) { + q = p; + p = p->next; + } + q->next = NULL; /* terminate first half of list */ + q = msort(list, half); /* sort first half of list */ + p = msort(p, len - half); /* sort second half */ + lpp = &list; + for (;;) { +#ifdef BB_LOCALE_SUPPORT + if (strcoll(p->text, q->text) < 0) +#else + if (strcmp(p->text, q->text) < 0) +#endif + { + *lpp = p; + lpp = &p->next; + if ((p = *lpp) == NULL) { + *lpp = q; + break; + } + } else { + *lpp = q; + lpp = &q->next; + if ((q = *lpp) == NULL) { + *lpp = p; + break; + } + } + } + return list; +} + + +/* + * Returns true if the pattern matches the string. + */ + +static inline int +patmatch(char *pattern, const char *string) +{ + return pmatch(preglob(pattern, 0, 0), string); +} + + +/* + * Remove any CTLESC characters from a string. + */ + +static char * +_rmescapes(char *str, int flag) +{ + char *p, *q, *r; + static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 }; + unsigned inquotes; + int notescaped; + int globbing; + + p = strpbrk(str, qchars); + if (!p) { + return str; + } + q = p; + r = str; + if (flag & RMESCAPE_ALLOC) { + size_t len = p - str; + size_t fulllen = len + strlen(p) + 1; + + if (flag & RMESCAPE_GROW) { + r = makestrspace(fulllen, expdest); + } else if (flag & RMESCAPE_HEAP) { + r = ckmalloc(fulllen); + } else { + r = stalloc(fulllen); + } + q = r; + if (len > 0) { + q = mempcpy(q, str, len); + } + } + inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; + globbing = flag & RMESCAPE_GLOB; + notescaped = globbing; + while (*p) { + if (*p == CTLQUOTEMARK) { + inquotes = ~inquotes; + p++; + notescaped = globbing; + continue; + } + if (*p == '\\') { + /* naked back slash */ + notescaped = 0; + goto copy; + } + if (*p == CTLESC) { + p++; + if (notescaped && inquotes && *p != '/') { + *q++ = '\\'; + } + } + notescaped = globbing; +copy: + *q++ = *p++; + } + *q = '\0'; + if (flag & RMESCAPE_GROW) { + expdest = r; + STADJUST(q - r + 1, expdest); + } + return r; +} + + +/* + * See if a pattern matches in a case statement. + */ + +int +casematch(union node *pattern, char *val) +{ + struct stackmark smark; + int result; + + setstackmark(&smark); + argbackq = pattern->narg.backquote; + STARTSTACKSTR(expdest); + ifslastp = NULL; + argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); + STACKSTRNUL(expdest); + result = patmatch(stackblock(), val); + popstackmark(&smark); + return result; +} + +/* + * Our own itoa(). + */ + +static int +cvtnum(long num) +{ + int len; + + expdest = makestrspace(32, expdest); + len = fmtstr(expdest, 32, "%ld", num); + STADJUST(len, expdest); + return len; +} + +static void +varunset(const char *end, const char *var, const char *umsg, int varflags) +{ + const char *msg; + const char *tail; + + tail = nullstr; + msg = "parameter not set"; + if (umsg) { + if (*end == CTLENDVAR) { + if (varflags & VSNUL) + tail = " or null"; + } else + msg = umsg; + } + error("%.*s: %s%s", end - var - 1, var, msg, tail); +} + + +/* $NetBSD: input.c,v 1.37 2002/11/24 22:35:40 christos Exp $ */ + +/* + * This implements the input routines used by the parser. + */ + +#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ +#define IBUFSIZ (BUFSIZ + 1) + +static void pushfile(void); + +/* + * Read a line from the script. + */ + +static inline char * +pfgets(char *line, int len) +{ + char *p = line; + int nleft = len; + int c; + + while (--nleft > 0) { + c = pgetc2(); + if (c == PEOF) { + if (p == line) + return NULL; + break; + } + *p++ = c; + if (c == '\n') + break; + } + *p = '\0'; + return line; +} + + +/* + * Read a character from the script, returning PEOF on end of file. + * Nul characters in the input are silently discarded. + */ + +#define pgetc_as_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer()) + +#ifdef BB_ASH_OPTIMIZE_FOR_SIZE +#define pgetc_macro() pgetc() +static int +pgetc(void) +{ + return pgetc_as_macro(); +} +#else +#define pgetc_macro() pgetc_as_macro() +static int +pgetc(void) +{ + return pgetc_macro(); +} +#endif + + +/* + * Same as pgetc(), but ignores PEOA. + */ +#ifdef BB_ASH_ALIAS +static int pgetc2(void) +{ + int c; + + do { + c = pgetc_macro(); + } while (c == PEOA); + return c; +} +#else +static inline int pgetc2(void) +{ + return pgetc_macro(); +} +#endif + + +#ifdef BB_FEATURE_COMMAND_EDITING +static const char *cmdedit_prompt; +static inline void putprompt(const char *s) +{ + cmdedit_prompt = s; +} +#else +static inline void putprompt(const char *s) +{ + out2str(s); +} +#endif + +static inline int +preadfd(void) +{ + int nr; + char *buf = parsefile->buf; + parsenextc = buf; + +retry: +#ifdef BB_FEATURE_COMMAND_EDITING + if (!iflag || parsefile->fd) + nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); + else { + nr = cmdedit_read_input((char *) cmdedit_prompt, buf); + if(nr == 0) { + /* Ctrl+C presend */ + raise(SIGINT); + goto retry; + } + if(nr < 0) { + /* Ctrl+D presend */ + nr = 0; + } + } +#else + nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); +#endif + + if (nr < 0) { + if (parsefile->fd == 0 && errno == EWOULDBLOCK) { + int flags = fcntl(0, F_GETFL, 0); + if (flags >= 0 && flags & O_NONBLOCK) { + flags &=~ O_NONBLOCK; + if (fcntl(0, F_SETFL, flags) >= 0) { + out2str("sh: turning off NDELAY mode\n"); + goto retry; + } + } + } + } + return nr; +} + +/* + * Refill the input buffer and return the next input character: + * + * 1) If a string was pushed back on the input, pop it; + * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading + * from a string so we can't refill the buffer, return EOF. + * 3) If the is more stuff in this buffer, use it else call read to fill it. + * 4) Process input up to the next newline, deleting nul characters. + */ + +int +preadbuffer(void) +{ + char *p, *q; + int more; + char savec; + + while (parsefile->strpush) { +#ifdef BB_ASH_ALIAS + if (parsenleft == -1 && parsefile->strpush->ap && + parsenextc[-1] != ' ' && parsenextc[-1] != '\t') { + return PEOA; + } +#endif + popstring(); + if (--parsenleft >= 0) + return (*parsenextc++); + } + if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) + return PEOF; + flushall(); + +again: + if (parselleft <= 0) { + if ((parselleft = preadfd()) <= 0) { + parselleft = parsenleft = EOF_NLEFT; + return PEOF; + } + } + + q = p = parsenextc; + + /* delete nul characters */ + for (more = 1; more;) { + switch (*p) { + case '\0': + p++; /* Skip nul */ + goto check; + + case '\n': + parsenleft = q - parsenextc; + more = 0; /* Stop processing here */ + break; + + } + + *q++ = *p++; +check: + if (--parselleft <= 0 && more) { + parsenleft = q - parsenextc - 1; + if (parsenleft < 0) + goto again; + more = 0; + } + } + + savec = *q; + *q = '\0'; + + if (vflag) { + out2str(parsenextc); + } + + *q = savec; + + return *parsenextc++; +} + +/* + * Undo the last call to pgetc. Only one character may be pushed back. + * PEOF may be pushed back. + */ + +void +pungetc(void) +{ + parsenleft++; + parsenextc--; +} + +/* + * Push a string back onto the input at this current parsefile level. + * We handle aliases this way. + */ +void +pushstring(char *s, void *ap) +{ + struct strpush *sp; + size_t len; + + len = strlen(s); + INTOFF; +/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ + if (parsefile->strpush) { + sp = ckmalloc(sizeof (struct strpush)); + sp->prev = parsefile->strpush; + parsefile->strpush = sp; + } else + sp = parsefile->strpush = &(parsefile->basestrpush); + sp->prevstring = parsenextc; + sp->prevnleft = parsenleft; +#ifdef BB_ASH_ALIAS + sp->ap = (struct alias *)ap; + if (ap) { + ((struct alias *)ap)->flag |= ALIASINUSE; + sp->string = s; + } +#endif + parsenextc = s; + parsenleft = len; + INTON; +} + +void +popstring(void) +{ + struct strpush *sp = parsefile->strpush; + + INTOFF; +#ifdef BB_ASH_ALIAS + if (sp->ap) { + if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { + checkkwd |= CHKALIAS; + } + if (sp->string != sp->ap->val) { + ckfree(sp->string); + } + sp->ap->flag &= ~ALIASINUSE; + if (sp->ap->flag & ALIASDEAD) { + unalias(sp->ap->name); + } + } +#endif + parsenextc = sp->prevstring; + parsenleft = sp->prevnleft; +/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ + parsefile->strpush = sp->prev; + if (sp != &(parsefile->basestrpush)) + ckfree(sp); + INTON; +} + +/* + * Set the input to take input from a file. If push is set, push the + * old input onto the stack first. + */ + +void +setinputfile(const char *fname, int push) +{ + int fd; + int fd2; + + INTOFF; + if ((fd = open(fname, O_RDONLY)) < 0) + error("Can't open %s", fname); + if (fd < 10) { + fd2 = ash_copyfd(fd, 10); + close(fd); + if (fd2 < 0) + error("Out of file descriptors"); + fd = fd2; + } + setinputfd(fd, push); + INTON; +} + + +/* + * Like setinputfile, but takes an open file descriptor. Call this with + * interrupts off. + */ + +static void +setinputfd(int fd, int push) +{ + (void) fcntl(fd, F_SETFD, FD_CLOEXEC); + if (push) { + pushfile(); + parsefile->buf = 0; + } + parsefile->fd = fd; + if (parsefile->buf == NULL) + parsefile->buf = ckmalloc(IBUFSIZ); + parselleft = parsenleft = 0; + plinno = 1; +} + + +/* + * Like setinputfile, but takes input from a string. + */ + +static void +setinputstring(char *string) +{ + INTOFF; + pushfile(); + parsenextc = string; + parsenleft = strlen(string); + parsefile->buf = NULL; + plinno = 1; + INTON; +} + + +/* + * To handle the "." command, a stack of input files is used. Pushfile + * adds a new entry to the stack and popfile restores the previous level. + */ + +static void +pushfile(void) +{ + struct parsefile *pf; + + parsefile->nleft = parsenleft; + parsefile->lleft = parselleft; + parsefile->nextc = parsenextc; + parsefile->linno = plinno; + pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); + pf->prev = parsefile; + pf->fd = -1; + pf->strpush = NULL; + pf->basestrpush.prev = NULL; + parsefile = pf; +} + + +static void +popfile(void) +{ + struct parsefile *pf = parsefile; + + INTOFF; + if (pf->fd >= 0) + close(pf->fd); + if (pf->buf) + ckfree(pf->buf); + while (pf->strpush) + popstring(); + parsefile = pf->prev; + ckfree(pf); + parsenleft = parsefile->nleft; + parselleft = parsefile->lleft; + parsenextc = parsefile->nextc; + plinno = parsefile->linno; + INTON; +} + + +/* + * Return to top level. + */ + +static void +popallfiles(void) +{ + while (parsefile != &basepf) + popfile(); +} + + +/* + * Close the file(s) that the shell is reading commands from. Called + * after a fork is done. + */ + +static void +closescript(void) +{ + popallfiles(); + if (parsefile->fd > 0) { + close(parsefile->fd); + parsefile->fd = 0; + } +} + +/* $NetBSD: jobs.c,v 1.56 2002/11/25 12:13:03 agc Exp $ */ + +/* mode flags for set_curjob */ +#define CUR_DELETE 2 +#define CUR_RUNNING 1 +#define CUR_STOPPED 0 + +/* mode flags for dowait */ +#define DOWAIT_NORMAL 0 +#define DOWAIT_BLOCK 1 + +/* array of jobs */ +static struct job *jobtab; +/* size of array */ +static unsigned njobs; +#if JOBS +/* pgrp of shell on invocation */ +static int initialpgrp; +static int ttyfd = -1; +#endif +/* current job */ +static struct job *curjob; +/* number of presumed living untracked jobs */ +static int jobless; + +static void set_curjob(struct job *, unsigned); +#if JOBS +static int restartjob(struct job *, int); +static void xtcsetpgrp(int, pid_t); +static char *commandtext(union node *); +static void cmdlist(union node *, int); +static void cmdtxt(union node *); +static void cmdputs(const char *); +static void showpipe(struct job *, FILE *); +#endif +static int sprint_status(char *, int, int); +static void freejob(struct job *); +static struct job *getjob(const char *, int); +static struct job *growjobtab(void); +static void forkchild(struct job *, union node *, int); +static void forkparent(struct job *, union node *, int, pid_t); +static int dowait(int, struct job *); +static int getstatus(struct job *); + +static void +set_curjob(struct job *jp, unsigned mode) +{ + struct job *jp1; + struct job **jpp, **curp; + + /* first remove from list */ + jpp = curp = &curjob; + do { + jp1 = *jpp; + if (jp1 == jp) + break; + jpp = &jp1->prev_job; + } while (1); + *jpp = jp1->prev_job; + + /* Then re-insert in correct position */ + jpp = curp; + switch (mode) { + default: +#ifdef DEBUG + abort(); +#endif + case CUR_DELETE: + /* job being deleted */ + break; + case CUR_RUNNING: + /* newly created job or backgrounded job, + put after all stopped jobs. */ + do { + jp1 = *jpp; +#ifdef JOBS + if (!jp1 || jp1->state != JOBSTOPPED) +#endif + break; + jpp = &jp1->prev_job; + } while (1); + /* FALLTHROUGH */ +#ifdef JOBS + case CUR_STOPPED: +#endif + /* newly stopped job - becomes curjob */ + jp->prev_job = *jpp; + *jpp = jp; + break; + } +} + +#if JOBS +/* + * Turn job control on and off. + * + * Note: This code assumes that the third arg to ioctl is a character + * pointer, which is true on Berkeley systems but not System V. Since + * System V doesn't have job control yet, this isn't a problem now. + * + * Called with interrupts off. + */ + +void +setjobctl(int on) +{ + int fd; + int pgrp; + + if (on == jobctl || rootshell == 0) + return; + if (on) { + int ofd; + ofd = fd = open(_PATH_TTY, O_RDWR); + if (fd < 0) { + fd += 3; + while (!isatty(fd) && --fd >= 0) + ; + } + fd = fcntl(fd, F_DUPFD, 10); + close(ofd); + if (fd < 0) + goto out; + fcntl(fd, F_SETFD, FD_CLOEXEC); + do { /* while we are in the background */ + if ((pgrp = tcgetpgrp(fd)) < 0) { +out: + sh_warnx("can't access tty; job control turned off"); + mflag = on = 0; + goto close; + } + if (pgrp == getpgrp()) + break; + killpg(0, SIGTTIN); + } while (1); + initialpgrp = pgrp; + + setsignal(SIGTSTP); + setsignal(SIGTTOU); + setsignal(SIGTTIN); + pgrp = rootpid; + setpgid(0, pgrp); + xtcsetpgrp(fd, pgrp); + } else { + /* turning job control off */ + fd = ttyfd; + pgrp = initialpgrp; + xtcsetpgrp(fd, pgrp); + setpgid(0, pgrp); + setsignal(SIGTSTP); + setsignal(SIGTTOU); + setsignal(SIGTTIN); +close: + close(fd); + fd = -1; + } + ttyfd = fd; + jobctl = on; +} + +static int +killcmd(int argc, char **argv) +{ + int signo = -1; + int list = 0; + int i; + pid_t pid; + struct job *jp; + + if (argc <= 1) { +usage: + error( +"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n" +"kill -l [exitstatus]" + ); + } + + if (**++argv == '-') { + signo = decode_signal(*argv + 1, 1); + if (signo < 0) { + int c; + + while ((c = nextopt("ls:")) != '\0') + switch (c) { + default: +#ifdef DEBUG + abort(); +#endif + case 'l': + list = 1; + break; + case 's': + signo = decode_signal(optionarg, 1); + if (signo < 0) { + error( + "invalid signal number or name: %s", + optionarg + ); + } + break; + } + argv = argptr; + } else + argv++; + } + + if (!list && signo < 0) + signo = SIGTERM; + + if ((signo < 0 || !*argv) ^ list) { + goto usage; + } + + if (list) { + const char *name; + + if (!*argv) { + for (i = 1; i < NSIG; i++) { + name = u_signal_names(0, &i, 1); + if (name) + out1fmt(snlfmt, name); + } + return 0; + } + name = u_signal_names(*argptr, &signo, -1); + if (name) + out1fmt(snlfmt, name); + else + error("invalid signal number or exit status: %s", *argptr); + return 0; + } + + i = 0; + do { + if (**argv == '%') { + jp = getjob(*argv, 0); + pid = -jp->ps[0].pid; + } else + pid = number(*argv); + if (kill(pid, signo) != 0) { + sh_warnx("%m\n"); + i = 1; + } + } while (*++argv); + + return i; +} +#endif /* JOBS */ + +#if defined(JOBS) || defined(DEBUG) +static int +jobno(const struct job *jp) +{ + return jp - jobtab + 1; +} +#endif + +#ifdef JOBS +static int +fgcmd(int argc, char **argv) +{ + struct job *jp; + FILE *out; + int mode; + int retval; + + mode = (**argv == 'f') ? FORK_FG : FORK_BG; + nextopt(nullstr); + argv = argptr; + out = stdout; + do { + jp = getjob(*argv, 1); + if (mode == FORK_BG) { + set_curjob(jp, CUR_RUNNING); + fprintf(out, "[%d] ", jobno(jp)); + } + outstr(jp->ps->cmd, out); + showpipe(jp, out); + retval = restartjob(jp, mode); + } while (*argv && *++argv); + return retval; +} + +static int bgcmd(int, char **) __attribute__((__alias__("fgcmd"))); + + +static int +restartjob(struct job *jp, int mode) +{ + struct procstat *ps; + int i; + int status; + pid_t pgid; + + INTOFF; + if (jp->state == JOBDONE) + goto out; + jp->state = JOBRUNNING; + pgid = jp->ps->pid; + if (mode == FORK_FG) + xtcsetpgrp(ttyfd, pgid); + killpg(pgid, SIGCONT); + ps = jp->ps; + i = jp->nprocs; + do { + if (WIFSTOPPED(ps->status)) { + ps->status = -1; + } + } while (ps++, --i); +out: + status = (mode == FORK_FG) ? waitforjob(jp) : 0; + INTON; + return status; +} +#endif + +static int +sprint_status(char *s, int status, int sigonly) +{ + int col; + int st; + + col = 0; + if (!WIFEXITED(status)) { +#if JOBS + if (WIFSTOPPED(status)) + st = WSTOPSIG(status); + else +#endif + st = WTERMSIG(status); + if (sigonly) { + if (st == SIGINT || st == SIGPIPE) + goto out; +#if JOBS + if (WIFSTOPPED(status)) + goto out; +#endif + } + st &= 0x7f; + col = fmtstr(s, 32, strsignal(st)); + if (WCOREDUMP(status)) { + col += fmtstr(s + col, 16, " (core dumped)"); + } + } else if (!sigonly) { + st = WEXITSTATUS(status); + if (st) + col = fmtstr(s, 16, "Done(%d)", st); + else + col = fmtstr(s, 16, "Done"); + } + +out: + return col; +} + +#if JOBS +static void +showjob(FILE *out, struct job *jp, int mode) +{ + struct procstat *ps; + struct procstat *psend; + int col; + int indent; + char s[80]; + + ps = jp->ps; + + if (mode & SHOW_PGID) { + /* just output process (group) id of pipeline */ + fprintf(out, "%d\n", ps->pid); + return; + } + + col = fmtstr(s, 16, "[%d] ", jobno(jp)); + indent = col; + + if (jp == curjob) + s[col - 2] = '+'; + else if (curjob && jp == curjob->prev_job) + s[col - 2] = '-'; + + if (mode & SHOW_PID) + col += fmtstr(s + col, 16, "%d ", ps->pid); + + psend = ps + jp->nprocs; + + if (jp->state == JOBRUNNING) { + scopy("Running", s + col); + col += strlen("Running"); + } else { + int status = psend[-1].status; +#if JOBS + if (jp->state == JOBSTOPPED) + status = jp->stopstatus; +#endif + col += sprint_status(s + col, status, 0); + } + + goto start; + + do { + /* for each process */ + col = fmtstr(s, 48, " |\n%*c%d ", indent, ' ', ps->pid) - 3; + +start: + fprintf(out, "%s%*c%s", + s, 33 - col >= 0 ? 33 - col : 0, ' ', ps->cmd + ); + if (!(mode & SHOW_PID)) { + showpipe(jp, out); + break; + } + if (++ps == psend) { + outcslow('\n', out); + break; + } + } while (1); + + jp->changed = 0; + + if (jp->state == JOBDONE) { + TRACE(("showjob: freeing job %d\n", jobno(jp))); + freejob(jp); + } +} + + +static int +jobscmd(int argc, char **argv) +{ + int mode, m; + FILE *out; + + mode = 0; + while ((m = nextopt("lp"))) + if (m == 'l') + mode = SHOW_PID; + else + mode = SHOW_PGID; + + out = stdout; + argv = argptr; + if (*argv) + do + showjob(out, getjob(*argv,0), mode); + while (*++argv); + else + showjobs(out, mode); + + return 0; +} + + +/* + * Print a list of jobs. If "change" is nonzero, only print jobs whose + * statuses have changed since the last call to showjobs. + */ + +static void +showjobs(FILE *out, int mode) +{ + struct job *jp; + + TRACE(("showjobs(%x) called\n", mode)); + + /* If not even one one job changed, there is nothing to do */ + while (dowait(DOWAIT_NORMAL, NULL) > 0) + continue; + + for (jp = curjob; jp; jp = jp->prev_job) { + if (!(mode & SHOW_CHANGED) || jp->changed) + showjob(out, jp, mode); + } +} +#endif /* JOBS */ + +/* + * Mark a job structure as unused. + */ + +static void +freejob(struct job *jp) +{ + struct procstat *ps; + int i; + + INTOFF; + for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) { + if (ps->cmd != nullstr) + ckfree(ps->cmd); + } + if (jp->ps != &jp->ps0) + ckfree(jp->ps); + jp->used = 0; + set_curjob(jp, CUR_DELETE); + INTON; +} + + +static int +waitcmd(int argc, char **argv) +{ + struct job *job; + int retval; + struct job *jp; + + EXSIGON(); + + nextopt(nullstr); + retval = 0; + + argv = argptr; + if (!*argv) { + /* wait for all jobs */ + for (;;) { + jp = curjob; + while (1) { + if (!jp) { + /* no running procs */ + goto out; + } + if (jp->state == JOBRUNNING) + break; + jp->waited = 1; + jp = jp->prev_job; + } + dowait(DOWAIT_BLOCK, 0); + } + } + + retval = 127; + do { + if (**argv != '%') { + pid_t pid = number(*argv); + job = curjob; + goto start; + do { + if (job->ps[job->nprocs - 1].pid == pid) + break; + job = job->prev_job; +start: + if (!job) + goto repeat; + } while (1); + } else + job = getjob(*argv, 0); + /* loop until process terminated or stopped */ + while (job->state == JOBRUNNING) + dowait(DOWAIT_BLOCK, 0); + job->waited = 1; + retval = getstatus(job); +repeat: + ; + } while (*++argv); + +out: + return retval; +} + + +/* + * Convert a job name to a job structure. + */ + +static struct job * +getjob(const char *name, int getctl) +{ + struct job *jp; + struct job *found; + const char *err_msg = "No such job: %s"; + unsigned num; + int c; + const char *p; + char *(*match)(const char *, const char *); + + jp = curjob; + p = name; + if (!p) + goto currentjob; + + if (*p != '%') + goto err; + + c = *++p; + if (!c) + goto currentjob; + + if (!p[1]) { + if (c == '+' || c == '%') { +currentjob: + err_msg = "No current job"; + goto check; + } else if (c == '-') { + if (jp) + jp = jp->prev_job; + err_msg = "No previous job"; +check: + if (!jp) + goto err; + goto gotit; + } + } + + if (is_number(p)) { + num = atoi(p); + if (num < njobs) { + jp = jobtab + num - 1; + if (jp->used) + goto gotit; + goto err; + } + } + + match = prefix; + if (*p == '?') { + match = strstr; + p++; + } + + found = 0; + while (1) { + if (!jp) + goto err; + if (match(jp->ps[0].cmd, p)) { + if (found) + goto err; + found = jp; + err_msg = "%s: ambiguous"; + } + jp = jp->prev_job; + } + +gotit: +#if JOBS + err_msg = "job %s not created under job control"; + if (getctl && jp->jobctl == 0) + goto err; +#endif + return jp; +err: + error(err_msg, name); +} + + +/* + * Return a new job structure. + * Called with interrupts off. + */ + +static struct job * +makejob(union node *node, int nprocs) +{ + int i; + struct job *jp; + + for (i = njobs, jp = jobtab ; ; jp++) { + if (--i < 0) { + jp = growjobtab(); + break; + } + if (jp->used == 0) + break; + if (jp->state != JOBDONE || !jp->waited) + continue; +#if JOBS + if (jobctl) + continue; +#endif + freejob(jp); + break; + } + memset(jp, 0, sizeof(*jp)); +#if JOBS + if (jobctl) + jp->jobctl = 1; +#endif + jp->prev_job = curjob; + curjob = jp; + jp->used = 1; + jp->ps = &jp->ps0; + if (nprocs > 1) { + jp->ps = ckmalloc(nprocs * sizeof (struct procstat)); + } + TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs, + jobno(jp))); + return jp; +} + +static struct job * +growjobtab(void) +{ + size_t len; + ptrdiff_t offset; + struct job *jp, *jq; + + len = njobs * sizeof(*jp); + jq = jobtab; + jp = ckrealloc(jq, len + 4 * sizeof(*jp)); + + offset = (char *)jp - (char *)jq; + if (offset) { + /* Relocate pointers */ + size_t l = len; + + jq = (struct job *)((char *)jq + l); + while (l) { + l -= sizeof(*jp); + jq--; +#define joff(p) ((struct job *)((char *)(p) + l)) +#define jmove(p) (p) = (void *)((char *)(p) + offset) + if (likely(joff(jp)->ps == &jq->ps0)) + jmove(joff(jp)->ps); + if (joff(jp)->prev_job) + jmove(joff(jp)->prev_job); + } + if (curjob) + jmove(curjob); +#undef joff +#undef jmove + } + + njobs += 4; + jobtab = jp; + jp = (struct job *)((char *)jp + len); + jq = jp + 3; + do { + jq->used = 0; + } while (--jq >= jp); + return jp; +} + + +/* + * Fork off a subshell. If we are doing job control, give the subshell its + * own process group. Jp is a job structure that the job is to be added to. + * N is the command that will be evaluated by the child. Both jp and n may + * be NULL. The mode parameter can be one of the following: + * FORK_FG - Fork off a foreground process. + * FORK_BG - Fork off a background process. + * FORK_NOJOB - Like FORK_FG, but don't give the process its own + * process group even if job control is on. + * + * When job control is turned off, background processes have their standard + * input redirected to /dev/null (except for the second and later processes + * in a pipeline). + * + * Called with interrupts off. + */ + +static inline void +forkchild(struct job *jp, union node *n, int mode) +{ + int wasroot; + + TRACE(("Child shell %d\n", getpid())); + wasroot = rootshell; + rootshell = 0; + + closescript(); + clear_traps(); +#if JOBS + /* do job control only in root shell */ + jobctl = 0; + if (mode != FORK_NOJOB && jp->jobctl && wasroot) { + pid_t pgrp; + + if (jp->nprocs == 0) + pgrp = getpid(); + else + pgrp = jp->ps[0].pid; + /* This can fail because we are doing it in the parent also */ + (void)setpgid(0, pgrp); + if (mode == FORK_FG) + xtcsetpgrp(ttyfd, pgrp); + setsignal(SIGTSTP); + setsignal(SIGTTOU); + } else +#endif + if (mode == FORK_BG) { + ignoresig(SIGINT); + ignoresig(SIGQUIT); + if (jp->nprocs == 0) { + close(0); + if (open(_PATH_DEVNULL, O_RDONLY) != 0) + error("Can't open %s", _PATH_DEVNULL); + } + } + if (wasroot && iflag) { + setsignal(SIGINT); + setsignal(SIGQUIT); + setsignal(SIGTERM); + } + for (jp = curjob; jp; jp = jp->prev_job) + freejob(jp); + jobless = 0; +} + +static inline void +forkparent(struct job *jp, union node *n, int mode, pid_t pid) +{ + TRACE(("In parent shell: child = %d\n", pid)); + if (!jp) { + while (jobless && dowait(DOWAIT_NORMAL, 0) > 0); + jobless++; + return; + } +#if JOBS + if (mode != FORK_NOJOB && jp->jobctl) { + int pgrp; + + if (jp->nprocs == 0) + pgrp = pid; + else + pgrp = jp->ps[0].pid; + /* This can fail because we are doing it in the child also */ + (void)setpgid(pid, pgrp); + } +#endif + if (mode == FORK_BG) { + backgndpid = pid; /* set $! */ + set_curjob(jp, CUR_RUNNING); + } + if (jp) { + struct procstat *ps = &jp->ps[jp->nprocs++]; + ps->pid = pid; + ps->status = -1; + ps->cmd = nullstr; +#if JOBS + if (jobctl && n) + ps->cmd = commandtext(n); +#endif + } +} + +static int +forkshell(struct job *jp, union node *n, int mode) +{ + int pid; + + TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode)); + pid = fork(); + if (pid < 0) { + TRACE(("Fork failed, errno=%d", errno)); + if (jp) + freejob(jp); + error("Cannot fork"); + } + if (pid == 0) + forkchild(jp, n, mode); + else + forkparent(jp, n, mode, pid); + return pid; +} + +/* + * Wait for job to finish. + * + * Under job control we have the problem that while a child process is + * running interrupts generated by the user are sent to the child but not + * to the shell. This means that an infinite loop started by an inter- + * active user may be hard to kill. With job control turned off, an + * interactive user may place an interactive program inside a loop. If + * the interactive program catches interrupts, the user doesn't want + * these interrupts to also abort the loop. The approach we take here + * is to have the shell ignore interrupt signals while waiting for a + * forground process to terminate, and then send itself an interrupt + * signal if the child process was terminated by an interrupt signal. + * Unfortunately, some programs want to do a bit of cleanup and then + * exit on interrupt; unless these processes terminate themselves by + * sending a signal to themselves (instead of calling exit) they will + * confuse this approach. + * + * Called with interrupts off. + */ + +int +waitforjob(struct job *jp) +{ + int st; + + TRACE(("waitforjob(%%%d) called\n", jobno(jp))); + while (jp->state == JOBRUNNING) { + dowait(DOWAIT_BLOCK, jp); + } + st = getstatus(jp); +#if JOBS + if (jp->jobctl) { + xtcsetpgrp(ttyfd, rootpid); + /* + * This is truly gross. + * If we're doing job control, then we did a TIOCSPGRP which + * caused us (the shell) to no longer be in the controlling + * session -- so we wouldn't have seen any ^C/SIGINT. So, we + * intuit from the subprocess exit status whether a SIGINT + * occurred, and if so interrupt ourselves. Yuck. - mycroft + */ + if (jp->sigint) + raise(SIGINT); + } + if (jp->state == JOBDONE) +#endif + freejob(jp); + return st; +} + + +/* + * Do a wait system call. If job control is compiled in, we accept + * stopped processes. If block is zero, we return a value of zero + * rather than blocking. + * + * System V doesn't have a non-blocking wait system call. It does + * have a SIGCLD signal that is sent to a process when one of it's + * children dies. The obvious way to use SIGCLD would be to install + * a handler for SIGCLD which simply bumped a counter when a SIGCLD + * was received, and have waitproc bump another counter when it got + * the status of a process. Waitproc would then know that a wait + * system call would not block if the two counters were different. + * This approach doesn't work because if a process has children that + * have not been waited for, System V will send it a SIGCLD when it + * installs a signal handler for SIGCLD. What this means is that when + * a child exits, the shell will be sent SIGCLD signals continuously + * until is runs out of stack space, unless it does a wait call before + * restoring the signal handler. The code below takes advantage of + * this (mis)feature by installing a signal handler for SIGCLD and + * then checking to see whether it was called. If there are any + * children to be waited for, it will be. + * + * If neither SYSV nor BSD is defined, we don't implement nonblocking + * waits at all. In this case, the user will not be informed when + * a background process until the next time she runs a real program + * (as opposed to running a builtin command or just typing return), + * and the jobs command may give out of date information. + */ + +static inline int +waitproc(int block, int *status) +{ + int flags = 0; + +#if JOBS + if (jobctl) + flags |= WUNTRACED; +#endif + if (block == 0) + flags |= WNOHANG; + return wait3(status, flags, (struct rusage *)NULL); +} + +/* + * Wait for a process to terminate. + */ + +static int +dowait(int block, struct job *job) +{ + int pid; + int status; + struct job *jp; + struct job *thisjob; + int state; + + TRACE(("dowait(%d) called\n", block)); + pid = waitproc(block, &status); + TRACE(("wait returns pid %d, status=%d\n", pid, status)); + if (pid <= 0) + return pid; + INTOFF; + thisjob = NULL; + for (jp = curjob; jp; jp = jp->prev_job) { + struct procstat *sp; + struct procstat *spend; + if (jp->state == JOBDONE) + continue; + state = JOBDONE; + spend = jp->ps + jp->nprocs; + sp = jp->ps; + do { + if (sp->pid == pid) { + TRACE(("Job %d: changing status of proc %d from 0x%x to 0x%x\n", jobno(jp), pid, sp->status, status)); + sp->status = status; + thisjob = jp; + } + if (sp->status == -1) + state = JOBRUNNING; +#ifdef JOBS + if (state == JOBRUNNING) + continue; + if (WIFSTOPPED(sp->status)) { + jp->stopstatus = sp->status; + state = JOBSTOPPED; + } +#endif + } while (++sp < spend); + if (thisjob) + goto gotjob; + } +#ifdef JOBS + if (!WIFSTOPPED(status)) +#endif + + jobless--; + goto out; + +gotjob: + if (state != JOBRUNNING) { + thisjob->changed = 1; + + if (thisjob->state != state) { + TRACE(("Job %d: changing state from %d to %d\n", jobno(thisjob), thisjob->state, state)); + thisjob->state = state; +#ifdef JOBS + if (state == JOBSTOPPED) { + set_curjob(thisjob, CUR_STOPPED); + } +#endif + } + } + +out: + INTON; + + if (thisjob && thisjob == job) { + char s[48 + 1]; + int len; + + len = sprint_status(s, status, 1); + if (len) { + s[len] = '\n'; + s[len + 1] = 0; + out2str(s); + } + } + return pid; +} + + +/* + * return 1 if there are stopped jobs, otherwise 0 + */ + +int +stoppedjobs(void) +{ + struct job *jp; + int retval; + + retval = 0; + if (job_warning) + goto out; + jp = curjob; + if (jp && jp->state == JOBSTOPPED) { + out2str("You have stopped jobs.\n"); + job_warning = 2; + retval++; + } + +out: + return retval; +} + +/* + * Return a string identifying a command (to be printed by the + * jobs command). + */ + +#if JOBS +static char *cmdnextc; + +static char * +commandtext(union node *n) +{ + char *name; + + STARTSTACKSTR(cmdnextc); + cmdtxt(n); + name = stackblock(); + TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n", + name, cmdnextc, cmdnextc)); + return savestr(name); +} + +static void +cmdtxt(union node *n) +{ + union node *np; + struct nodelist *lp; + const char *p; + char s[2]; + + switch (n->type) { + default: +#if DEBUG + abort(); +#endif + case NPIPE: + lp = n->npipe.cmdlist; + for (;;) { + cmdtxt(lp->n); + lp = lp->next; + if (!lp) + break; + cmdputs(" | "); + } + break; + case NSEMI: + p = "; "; + goto binop; + case NAND: + p = " && "; + goto binop; + case NOR: + p = " || "; +binop: + cmdtxt(n->nbinary.ch1); + cmdputs(p); + n = n->nbinary.ch2; + goto donode; + case NREDIR: + case NBACKGND: + n = n->nredir.n; + goto donode; + case NNOT: + cmdputs("!"); + n = n->nnot.com; +donode: + cmdtxt(n); + break; + case NIF: + cmdputs("if "); + cmdtxt(n->nif.test); + cmdputs("; then "); + n = n->nif.ifpart; + if (n->nif.elsepart) { + cmdtxt(n); + cmdputs("; else "); + n = n->nif.elsepart; + } + p = "; fi"; + goto dotail; + case NSUBSHELL: + cmdputs("("); + n = n->nredir.n; + p = ")"; + goto dotail; + case NWHILE: + p = "while "; + goto until; + case NUNTIL: + p = "until "; +until: + cmdputs(p); + cmdtxt(n->nbinary.ch1); + n = n->nbinary.ch2; + p = "; done"; +dodo: + cmdputs("; do "); +dotail: + cmdtxt(n); + goto dotail2; + case NFOR: + cmdputs("for "); + cmdputs(n->nfor.var); + cmdputs(" in "); + cmdlist(n->nfor.args, 1); + n = n->nfor.body; + p = "; done"; + goto dodo; + case NDEFUN: + cmdputs(n->narg.text); + p = "() { ... }"; + goto dotail2; + case NCMD: + cmdlist(n->ncmd.args, 1); + cmdlist(n->ncmd.redirect, 0); + break; + case NARG: + p = n->narg.text; +dotail2: + cmdputs(p); + break; + case NHERE: + case NXHERE: + p = "<<..."; + goto dotail2; + case NCASE: + cmdputs("case "); + cmdputs(n->ncase.expr->narg.text); + cmdputs(" in "); + for (np = n->ncase.cases; np; np = np->nclist.next) { + cmdtxt(np->nclist.pattern); + cmdputs(") "); + cmdtxt(np->nclist.body); + cmdputs(";; "); + } + p = "esac"; + goto dotail2; + case NTO: + p = ">"; + goto redir; + case NCLOBBER: + p = ">|"; + goto redir; + case NAPPEND: + p = ">>"; + goto redir; + case NTOFD: + p = ">&"; + goto redir; + case NFROM: + p = "<"; + goto redir; + case NFROMFD: + p = "<&"; + goto redir; + case NFROMTO: + p = "<>"; +redir: + s[0] = n->nfile.fd + '0'; + s[1] = '\0'; + cmdputs(s); + cmdputs(p); + if (n->type == NTOFD || n->type == NFROMFD) { + s[0] = n->ndup.dupfd + '0'; + p = s; + goto dotail2; + } else { + n = n->nfile.fname; + goto donode; + } + } +} + +static void +cmdlist(union node *np, int sep) +{ + for (; np; np = np->narg.next) { + if (!sep) + cmdputs(spcstr); + cmdtxt(np); + if (sep && np->narg.next) + cmdputs(spcstr); + } +} + +static void +cmdputs(const char *s) +{ + const char *p, *str; + char c, cc[2] = " "; + char *nextc; + int subtype = 0; + int quoted = 0; + static const char *const vstype[16] = { + nullstr, "}", "-", "+", "?", "=", + "#", "##", "%", "%%" + }; + + nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc); + p = s; + while ((c = *p++) != 0) { + str = 0; + switch (c) { + case CTLESC: + c = *p++; + break; + case CTLVAR: + subtype = *p++; + if ((subtype & VSTYPE) == VSLENGTH) + str = "${#"; + else + str = "${"; + if (!(subtype & VSQUOTE) != !(quoted & 1)) { + quoted ^= 1; + c = '"'; + } else + goto dostr; + break; + case CTLENDVAR: + quoted >>= 1; + subtype = 0; + if (quoted & 1) { + str = "\"}"; + goto dostr; + } + c = '}'; + break; + case CTLBACKQ: + str = "$(...)"; + goto dostr; + case CTLBACKQ+CTLQUOTE: + str = "\"$(...)\""; + goto dostr; +#ifdef BB_ASH_MATH_SUPPORT + case CTLARI: + str = "$(("; + goto dostr; + case CTLENDARI: + str = "))"; + goto dostr; +#endif + case CTLQUOTEMARK: + quoted ^= 1; + c = '"'; + break; + case '=': + if (subtype == 0) + break; + str = vstype[subtype & VSTYPE]; + if (subtype & VSNUL) + c = ':'; + else + c = *str++; + if (c != '}') + quoted <<= 1; + break; + case '\'': + case '\\': + case '"': + case '$': + /* These can only happen inside quotes */ + cc[0] = c; + str = cc; + c = '\\'; + break; + default: + break; + } + USTPUTC(c, nextc); + if (!str) + continue; +dostr: + while ((c = *str++)) { + USTPUTC(c, nextc); + } + } + if (quoted & 1) { + USTPUTC('"', nextc); + } + *nextc = 0; + cmdnextc = nextc; +} + + +static void +showpipe(struct job *jp, FILE *out) +{ + struct procstat *sp; + struct procstat *spend; + + spend = jp->ps + jp->nprocs; + for (sp = jp->ps + 1; sp < spend; sp++) + fprintf(out, " | %s", sp->cmd); + outcslow('\n', out); + flushall(); +} + +static void +xtcsetpgrp(int fd, pid_t pgrp) +{ + if (tcsetpgrp(fd, pgrp)) + error("Cannot set tty process group (%m)"); +} +#endif /* JOBS */ + +static int +getstatus(struct job *job) { + int status; + int retval; + + status = job->ps[job->nprocs - 1].status; + retval = WEXITSTATUS(status); + if (!WIFEXITED(status)) { +#if JOBS + retval = WSTOPSIG(status); + if (!WIFSTOPPED(status)) +#endif + { + /* XXX: limits number of signals */ + retval = WTERMSIG(status); +#if JOBS + if (retval == SIGINT) + job->sigint = 1; +#endif + } + retval += 128; + } + TRACE(("getstatus: job %d, nproc %d, status %x, retval %x\n", + jobno(job), job->nprocs, status, retval)); + return retval; +} + +#ifdef BB_ASH_MAIL +/* $NetBSD: mail.c,v 1.15 2002/11/24 22:35:40 christos Exp $ */ + +/* + * Routines to check for mail. (Perhaps make part of main.c?) + */ + +#define MAXMBOXES 10 + +/* times of mailboxes */ +static time_t mailtime[MAXMBOXES]; +/* Set if MAIL or MAILPATH is changed. */ +static int mail_var_path_changed; + + + +/* + * Print appropriate message(s) if mail has arrived. + * If mail_var_path_changed is set, + * then the value of MAIL has mail_var_path_changed, + * so we just update the values. + */ + +static void +chkmail(void) +{ + const char *mpath; + char *p; + char *q; + time_t *mtp; + struct stackmark smark; + struct stat statb; + + setstackmark(&smark); + mpath = mpathset() ? mpathval() : mailval(); + for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) { + p = padvance(&mpath, nullstr); + if (p == NULL) + break; + if (*p == '\0') + continue; + for (q = p ; *q ; q++); +#ifdef DEBUG + if (q[-1] != '/') + abort(); +#endif + q[-1] = '\0'; /* delete trailing '/' */ + if (stat(p, &statb) < 0) { + *mtp = 0; + continue; + } + if (!mail_var_path_changed && statb.st_mtime != *mtp) { + fprintf( + stderr, snlfmt, + pathopt ? pathopt : "you have mail" + ); + } + *mtp = statb.st_mtime; + } + mail_var_path_changed = 0; + popstackmark(&smark); +} + + +static void +changemail(const char *val) +{ + mail_var_path_changed++; +} + +#endif /* BB_ASH_MAIL */ + +/* $NetBSD: main.c,v 1.46 2002/12/11 19:12:18 christos Exp $ */ + + +#if PROFILE +static short profile_buf[16384]; +extern int etext(); +#endif + +static int isloginsh; + +static void read_profile(const char *); + +/* + * Main routine. We initialize things, parse the arguments, execute + * profiles if we're a login shell, and then call cmdloop to execute + * commands. The setjmp call sets up the location to jump to when an + * exception occurs. When an exception occurs the variable "state" + * is used to figure out how far we had gotten. + */ + +int +ash_main(int argc, char **argv) +{ + char *shinit; + volatile int state; + struct jmploc jmploc; + struct stackmark smark; + +#ifdef __GLIBC__ + dash_errno = __errno_location(); +#endif + +#if PROFILE + monitor(4, etext, profile_buf, sizeof profile_buf, 50); +#endif + state = 0; + if (setjmp(jmploc.loc)) { + int status; + int e; + + reset(); + + e = exception; + switch (exception) { + case EXEXEC: + status = exerrno; + break; + + case EXERROR: + status = 2; + break; + + default: + status = exitstatus; + break; + } + exitstatus = status; + + if (e == EXEXIT || state == 0 || iflag == 0 || ! rootshell) + exitshell(); + + if (e == EXINT) { + outcslow('\n', stderr); + } + popstackmark(&smark); + FORCEINTON; /* enable interrupts */ + if (state == 1) + goto state1; + else if (state == 2) + goto state2; + else if (state == 3) + goto state3; + else + goto state4; + } + handler = &jmploc; +#ifdef DEBUG + opentrace(); + trputs("Shell args: "); trargs(argv); +#endif + rootpid = getpid(); + rootshell = 1; + init(); + setstackmark(&smark); + procargs(argc, argv); +#ifdef BB_FEATURE_COMMAND_SAVEHISTORY + if ( iflag ) { + const char *hp = lookupvar("HISTFILE"); + + if(hp == NULL ) { + hp = lookupvar("HOME"); + if(hp != NULL) { + char *defhp = concat_path_file(hp, ".ash_history"); + setvar("HISTFILE", defhp, 0); + free(defhp); + } + } + } +#endif + if (argv[0] && argv[0][0] == '-') + isloginsh = 1; + if (isloginsh) { + state = 1; + read_profile("/etc/profile"); +state1: + state = 2; + read_profile(".profile"); + } +state2: + state = 3; + if ( +#ifndef linux + getuid() == geteuid() && getgid() == getegid() && +#endif + iflag + ) { + if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { + read_profile(shinit); + } + } +state3: + state = 4; + if (minusc) + evalstring(minusc, 0); + + if (sflag || minusc == NULL) { +#ifdef BB_FEATURE_COMMAND_SAVEHISTORY + if ( iflag ) { + const char *hp = lookupvar("HISTFILE"); + + if(hp != NULL ) + load_history ( hp ); + } +#endif +state4: /* XXX ??? - why isn't this before the "if" statement */ + cmdloop(1); + } +#if PROFILE + monitor(0); +#endif +#if GPROF + { + extern void _mcleanup(void); + _mcleanup(); + } +#endif + exitshell(); + /* NOTREACHED */ +} + + +/* + * Read and execute commands. "Top" is nonzero for the top level command + * loop; it turns on prompting if the shell is interactive. + */ + +static void +cmdloop(int top) +{ + union node *n; + struct stackmark smark; + int inter; + int numeof = 0; + + TRACE(("cmdloop(%d) called\n", top)); + setstackmark(&smark); + for (;;) { + if (pendingsigs) + dotrap(); +#if JOBS + if (jobctl) + showjobs(stderr, SHOW_CHANGED); +#endif + inter = 0; + if (iflag && top) { + inter++; +#ifdef BB_ASH_MAIL + chkmail(); +#endif + } + n = parsecmd(inter); + /* showtree(n); DEBUG */ + if (n == NEOF) { + if (!top || numeof >= 50) + break; + if (!stoppedjobs()) { + if (!Iflag) + break; + out2str("\nUse \"exit\" to leave shell.\n"); + } + numeof++; + } else if (n != NULL && nflag == 0) { + job_warning = (job_warning == 2) ? 1 : 0; + numeof = 0; + evaltree(n, 0); + } + popstackmark(&smark); + setstackmark(&smark); + if (evalskip == SKIPFILE) { + evalskip = 0; + break; + } + } + popstackmark(&smark); +} + + +/* + * Read /etc/profile or .profile. Return on error. + */ + +static void +read_profile(const char *name) +{ + int fd; + int xflag_set = 0; + int vflag_set = 0; + + INTOFF; + if ((fd = open(name, O_RDONLY)) >= 0) + setinputfd(fd, 1); + INTON; + if (fd < 0) + return; + /* -q turns off -x and -v just when executing init files */ + if (qflag) { + if (xflag) + xflag = 0, xflag_set = 1; + if (vflag) + vflag = 0, vflag_set = 1; + } + cmdloop(0); + if (qflag) { + if (xflag_set) + xflag = 1; + if (vflag_set) + vflag = 1; + } + popfile(); +} + + +/* + * Read a file containing shell functions. + */ + +static void +readcmdfile(char *name) +{ + int fd; + + INTOFF; + if ((fd = open(name, O_RDONLY)) >= 0) + setinputfd(fd, 1); + else + error("Can't open %s", name); + INTON; + cmdloop(0); + popfile(); +} + + +/* + * Take commands from a file. To be compatible we should do a path + * search for the file, which is necessary to find sub-commands. + */ + +static inline char * +find_dot_file(char *name) +{ + char *fullname; + const char *path = pathval(); + struct stat statb; + + /* don't try this for absolute or relative paths */ + if (strchr(name, '/')) + return name; + + while ((fullname = padvance(&path, name)) != NULL) { + if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { + /* + * Don't bother freeing here, since it will + * be freed by the caller. + */ + return fullname; + } + stunalloc(fullname); + } + + /* not found in the PATH */ + error(not_found_msg, name); + /* NOTREACHED */ +} + +int +dotcmd(int argc, char **argv) +{ + exitstatus = 0; + + if (argc >= 2) { /* That's what SVR2 does */ + char *fullname; + struct stackmark smark; + + setstackmark(&smark); + fullname = find_dot_file(argv[1]); + setinputfile(fullname, 1); + commandname = fullname; + cmdloop(0); + popfile(); + popstackmark(&smark); + } + return exitstatus; +} + + +static int +exitcmd(int argc, char **argv) +{ + if (stoppedjobs()) + return 0; + if (argc > 1) + exitstatus = number(argv[1]); + exraise(EXEXIT); + /* NOTREACHED */ +} + +/* $NetBSD: memalloc.c,v 1.27 2003/01/22 20:36:04 dsl Exp $ */ + +/* + * Same for malloc, realloc, but returns an error when out of space. + */ + +static pointer +ckrealloc(pointer p, size_t nbytes) +{ + p = realloc(p, nbytes); + if (p == NULL) + error(memory_exhausted); + return p; +} + +static pointer +ckmalloc(size_t nbytes) +{ + return ckrealloc(NULL, nbytes); +} + +/* + * Make a copy of a string in safe storage. + */ + +static char * +savestr(const char *s) +{ + char *p = strdup(s); + if (!p) + error(memory_exhausted); + return p; +} + + +/* + * Parse trees for commands are allocated in lifo order, so we use a stack + * to make this more efficient, and also to avoid all sorts of exception + * handling code to handle interrupts in the middle of a parse. + * + * The size 504 was chosen because the Ultrix malloc handles that size + * well. + */ + + +static pointer +stalloc(size_t nbytes) +{ + char *p; + size_t aligned; + + aligned = SHELL_ALIGN(nbytes); + if (aligned > stacknleft) { + size_t len; + size_t blocksize; + struct stack_block *sp; + + blocksize = aligned; + if (blocksize < MINSIZE) + blocksize = MINSIZE; + len = sizeof(struct stack_block) - MINSIZE + blocksize; + if (len < blocksize) + error(memory_exhausted); + INTOFF; + sp = ckmalloc(len); + sp->prev = stackp; + stacknxt = sp->space; + stacknleft = blocksize; + sstrend = stacknxt + blocksize; + stackp = sp; + INTON; + } + p = stacknxt; + stacknxt += aligned; + stacknleft -= aligned; + return p; +} + + +void +stunalloc(pointer p) +{ +#ifdef DEBUG + if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) { + write(2, "stunalloc\n", 10); + abort(); + } +#endif + stacknleft += stacknxt - (char *)p; + stacknxt = p; +} + + +void +setstackmark(struct stackmark *mark) +{ + mark->stackp = stackp; + mark->stacknxt = stacknxt; + mark->stacknleft = stacknleft; + mark->marknext = markp; + markp = mark; +} + + +void +popstackmark(struct stackmark *mark) +{ + struct stack_block *sp; + + INTOFF; + markp = mark->marknext; + while (stackp != mark->stackp) { + sp = stackp; + stackp = sp->prev; + ckfree(sp); + } + stacknxt = mark->stacknxt; + stacknleft = mark->stacknleft; + sstrend = mark->stacknxt + mark->stacknleft; + INTON; +} + + +/* + * When the parser reads in a string, it wants to stick the string on the + * stack and only adjust the stack pointer when it knows how big the + * string is. Stackblock (defined in stack.h) returns a pointer to a block + * of space on top of the stack and stackblocklen returns the length of + * this block. Growstackblock will grow this space by at least one byte, + * possibly moving it (like realloc). Grabstackblock actually allocates the + * part of the block that has been used. + */ + +void +growstackblock(void) +{ + size_t newlen; + + newlen = stacknleft * 2; + if (newlen < stacknleft) + error(memory_exhausted); + if (newlen < 128) + newlen += 128; + + if (stacknxt == stackp->space && stackp != &stackbase) { + struct stack_block *oldstackp; + struct stackmark *xmark; + struct stack_block *sp; + struct stack_block *prevstackp; + size_t grosslen; + + INTOFF; + oldstackp = stackp; + sp = stackp; + prevstackp = sp->prev; + grosslen = newlen + sizeof(struct stack_block) - MINSIZE; + sp = ckrealloc((pointer)sp, grosslen); + sp->prev = prevstackp; + stackp = sp; + stacknxt = sp->space; + stacknleft = newlen; + sstrend = sp->space + newlen; + + /* + * Stack marks pointing to the start of the old block + * must be relocated to point to the new block + */ + xmark = markp; + while (xmark != NULL && xmark->stackp == oldstackp) { + xmark->stackp = stackp; + xmark->stacknxt = stacknxt; + xmark->stacknleft = stacknleft; + xmark = xmark->marknext; + } + INTON; + } else { + char *oldspace = stacknxt; + int oldlen = stacknleft; + char *p = stalloc(newlen); + + /* free the space we just allocated */ + stacknxt = memcpy(p, oldspace, oldlen); + stacknleft += newlen; + } +} + +static inline void +grabstackblock(size_t len) +{ + len = SHELL_ALIGN(len); + stacknxt += len; + stacknleft -= len; +} + +/* + * The following routines are somewhat easier to use than the above. + * The user declares a variable of type STACKSTR, which may be declared + * to be a register. The macro STARTSTACKSTR initializes things. Then + * the user uses the macro STPUTC to add characters to the string. In + * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is + * grown as necessary. When the user is done, she can just leave the + * string there and refer to it using stackblock(). Or she can allocate + * the space for it using grabstackstr(). If it is necessary to allow + * someone else to use the stack temporarily and then continue to grow + * the string, the user should use grabstack to allocate the space, and + * then call ungrabstr(p) to return to the previous mode of operation. + * + * USTPUTC is like STPUTC except that it doesn't check for overflow. + * CHECKSTACKSPACE can be called before USTPUTC to ensure that there + * is space for at least one character. + */ + +void * +growstackstr(void) +{ + size_t len = stackblocksize(); + if (herefd >= 0 && len >= 1024) { + xwrite(herefd, stackblock(), len); + return stackblock(); + } + growstackblock(); + return stackblock() + len; +} + +/* + * Called from CHECKSTRSPACE. + */ + +char * +makestrspace(size_t newlen, char *p) +{ + size_t len = p - stacknxt; + size_t size = stackblocksize(); + + for (;;) { + size_t nleft; + + size = stackblocksize(); + nleft = size - len; + if (nleft >= newlen) + break; + growstackblock(); + } + return stackblock() + len; +} + +char * +stnputs(const char *s, size_t n, char *p) +{ + p = makestrspace(n, p); + p = mempcpy(p, s, n); + return p; +} + +char * +stputs(const char *s, char *p) +{ + return stnputs(s, strlen(s), p); +} + +/* $NetBSD: mystring.c,v 1.15 2002/11/24 22:35:42 christos Exp $ */ + +/* + * String functions. + * + * number(s) Convert a string of digits to an integer. + * is_number(s) Return true if s is a string of digits. + */ + +/* + * prefix -- see if pfx is a prefix of string. + */ + +char * +prefix(const char *string, const char *pfx) +{ + while (*pfx) { + if (*pfx++ != *string++) + return 0; + } + return (char *) string; +} + + +/* + * Convert a string of digits to an integer, printing an error message on + * failure. + */ + +int +number(const char *s) +{ + + if (! is_number(s)) + error(illnum, s); + return atoi(s); +} + + +/* + * Check for a valid number. This should be elsewhere. + */ + +int +is_number(const char *p) +{ + do { + if (! is_digit(*p)) + return 0; + } while (*++p != '\0'); + return 1; +} + + +/* + * Produce a possibly single quoted string suitable as input to the shell. + * The return string is allocated on the stack. + */ + +char * +single_quote(const char *s) { + char *p; + + STARTSTACKSTR(p); + + do { + char *q; + size_t len; + + len = strchrnul(s, '\'') - s; + + q = p = makestrspace(len + 3, p); + + *q++ = '\''; + q = mempcpy(q, s, len); + *q++ = '\''; + s += len; + + STADJUST(q - p, p); + + len = strspn(s, "'"); + if (!len) + break; + + q = p = makestrspace(len + 3, p); + + *q++ = '"'; + q = mempcpy(q, s, len); + *q++ = '"'; + s += len; + + STADJUST(q - p, p); + } while (*s); + + USTPUTC(0, p); + + return stackblock(); +} + +/* + * Like strdup but works with the ash stack. + */ + +char * +sstrdup(const char *p) +{ + size_t len = strlen(p) + 1; + return memcpy(stalloc(len), p, len); +} + + +static void +calcsize(union node *n) +{ + if (n == NULL) + return; + funcblocksize += nodesize[n->type]; + switch (n->type) { + case NCMD: + calcsize(n->ncmd.redirect); + calcsize(n->ncmd.args); + calcsize(n->ncmd.assign); + break; + case NPIPE: + sizenodelist(n->npipe.cmdlist); + break; + case NREDIR: + case NBACKGND: + case NSUBSHELL: + calcsize(n->nredir.redirect); + calcsize(n->nredir.n); + break; + case NAND: + case NOR: + case NSEMI: + case NWHILE: + case NUNTIL: + calcsize(n->nbinary.ch2); + calcsize(n->nbinary.ch1); + break; + case NIF: + calcsize(n->nif.elsepart); + calcsize(n->nif.ifpart); + calcsize(n->nif.test); + break; + case NFOR: + funcstringsize += strlen(n->nfor.var) + 1; + calcsize(n->nfor.body); + calcsize(n->nfor.args); + break; + case NCASE: + calcsize(n->ncase.cases); + calcsize(n->ncase.expr); + break; + case NCLIST: + calcsize(n->nclist.body); + calcsize(n->nclist.pattern); + calcsize(n->nclist.next); + break; + case NDEFUN: + case NARG: + sizenodelist(n->narg.backquote); + funcstringsize += strlen(n->narg.text) + 1; + calcsize(n->narg.next); + break; + case NTO: + case NCLOBBER: + case NFROM: + case NFROMTO: + case NAPPEND: + calcsize(n->nfile.fname); + calcsize(n->nfile.next); + break; + case NTOFD: + case NFROMFD: + calcsize(n->ndup.vname); + calcsize(n->ndup.next); + break; + case NHERE: + case NXHERE: + calcsize(n->nhere.doc); + calcsize(n->nhere.next); + break; + case NNOT: + calcsize(n->nnot.com); + break; + }; +} + + +static void +sizenodelist(struct nodelist *lp) +{ + while (lp) { + funcblocksize += SHELL_ALIGN(sizeof(struct nodelist)); + calcsize(lp->n); + lp = lp->next; + } +} + + +static union node * +copynode(union node *n) +{ + union node *new; + + if (n == NULL) + return NULL; + new = funcblock; + funcblock = (char *) funcblock + nodesize[n->type]; + switch (n->type) { + case NCMD: + new->ncmd.redirect = copynode(n->ncmd.redirect); + new->ncmd.args = copynode(n->ncmd.args); + new->ncmd.assign = copynode(n->ncmd.assign); + break; + case NPIPE: + new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); + new->npipe.backgnd = n->npipe.backgnd; + break; + case NREDIR: + case NBACKGND: + case NSUBSHELL: + new->nredir.redirect = copynode(n->nredir.redirect); + new->nredir.n = copynode(n->nredir.n); + break; + case NAND: + case NOR: + case NSEMI: + case NWHILE: + case NUNTIL: + new->nbinary.ch2 = copynode(n->nbinary.ch2); + new->nbinary.ch1 = copynode(n->nbinary.ch1); + break; + case NIF: + new->nif.elsepart = copynode(n->nif.elsepart); + new->nif.ifpart = copynode(n->nif.ifpart); + new->nif.test = copynode(n->nif.test); + break; + case NFOR: + new->nfor.var = nodesavestr(n->nfor.var); + new->nfor.body = copynode(n->nfor.body); + new->nfor.args = copynode(n->nfor.args); + break; + case NCASE: + new->ncase.cases = copynode(n->ncase.cases); + new->ncase.expr = copynode(n->ncase.expr); + break; + case NCLIST: + new->nclist.body = copynode(n->nclist.body); + new->nclist.pattern = copynode(n->nclist.pattern); + new->nclist.next = copynode(n->nclist.next); + break; + case NDEFUN: + case NARG: + new->narg.backquote = copynodelist(n->narg.backquote); + new->narg.text = nodesavestr(n->narg.text); + new->narg.next = copynode(n->narg.next); + break; + case NTO: + case NCLOBBER: + case NFROM: + case NFROMTO: + case NAPPEND: + new->nfile.fname = copynode(n->nfile.fname); + new->nfile.fd = n->nfile.fd; + new->nfile.next = copynode(n->nfile.next); + break; + case NTOFD: + case NFROMFD: + new->ndup.vname = copynode(n->ndup.vname); + new->ndup.dupfd = n->ndup.dupfd; + new->ndup.fd = n->ndup.fd; + new->ndup.next = copynode(n->ndup.next); + break; + case NHERE: + case NXHERE: + new->nhere.doc = copynode(n->nhere.doc); + new->nhere.fd = n->nhere.fd; + new->nhere.next = copynode(n->nhere.next); + break; + case NNOT: + new->nnot.com = copynode(n->nnot.com); + break; + }; + new->type = n->type; + return new; +} + + +static struct nodelist * +copynodelist(struct nodelist *lp) +{ + struct nodelist *start; + struct nodelist **lpp; + + lpp = &start; + while (lp) { + *lpp = funcblock; + funcblock = (char *) funcblock + + SHELL_ALIGN(sizeof(struct nodelist)); + (*lpp)->n = copynode(lp->n); + lp = lp->next; + lpp = &(*lpp)->next; + } + *lpp = NULL; + return start; +} + + +static char * +nodesavestr(char *s) +{ + char *rtn = funcstring; + + funcstring = stpcpy(funcstring, s) + 1; + return rtn; +} + + +/* + * Free a parse tree. + */ + +static void +freefunc(struct funcnode *f) +{ + if (f && --f->count < 0) + ckfree(f); +} + + +static void options(int); +static void setoption(int, int); + + +/* + * Process the shell command line arguments. + */ + +void +procargs(int argc, char **argv) +{ + int i; + const char *xminusc; + char **xargv; + + xargv = argv; + arg0 = xargv[0]; + if (argc > 0) + xargv++; + for (i = 0; i < NOPTS; i++) + optlist[i] = 2; + argptr = xargv; + options(1); + xargv = argptr; + xminusc = minusc; + if (*xargv == NULL) { + if (xminusc) + error("-c requires an argument"); + sflag = 1; + } + if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) + iflag = 1; + if (mflag == 2) + mflag = iflag; + for (i = 0; i < NOPTS; i++) + if (optlist[i] == 2) + optlist[i] = 0; +#if DEBUG == 2 + debug = 1; +#endif + /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ + if (xminusc) { + minusc = *xargv++; + if (*xargv) + goto setarg0; + } else if (!sflag) { + setinputfile(*xargv, 0); +setarg0: + arg0 = *xargv++; + commandname = arg0; + } + + shellparam.p = xargv; +#ifdef BB_ASH_GETOPTS + shellparam.optind = 1; + shellparam.optoff = -1; +#endif + /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ + while (*xargv) { + shellparam.nparam++; + xargv++; + } + optschanged(); +} + + +void +optschanged(void) +{ +#ifdef DEBUG + opentrace(); +#endif + setinteractive(iflag); + setjobctl(mflag); +} + +static inline void +minus_o(char *name, int val) +{ + int i; + + if (name == NULL) { + out1str("Current option settings\n"); + for (i = 0; i < NOPTS; i++) + out1fmt("%-16s%s\n", optnames(i), + optlist[i] ? "on" : "off"); + } else { + for (i = 0; i < NOPTS; i++) + if (equal(name, optnames(i))) { + optlist[i] = val; + return; + } + error("Illegal option -o %s", name); + } +} + +/* + * Process shell options. The global variable argptr contains a pointer + * to the argument list; we advance it past the options. + */ + +static void +options(int cmdline) +{ + char *p; + int val; + int c; + + if (cmdline) + minusc = NULL; + while ((p = *argptr) != NULL) { + argptr++; + if ((c = *p++) == '-') { + val = 1; + if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { + if (!cmdline) { + /* "-" means turn off -x and -v */ + if (p[0] == '\0') + xflag = vflag = 0; + /* "--" means reset params */ + else if (*argptr == NULL) + setparam(argptr); + } + break; /* "-" or "--" terminates options */ + } + } else if (c == '+') { + val = 0; + } else { + argptr--; + break; + } + while ((c = *p++) != '\0') { + if (c == 'c' && cmdline) { + minusc = p; /* command is after shell args*/ + } else if (c == 'o') { + minus_o(*argptr, val); + if (*argptr) + argptr++; + } else if (cmdline && (c == '-')) { // long options + if (strcmp(p, "login") == 0) + isloginsh = 1; + break; + } else { + setoption(c, val); + } + } + } +} + + +static void +setoption(int flag, int val) +{ + int i; + + for (i = 0; i < NOPTS; i++) + if (optletters(i) == flag) { + optlist[i] = val; + return; + } + error("Illegal option -%c", flag); + /* NOTREACHED */ +} + + + +/* + * Set the shell parameters. + */ + +void +setparam(char **argv) +{ + char **newparam; + char **ap; + int nparam; + + for (nparam = 0 ; argv[nparam] ; nparam++); + ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); + while (*argv) { + *ap++ = savestr(*argv++); + } + *ap = NULL; + freeparam(&shellparam); + shellparam.malloc = 1; + shellparam.nparam = nparam; + shellparam.p = newparam; +#ifdef BB_ASH_GETOPTS + shellparam.optind = 1; + shellparam.optoff = -1; +#endif +} + + +/* + * Free the list of positional parameters. + */ + +void +freeparam(volatile struct shparam *param) +{ + char **ap; + + if (param->malloc) { + for (ap = param->p ; *ap ; ap++) + ckfree(*ap); + ckfree(param->p); + } +} + + + +/* + * The shift builtin command. + */ + +int +shiftcmd(int argc, char **argv) +{ + int n; + char **ap1, **ap2; + + n = 1; + if (argc > 1) + n = number(argv[1]); + if (n > shellparam.nparam) + error("can't shift that many"); + INTOFF; + shellparam.nparam -= n; + for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { + if (shellparam.malloc) + ckfree(*ap1); + } + ap2 = shellparam.p; + while ((*ap2++ = *ap1++) != NULL); +#ifdef BB_ASH_GETOPTS + shellparam.optind = 1; + shellparam.optoff = -1; +#endif + INTON; + return 0; +} + + + +/* + * The set command builtin. + */ + +int +setcmd(int argc, char **argv) +{ + if (argc == 1) + return showvars(nullstr, 0, VUNSET); + INTOFF; + options(0); + optschanged(); + if (*argptr != NULL) { + setparam(argptr); + } + INTON; + return 0; +} + + +#ifdef BB_ASH_GETOPTS +static void +getoptsreset(value) + const char *value; +{ + shellparam.optind = number(value); + shellparam.optoff = -1; +} +#endif + +#ifdef BB_LOCALE_SUPPORT +static void change_lc_all(const char *value) +{ + if (value != 0 && *value != 0) + setlocale(LC_ALL, value); +} + +static void change_lc_ctype(const char *value) +{ + if (value != 0 && *value != 0) + setlocale(LC_CTYPE, value); +} + +#endif + +#ifdef BB_ASH_GETOPTS +static int +getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff) +{ + char *p, *q; + char c = '?'; + int done = 0; + int err = 0; + char s[12]; + char **optnext; + + if(*param_optind < 1) + return 1; + optnext = optfirst + *param_optind - 1; + + if (*param_optind <= 1 || *optoff < 0 || strlen(optnext[-1]) < *optoff) + p = NULL; + else + p = optnext[-1] + *optoff; + if (p == NULL || *p == '\0') { + /* Current word is done, advance */ + p = *optnext; + if (p == NULL || *p != '-' || *++p == '\0') { +atend: + p = NULL; + done = 1; + goto out; + } + optnext++; + if (p[0] == '-' && p[1] == '\0') /* check for "--" */ + goto atend; + } + + c = *p++; + for (q = optstr; *q != c; ) { + if (*q == '\0') { + if (optstr[0] == ':') { + s[0] = c; + s[1] = '\0'; + err |= setvarsafe("OPTARG", s, 0); + } else { + fprintf(stderr, "Illegal option -%c\n", c); + (void) unsetvar("OPTARG"); + } + c = '?'; + goto out; + } + if (*++q == ':') + q++; + } + + if (*++q == ':') { + if (*p == '\0' && (p = *optnext) == NULL) { + if (optstr[0] == ':') { + s[0] = c; + s[1] = '\0'; + err |= setvarsafe("OPTARG", s, 0); + c = ':'; + } else { + fprintf(stderr, "No arg for -%c option\n", c); + (void) unsetvar("OPTARG"); + c = '?'; + } + goto out; + } + + if (p == *optnext) + optnext++; + err |= setvarsafe("OPTARG", p, 0); + p = NULL; + } else + err |= setvarsafe("OPTARG", nullstr, 0); + +out: + *optoff = p ? p - *(optnext - 1) : -1; + *param_optind = optnext - optfirst + 1; + fmtstr(s, sizeof(s), "%d", *param_optind); + err |= setvarsafe("OPTIND", s, VNOFUNC); + s[0] = c; + s[1] = '\0'; + err |= setvarsafe(optvar, s, 0); + if (err) { + *param_optind = 1; + *optoff = -1; + flushall(); + exraise(EXERROR); + } + return done; +} + +/* + * The getopts builtin. Shellparam.optnext points to the next argument + * to be processed. Shellparam.optptr points to the next character to + * be processed in the current argument. If shellparam.optnext is NULL, + * then it's the first time getopts has been called. + */ + +int +getoptscmd(int argc, char **argv) +{ + char **optbase; + + if (argc < 3) + error("Usage: getopts optstring var [arg]"); + else if (argc == 3) { + optbase = shellparam.p; + if (shellparam.optind > shellparam.nparam + 1) { + shellparam.optind = 1; + shellparam.optoff = -1; + } + } + else { + optbase = &argv[3]; + if (shellparam.optind > argc - 2) { + shellparam.optind = 1; + shellparam.optoff = -1; + } + } + + return getopts(argv[1], argv[2], optbase, &shellparam.optind, + &shellparam.optoff); +} +#endif /* BB_ASH_GETOPTS */ + +/* + * XXX - should get rid of. have all builtins use getopt(3). the + * library getopt must have the BSD extension static variable "optreset" + * otherwise it can't be used within the shell safely. + * + * Standard option processing (a la getopt) for builtin routines. The + * only argument that is passed to nextopt is the option string; the + * other arguments are unnecessary. It return the character, or '\0' on + * end of input. + */ + +static int +nextopt(const char *optstring) +{ + char *p; + const char *q; + char c; + + if ((p = optptr) == NULL || *p == '\0') { + p = *argptr; + if (p == NULL || *p != '-' || *++p == '\0') + return '\0'; + argptr++; + if (p[0] == '-' && p[1] == '\0') /* check for "--" */ + return '\0'; + } + c = *p++; + for (q = optstring ; *q != c ; ) { + if (*q == '\0') + error("Illegal option -%c", c); + if (*++q == ':') + q++; + } + if (*++q == ':') { + if (*p == '\0' && (p = *argptr++) == NULL) + error("No arg for -%c option", c); + optionarg = p; + p = NULL; + } + optptr = p; + return c; +} + + +/* $NetBSD: output.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */ + +void +outstr(const char *p, FILE *file) +{ + INTOFF; + fputs(p, file); + INTON; +} + +void +flushall(void) +{ + INTOFF; + fflush(stdout); + fflush(stderr); + INTON; +} + +void +flushout(FILE *dest) +{ + INTOFF; + fflush(dest); + INTON; +} + +static void +outcslow(int c, FILE *dest) +{ + INTOFF; + putc(c, dest); + fflush(dest); + INTON; +} + + +static int +out1fmt(const char *fmt, ...) +{ + va_list ap; + int r; + + INTOFF; + va_start(ap, fmt); + r = vprintf(fmt, ap); + va_end(ap); + INTON; + return r; +} + + +int +fmtstr(char *outbuf, size_t length, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + INTOFF; + ret = vsnprintf(outbuf, length, fmt, ap); + va_end(ap); + INTON; + return ret; +} + + +/* + * Version of write which resumes after a signal is caught. + */ + +static void +xwrite(int fd, const void *p, size_t n) +{ + ssize_t i; + + do { + i = full_write(fd, p, n); + } while (i < 0 && errno == EINTR); +} + + +/* $NetBSD: parser.c,v 1.54 2002/11/24 22:35:42 christos Exp $ */ + + +/* + * Shell command parser. + */ + +#define EOFMARKLEN 79 + + +struct heredoc { + struct heredoc *next; /* next here document in list */ + union node *here; /* redirection node */ + char *eofmark; /* string indicating end of input */ + int striptabs; /* if set, strip leading tabs */ +}; + + + +static struct heredoc *heredoclist; /* list of here documents to read */ + + +static union node *list(int); +static union node *andor(void); +static union node *pipeline(void); +static union node *command(void); +static union node *simplecmd(void); +static union node *makename(void); +static void parsefname(void); +static void parseheredoc(void); +static char peektoken(void); +static int readtoken(void); +static int xxreadtoken(void); +static int readtoken1(int firstc, int syntax, char *eofmark, int striptabs); +static int noexpand(char *); +static void synexpect(int) __attribute__((__noreturn__)); +static void synerror(const char *) __attribute__((__noreturn__)); +static void setprompt(int); + + +static inline int +goodname(const char *p) +{ + return !*endofname(p); +} + +static inline int +isassignment(const char *p) +{ + const char *q = endofname(p); + if (p == q) + return 0; + return *q == '='; +} + + +/* + * Read and parse a command. Returns NEOF on end of file. (NULL is a + * valid parse tree indicating a blank line.) + */ + +union node * +parsecmd(int interact) +{ + int t; + + tokpushback = 0; + doprompt = interact; + if (doprompt) + setprompt(doprompt); + needprompt = 0; + t = readtoken(); + if (t == TEOF) + return NEOF; + if (t == TNL) + return NULL; + tokpushback++; + return list(1); +} + + +static union node * +list(int nlflag) +{ + union node *n1, *n2, *n3; + int tok; + + checkkwd = CHKNL | CHKKWD | CHKALIAS; + if (nlflag == 2 && peektoken()) + return NULL; + n1 = NULL; + for (;;) { + n2 = andor(); + tok = readtoken(); + if (tok == TBACKGND) { + if (n2->type == NPIPE) { + n2->npipe.backgnd = 1; + } else { + if (n2->type != NREDIR) { + n3 = stalloc(sizeof(struct nredir)); + n3->nredir.n = n2; + n3->nredir.redirect = NULL; + n2 = n3; + } + n2->type = NBACKGND; + } + } + if (n1 == NULL) { + n1 = n2; + } + else { + n3 = (union node *)stalloc(sizeof (struct nbinary)); + n3->type = NSEMI; + n3->nbinary.ch1 = n1; + n3->nbinary.ch2 = n2; + n1 = n3; + } + switch (tok) { + case TBACKGND: + case TSEMI: + tok = readtoken(); + /* fall through */ + case TNL: + if (tok == TNL) { + parseheredoc(); + if (nlflag == 1) + return n1; + } else { + tokpushback++; + } + checkkwd = CHKNL | CHKKWD | CHKALIAS; + if (peektoken()) + return n1; + break; + case TEOF: + if (heredoclist) + parseheredoc(); + else + pungetc(); /* push back EOF on input */ + return n1; + default: + if (nlflag == 1) + synexpect(-1); + tokpushback++; + return n1; + } + } +} + + + +static union node * +andor(void) +{ + union node *n1, *n2, *n3; + int t; + + n1 = pipeline(); + for (;;) { + if ((t = readtoken()) == TAND) { + t = NAND; + } else if (t == TOR) { + t = NOR; + } else { + tokpushback++; + return n1; + } + checkkwd = CHKNL | CHKKWD | CHKALIAS; + n2 = pipeline(); + n3 = (union node *)stalloc(sizeof (struct nbinary)); + n3->type = t; + n3->nbinary.ch1 = n1; + n3->nbinary.ch2 = n2; + n1 = n3; + } +} + + + +static union node * +pipeline(void) +{ + union node *n1, *n2, *pipenode; + struct nodelist *lp, *prev; + int negate; + + negate = 0; + TRACE(("pipeline: entered\n")); + if (readtoken() == TNOT) { + negate = !negate; + checkkwd = CHKKWD | CHKALIAS; + } else + tokpushback++; + n1 = command(); + if (readtoken() == TPIPE) { + pipenode = (union node *)stalloc(sizeof (struct npipe)); + pipenode->type = NPIPE; + pipenode->npipe.backgnd = 0; + lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); + pipenode->npipe.cmdlist = lp; + lp->n = n1; + do { + prev = lp; + lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); + checkkwd = CHKNL | CHKKWD | CHKALIAS; + lp->n = command(); + prev->next = lp; + } while (readtoken() == TPIPE); + lp->next = NULL; + n1 = pipenode; + } + tokpushback++; + if (negate) { + n2 = (union node *)stalloc(sizeof (struct nnot)); + n2->type = NNOT; + n2->nnot.com = n1; + return n2; + } else + return n1; +} + + + +static union node * +command(void) +{ + union node *n1, *n2; + union node *ap, **app; + union node *cp, **cpp; + union node *redir, **rpp; + union node **rpp2; + int t; + + redir = NULL; + rpp2 = &redir; + + switch (readtoken()) { + default: + synexpect(-1); + /* NOTREACHED */ + case TIF: + n1 = (union node *)stalloc(sizeof (struct nif)); + n1->type = NIF; + n1->nif.test = list(0); + if (readtoken() != TTHEN) + synexpect(TTHEN); + n1->nif.ifpart = list(0); + n2 = n1; + while (readtoken() == TELIF) { + n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); + n2 = n2->nif.elsepart; + n2->type = NIF; + n2->nif.test = list(0); + if (readtoken() != TTHEN) + synexpect(TTHEN); + n2->nif.ifpart = list(0); + } + if (lasttoken == TELSE) + n2->nif.elsepart = list(0); + else { + n2->nif.elsepart = NULL; + tokpushback++; + } + t = TFI; + break; + case TWHILE: + case TUNTIL: { + int got; + n1 = (union node *)stalloc(sizeof (struct nbinary)); + n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; + n1->nbinary.ch1 = list(0); + if ((got=readtoken()) != TDO) { +TRACE(("expecting DO got %s %s\n", tokname(got), got == TWORD ? wordtext : "")); + synexpect(TDO); + } + n1->nbinary.ch2 = list(0); + t = TDONE; + break; + } + case TFOR: + if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) + synerror("Bad for loop variable"); + n1 = (union node *)stalloc(sizeof (struct nfor)); + n1->type = NFOR; + n1->nfor.var = wordtext; + checkkwd = CHKKWD | CHKALIAS; + if (readtoken() == TIN) { + app = ≈ + while (readtoken() == TWORD) { + n2 = (union node *)stalloc(sizeof (struct narg)); + n2->type = NARG; + n2->narg.text = wordtext; + n2->narg.backquote = backquotelist; + *app = n2; + app = &n2->narg.next; + } + *app = NULL; + n1->nfor.args = ap; + if (lasttoken != TNL && lasttoken != TSEMI) + synexpect(-1); + } else { + n2 = (union node *)stalloc(sizeof (struct narg)); + n2->type = NARG; + n2->narg.text = (char *)dolatstr; + n2->narg.backquote = NULL; + n2->narg.next = NULL; + n1->nfor.args = n2; + /* + * Newline or semicolon here is optional (but note + * that the original Bourne shell only allowed NL). + */ + if (lasttoken != TNL && lasttoken != TSEMI) + tokpushback++; + } + checkkwd = CHKNL | CHKKWD | CHKALIAS; + if (readtoken() != TDO) + synexpect(TDO); + n1->nfor.body = list(0); + t = TDONE; + break; + case TCASE: + n1 = (union node *)stalloc(sizeof (struct ncase)); + n1->type = NCASE; + if (readtoken() != TWORD) + synexpect(TWORD); + n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); + n2->type = NARG; + n2->narg.text = wordtext; + n2->narg.backquote = backquotelist; + n2->narg.next = NULL; + do { + checkkwd = CHKKWD | CHKALIAS; + } while (readtoken() == TNL); + if (lasttoken != TIN) + synexpect(TIN); + cpp = &n1->ncase.cases; +next_case: + checkkwd = CHKNL | CHKKWD; + t = readtoken(); + while(t != TESAC) { + if (lasttoken == TLP) + readtoken(); + *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); + cp->type = NCLIST; + app = &cp->nclist.pattern; + for (;;) { + *app = ap = (union node *)stalloc(sizeof (struct narg)); + ap->type = NARG; + ap->narg.text = wordtext; + ap->narg.backquote = backquotelist; + if (readtoken() != TPIPE) + break; + app = &ap->narg.next; + readtoken(); + } + ap->narg.next = NULL; + if (lasttoken != TRP) + synexpect(TRP); + cp->nclist.body = list(2); + + cpp = &cp->nclist.next; + + checkkwd = CHKNL | CHKKWD; + if ((t = readtoken()) != TESAC) { + if (t != TENDCASE) + synexpect(TENDCASE); + else + goto next_case; + } + } + *cpp = NULL; + goto redir; + case TLP: + n1 = (union node *)stalloc(sizeof (struct nredir)); + n1->type = NSUBSHELL; + n1->nredir.n = list(0); + n1->nredir.redirect = NULL; + t = TRP; + break; + case TBEGIN: + n1 = list(0); + t = TEND; + break; + case TWORD: + case TREDIR: + tokpushback++; + return simplecmd(); + } + + if (readtoken() != t) + synexpect(t); + +redir: + /* Now check for redirection which may follow command */ + checkkwd = CHKKWD | CHKALIAS; + rpp = rpp2; + while (readtoken() == TREDIR) { + *rpp = n2 = redirnode; + rpp = &n2->nfile.next; + parsefname(); + } + tokpushback++; + *rpp = NULL; + if (redir) { + if (n1->type != NSUBSHELL) { + n2 = (union node *)stalloc(sizeof (struct nredir)); + n2->type = NREDIR; + n2->nredir.n = n1; + n1 = n2; + } + n1->nredir.redirect = redir; + } + + return n1; +} + + +static union node * +simplecmd(void) { + union node *args, **app; + union node *n = NULL; + union node *vars, **vpp; + union node **rpp, *redir; + int savecheckkwd; + + args = NULL; + app = &args; + vars = NULL; + vpp = &vars; + redir = NULL; + rpp = &redir; + + savecheckkwd = CHKALIAS; + for (;;) { + checkkwd = savecheckkwd; + switch (readtoken()) { + case TWORD: + n = (union node *)stalloc(sizeof (struct narg)); + n->type = NARG; + n->narg.text = wordtext; + n->narg.backquote = backquotelist; + if (savecheckkwd && isassignment(wordtext)) { + *vpp = n; + vpp = &n->narg.next; + } else { + *app = n; + app = &n->narg.next; + savecheckkwd = 0; + } + break; + case TREDIR: + *rpp = n = redirnode; + rpp = &n->nfile.next; + parsefname(); /* read name of redirection file */ + break; + case TLP: + if ( + args && app == &args->narg.next && + !vars && !redir + ) { + struct builtincmd *bcmd; + const char *name; + + /* We have a function */ + if (readtoken() != TRP) + synexpect(TRP); + name = n->narg.text; + if ( + !goodname(name) || ( + (bcmd = find_builtin(name)) && + IS_BUILTIN_SPECIAL(bcmd) + ) + ) + synerror("Bad function name"); + n->type = NDEFUN; + checkkwd = CHKNL | CHKKWD | CHKALIAS; + n->narg.next = command(); + return n; + } + /* fall through */ + default: + tokpushback++; + goto out; + } + } +out: + *app = NULL; + *vpp = NULL; + *rpp = NULL; + n = (union node *)stalloc(sizeof (struct ncmd)); + n->type = NCMD; + n->ncmd.args = args; + n->ncmd.assign = vars; + n->ncmd.redirect = redir; + return n; +} + +static union node * +makename(void) +{ + union node *n; + + n = (union node *)stalloc(sizeof (struct narg)); + n->type = NARG; + n->narg.next = NULL; + n->narg.text = wordtext; + n->narg.backquote = backquotelist; + return n; +} + +void fixredir(union node *n, const char *text, int err) +{ + TRACE(("Fix redir %s %d\n", text, err)); + if (!err) + n->ndup.vname = NULL; + + if (is_digit(text[0]) && text[1] == '\0') + n->ndup.dupfd = digit_val(text[0]); + else if (text[0] == '-' && text[1] == '\0') + n->ndup.dupfd = -1; + else { + + if (err) + synerror("Bad fd number"); + else + n->ndup.vname = makename(); + } +} + + +static void +parsefname(void) +{ + union node *n = redirnode; + + if (readtoken() != TWORD) + synexpect(-1); + if (n->type == NHERE) { + struct heredoc *here = heredoc; + struct heredoc *p; + int i; + + if (quoteflag == 0) + n->type = NXHERE; + TRACE(("Here document %d\n", n->type)); + if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) + synerror("Illegal eof marker for << redirection"); + rmescapes(wordtext); + here->eofmark = wordtext; + here->next = NULL; + if (heredoclist == NULL) + heredoclist = here; + else { + for (p = heredoclist ; p->next ; p = p->next); + p->next = here; + } + } else if (n->type == NTOFD || n->type == NFROMFD) { + fixredir(n, wordtext, 0); + } else { + n->nfile.fname = makename(); + } +} + + +/* + * Input any here documents. + */ + +static void +parseheredoc(void) +{ + struct heredoc *here; + union node *n; + + here = heredoclist; + heredoclist = 0; + + while (here) { + if (needprompt) { + setprompt(2); + needprompt = 0; + } + readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, + here->eofmark, here->striptabs); + n = (union node *)stalloc(sizeof (struct narg)); + n->narg.type = NARG; + n->narg.next = NULL; + n->narg.text = wordtext; + n->narg.backquote = backquotelist; + here->here->nhere.doc = n; + here = here->next; + } +} + +static char peektoken(void) +{ + int t; + + t = readtoken(); + tokpushback++; + return tokname_array[t][0]; +} + +static int +readtoken(void) +{ + int t; +#ifdef DEBUG + int alreadyseen = tokpushback; +#endif + +#ifdef BB_ASH_ALIAS +top: +#endif + + t = xxreadtoken(); + + /* + * eat newlines + */ + if (checkkwd & CHKNL) { + while (t == TNL) { + parseheredoc(); + t = xxreadtoken(); + } + } + + if (t != TWORD || quoteflag) { + goto out; + } + + /* + * check for keywords + */ + if (checkkwd & CHKKWD) { + const char *const *pp; + + if ((pp = findkwd(wordtext))) { + lasttoken = t = pp - tokname_array; + TRACE(("keyword %s recognized\n", tokname(t))); + goto out; + } + } + + if (checkkwd & CHKALIAS) { +#ifdef BB_ASH_ALIAS + struct alias *ap; + if ((ap = lookupalias(wordtext, 1)) != NULL) { + if (*ap->val) { + pushstring(ap->val, ap); + } + goto top; + } +#endif + } +out: + checkkwd = 0; +#ifdef DEBUG + if (!alreadyseen) + TRACE(("token %s %s\n", tokname(t), t == TWORD ? wordtext : "")); + else + TRACE(("reread token %s %s\n", tokname(t), t == TWORD ? wordtext : "")); +#endif + return (t); +} + + +/* + * Read the next input token. + * If the token is a word, we set backquotelist to the list of cmds in + * backquotes. We set quoteflag to true if any part of the word was + * quoted. + * If the token is TREDIR, then we set redirnode to a structure containing + * the redirection. + * In all cases, the variable startlinno is set to the number of the line + * on which the token starts. + * + * [Change comment: here documents and internal procedures] + * [Readtoken shouldn't have any arguments. Perhaps we should make the + * word parsing code into a separate routine. In this case, readtoken + * doesn't need to have any internal procedures, but parseword does. + * We could also make parseoperator in essence the main routine, and + * have parseword (readtoken1?) handle both words and redirection.] + */ + +#define NEW_xxreadtoken +#ifdef NEW_xxreadtoken + +/* singles must be first! */ +static const char xxreadtoken_chars[7] = { '\n', '(', ')', '&', '|', ';', 0 }; + +static const char xxreadtoken_tokens[] = { + TNL, TLP, TRP, /* only single occurrence allowed */ + TBACKGND, TPIPE, TSEMI, /* if single occurrence */ + TEOF, /* corresponds to trailing nul */ + TAND, TOR, TENDCASE, /* if double occurrence */ +}; + +#define xxreadtoken_doubles \ + (sizeof(xxreadtoken_tokens) - sizeof(xxreadtoken_chars)) +#define xxreadtoken_singles \ + (sizeof(xxreadtoken_chars) - xxreadtoken_doubles - 1) + +static int xxreadtoken() +{ + int c; + + if (tokpushback) { + tokpushback = 0; + return lasttoken; + } + if (needprompt) { + setprompt(2); + needprompt = 0; + } + startlinno = plinno; + for (;;) { /* until token or start of word found */ + c = pgetc_macro(); + + if ((c != ' ') && (c != '\t') +#ifdef BB_ASH_ALIAS + && (c != PEOA) +#endif + ) { + if (c == '#') { + while ((c = pgetc()) != '\n' && c != PEOF); + pungetc(); + } else if (c == '\\') { + if (pgetc() != '\n') { + pungetc(); + goto READTOKEN1; + } + startlinno = ++plinno; + if (doprompt) + setprompt(2); + } else { + const char *p + = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1; + + if (c != PEOF) { + if (c == '\n') { + plinno++; + needprompt = doprompt; + } + + p = strchr(xxreadtoken_chars, c); + if (p == NULL) { + READTOKEN1: + return readtoken1(c, BASESYNTAX, (char *) NULL, 0); + } + + if (p - xxreadtoken_chars >= xxreadtoken_singles) { + if (pgetc() == *p) { /* double occurrence? */ + p += xxreadtoken_doubles + 1; + } else { + pungetc(); + } + } + } + + return lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars]; + } + } + } +} + + +#else +#define RETURN(token) return lasttoken = token + +static int +xxreadtoken(void) +{ + int c; + + if (tokpushback) { + tokpushback = 0; + return lasttoken; + } + if (needprompt) { + setprompt(2); + needprompt = 0; + } + startlinno = plinno; + for (;;) { /* until token or start of word found */ + c = pgetc_macro(); + switch (c) { + case ' ': case '\t': +#ifdef BB_ASH_ALIAS + case PEOA: +#endif + continue; + case '#': + while ((c = pgetc()) != '\n' && c != PEOF); + pungetc(); + continue; + case '\\': + if (pgetc() == '\n') { + startlinno = ++plinno; + if (doprompt) + setprompt(2); + continue; + } + pungetc(); + goto breakloop; + case '\n': + plinno++; + needprompt = doprompt; + RETURN(TNL); + case PEOF: + RETURN(TEOF); + case '&': + if (pgetc() == '&') + RETURN(TAND); + pungetc(); + RETURN(TBACKGND); + case '|': + if (pgetc() == '|') + RETURN(TOR); + pungetc(); + RETURN(TPIPE); + case ';': + if (pgetc() == ';') + RETURN(TENDCASE); + pungetc(); + RETURN(TSEMI); + case '(': + RETURN(TLP); + case ')': + RETURN(TRP); + default: + goto breakloop; + } + } +breakloop: + return readtoken1(c, BASESYNTAX, (char *)NULL, 0); +#undef RETURN +} +#endif /* NEW_xxreadtoken */ + + +/* + * If eofmark is NULL, read a word or a redirection symbol. If eofmark + * is not NULL, read a here document. In the latter case, eofmark is the + * word which marks the end of the document and striptabs is true if + * leading tabs should be stripped from the document. The argument firstc + * is the first character of the input token or document. + * + * Because C does not have internal subroutines, I have simulated them + * using goto's to implement the subroutine linkage. The following macros + * will run code that appears at the end of readtoken1. + */ + +#define CHECKEND() {goto checkend; checkend_return:;} +#define PARSEREDIR() {goto parseredir; parseredir_return:;} +#define PARSESUB() {goto parsesub; parsesub_return:;} +#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} +#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} +#define PARSEARITH() {goto parsearith; parsearith_return:;} + +static int +readtoken1(int firstc, int syntax, char *eofmark, int striptabs) +{ + int c = firstc; + char *out; + int len; + char line[EOFMARKLEN + 1]; + struct nodelist *bqlist; + int quotef; + int dblquote; + int varnest; /* levels of variables expansion */ + int arinest; /* levels of arithmetic expansion */ + int parenlevel; /* levels of parens in arithmetic */ + int dqvarnest; /* levels of variables expansion within double quotes */ + int oldstyle; + int prevsyntax; /* syntax before arithmetic */ +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &out; + (void) "ef; + (void) &dblquote; + (void) &varnest; + (void) &arinest; + (void) &parenlevel; + (void) &dqvarnest; + (void) &oldstyle; + (void) &prevsyntax; + (void) &syntax; +#endif + + startlinno = plinno; + dblquote = 0; + if (syntax == DQSYNTAX) + dblquote = 1; + quotef = 0; + bqlist = NULL; + varnest = 0; + arinest = 0; + parenlevel = 0; + dqvarnest = 0; + + STARTSTACKSTR(out); + loop: { /* for each line, until end of word */ + CHECKEND(); /* set c to PEOF if at end of here document */ + for (;;) { /* until end of line or end of word */ + CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ + switch(SIT(c, syntax)) { + case CNL: /* '\n' */ + if (syntax == BASESYNTAX) + goto endword; /* exit outer loop */ + USTPUTC(c, out); + plinno++; + if (doprompt) + setprompt(2); + c = pgetc(); + goto loop; /* continue outer loop */ + case CWORD: + USTPUTC(c, out); + break; + case CCTL: + if (eofmark == NULL || dblquote) + USTPUTC(CTLESC, out); + USTPUTC(c, out); + break; + case CBACK: /* backslash */ + c = pgetc2(); + if (c == PEOF) { + USTPUTC(CTLESC, out); + USTPUTC('\\', out); + pungetc(); + } else if (c == '\n') { + if (doprompt) + setprompt(2); + } else { + if ( + dblquote && + c != '\\' && c != '`' && + c != '$' && ( + c != '"' || + eofmark != NULL + ) + ) { + USTPUTC(CTLESC, out); + USTPUTC('\\', out); + } + if (SIT(c, SQSYNTAX) == CCTL) + USTPUTC(CTLESC, out); + USTPUTC(c, out); + quotef++; + } + break; + case CSQUOTE: + syntax = SQSYNTAX; +quotemark: + if (eofmark == NULL) { + USTPUTC(CTLQUOTEMARK, out); + } + break; + case CDQUOTE: + syntax = DQSYNTAX; + dblquote = 1; + goto quotemark; + case CENDQUOTE: + if (eofmark != NULL && arinest == 0 && + varnest == 0) { + USTPUTC(c, out); + } else { + if (dqvarnest == 0) { + syntax = BASESYNTAX; + dblquote = 0; + } + quotef++; + goto quotemark; + } + break; + case CVAR: /* '$' */ + PARSESUB(); /* parse substitution */ + break; + case CENDVAR: /* '}' */ + if (varnest > 0) { + varnest--; + if (dqvarnest > 0) { + dqvarnest--; + } + USTPUTC(CTLENDVAR, out); + } else { + USTPUTC(c, out); + } + break; +#ifdef BB_ASH_MATH_SUPPORT + case CLP: /* '(' in arithmetic */ + parenlevel++; + USTPUTC(c, out); + break; + case CRP: /* ')' in arithmetic */ + if (parenlevel > 0) { + USTPUTC(c, out); + --parenlevel; + } else { + if (pgetc() == ')') { + if (--arinest == 0) { + USTPUTC(CTLENDARI, out); + syntax = prevsyntax; + if (syntax == DQSYNTAX) + dblquote = 1; + else + dblquote = 0; + } else + USTPUTC(')', out); + } else { + /* + * unbalanced parens + * (don't 2nd guess - no error) + */ + pungetc(); + USTPUTC(')', out); + } + } + break; +#endif + case CBQUOTE: /* '`' */ + PARSEBACKQOLD(); + break; + case CENDFILE: + goto endword; /* exit outer loop */ + case CIGN: + break; + default: + if (varnest == 0) + goto endword; /* exit outer loop */ +#ifdef BB_ASH_ALIAS + if (c != PEOA) +#endif + USTPUTC(c, out); + + } + c = pgetc_macro(); + } + } +endword: +#ifdef BB_ASH_MATH_SUPPORT + if (syntax == ARISYNTAX) + synerror("Missing '))'"); +#endif + if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) + synerror("Unterminated quoted string"); + if (varnest != 0) { + startlinno = plinno; + /* { */ + synerror("Missing '}'"); + } + USTPUTC('\0', out); + len = out - (char *)stackblock(); + out = stackblock(); + if (eofmark == NULL) { + if ((c == '>' || c == '<') + && quotef == 0 + && len <= 2 + && (*out == '\0' || is_digit(*out))) { + PARSEREDIR(); + return lasttoken = TREDIR; + } else { + pungetc(); + } + } + quoteflag = quotef; + backquotelist = bqlist; + grabstackblock(len); + wordtext = out; + return lasttoken = TWORD; +/* end of readtoken routine */ + + + +/* + * Check to see whether we are at the end of the here document. When this + * is called, c is set to the first character of the next input line. If + * we are at the end of the here document, this routine sets the c to PEOF. + */ + +checkend: { + if (eofmark) { +#ifdef BB_ASH_ALIAS + if (c == PEOA) { + c = pgetc2(); + } +#endif + if (striptabs) { + while (c == '\t') { + c = pgetc2(); + } + } + if (c == *eofmark) { + if (pfgets(line, sizeof line) != NULL) { + char *p, *q; + + p = line; + for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); + if (*p == '\n' && *q == '\0') { + c = PEOF; + plinno++; + needprompt = doprompt; + } else { + pushstring(line, NULL); + } + } + } + } + goto checkend_return; +} + + +/* + * Parse a redirection operator. The variable "out" points to a string + * specifying the fd to be redirected. The variable "c" contains the + * first character of the redirection operator. + */ + +parseredir: { + char fd = *out; + union node *np; + + np = (union node *)stalloc(sizeof (struct nfile)); + if (c == '>') { + np->nfile.fd = 1; + c = pgetc(); + if (c == '>') + np->type = NAPPEND; + else if (c == '|') + np->type = NCLOBBER; + else if (c == '&') + np->type = NTOFD; + else { + np->type = NTO; + pungetc(); + } + } else { /* c == '<' */ + np->nfile.fd = 0; + switch (c = pgetc()) { + case '<': + if (sizeof (struct nfile) != sizeof (struct nhere)) { + np = (union node *)stalloc(sizeof (struct nhere)); + np->nfile.fd = 0; + } + np->type = NHERE; + heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); + heredoc->here = np; + if ((c = pgetc()) == '-') { + heredoc->striptabs = 1; + } else { + heredoc->striptabs = 0; + pungetc(); + } + break; + + case '&': + np->type = NFROMFD; + break; + + case '>': + np->type = NFROMTO; + break; + + default: + np->type = NFROM; + pungetc(); + break; + } + } + if (fd != '\0') + np->nfile.fd = digit_val(fd); + redirnode = np; + goto parseredir_return; +} + + +/* + * Parse a substitution. At this point, we have read the dollar sign + * and nothing else. + */ + +parsesub: { + int subtype; + int typeloc; + int flags; + char *p; + static const char types[] = "}-+?="; + + c = pgetc(); + if ( + c <= PEOA_OR_PEOF || + (c != '(' && c != '{' && !is_name(c) && !is_special(c)) + ) { + USTPUTC('$', out); + pungetc(); + } else if (c == '(') { /* $(command) or $((arith)) */ + if (pgetc() == '(') { +#ifdef BB_ASH_MATH_SUPPORT + PARSEARITH(); +#else + synerror("We unsupport $((arith))"); +#endif + } else { + pungetc(); + PARSEBACKQNEW(); + } + } else { + USTPUTC(CTLVAR, out); + typeloc = out - (char *)stackblock(); + USTPUTC(VSNORMAL, out); + subtype = VSNORMAL; + if (c == '{') { + c = pgetc(); + if (c == '#') { + if ((c = pgetc()) == '}') + c = '#'; + else + subtype = VSLENGTH; + } + else + subtype = 0; + } + if (c > PEOA_OR_PEOF && is_name(c)) { + do { + STPUTC(c, out); + c = pgetc(); + } while (c > PEOA_OR_PEOF && is_in_name(c)); + } else if (is_digit(c)) { + do { + STPUTC(c, out); + c = pgetc(); + } while (is_digit(c)); + } + else if (is_special(c)) { + USTPUTC(c, out); + c = pgetc(); + } + else +badsub: synerror("Bad substitution"); + + STPUTC('=', out); + flags = 0; + if (subtype == 0) { + switch (c) { + case ':': + flags = VSNUL; + c = pgetc(); + /*FALLTHROUGH*/ + default: + p = strchr(types, c); + if (p == NULL) + goto badsub; + subtype = p - types + VSNORMAL; + break; + case '%': + case '#': + { + int cc = c; + subtype = c == '#' ? VSTRIMLEFT : + VSTRIMRIGHT; + c = pgetc(); + if (c == cc) + subtype++; + else + pungetc(); + break; + } + } + } else { + pungetc(); + } + if (dblquote || arinest) + flags |= VSQUOTE; + *((char *)stackblock() + typeloc) = subtype | flags; + if (subtype != VSNORMAL) { + varnest++; + if (dblquote || arinest) { + dqvarnest++; + } + } + } + goto parsesub_return; +} + + +/* + * Called to parse command substitutions. Newstyle is set if the command + * is enclosed inside $(...); nlpp is a pointer to the head of the linked + * list of commands (passed by reference), and savelen is the number of + * characters on the top of the stack which must be preserved. + */ + +parsebackq: { + struct nodelist **nlpp; + int savepbq; + union node *n; + char *volatile str; + struct jmploc jmploc; + struct jmploc *volatile savehandler; + size_t savelen; + int saveprompt; +#ifdef __GNUC__ + (void) &saveprompt; +#endif + + savepbq = parsebackquote; + if (setjmp(jmploc.loc)) { + if (str) + ckfree(str); + parsebackquote = 0; + handler = savehandler; + longjmp(handler->loc, 1); + } + INTOFF; + str = NULL; + savelen = out - (char *)stackblock(); + if (savelen > 0) { + str = ckmalloc(savelen); + memcpy(str, stackblock(), savelen); + } + savehandler = handler; + handler = &jmploc; + INTON; + if (oldstyle) { + /* We must read until the closing backquote, giving special + treatment to some slashes, and then push the string and + reread it as input, interpreting it normally. */ + char *pout; + int pc; + size_t psavelen; + char *pstr; + + + STARTSTACKSTR(pout); + for (;;) { + if (needprompt) { + setprompt(2); + needprompt = 0; + } + switch (pc = pgetc()) { + case '`': + goto done; + + case '\\': + if ((pc = pgetc()) == '\n') { + plinno++; + if (doprompt) + setprompt(2); + /* + * If eating a newline, avoid putting + * the newline into the new character + * stream (via the STPUTC after the + * switch). + */ + continue; + } + if (pc != '\\' && pc != '`' && pc != '$' + && (!dblquote || pc != '"')) + STPUTC('\\', pout); + if (pc > PEOA_OR_PEOF) { + break; + } + /* fall through */ + + case PEOF: +#ifdef BB_ASH_ALIAS + case PEOA: +#endif + startlinno = plinno; + synerror("EOF in backquote substitution"); + + case '\n': + plinno++; + needprompt = doprompt; + break; + + default: + break; + } + STPUTC(pc, pout); + } +done: + STPUTC('\0', pout); + psavelen = pout - (char *)stackblock(); + if (psavelen > 0) { + pstr = grabstackstr(pout); + setinputstring(pstr); + } + } + nlpp = &bqlist; + while (*nlpp) + nlpp = &(*nlpp)->next; + *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); + (*nlpp)->next = NULL; + parsebackquote = oldstyle; + + if (oldstyle) { + saveprompt = doprompt; + doprompt = 0; + } + + n = list(2); + + if (oldstyle) + doprompt = saveprompt; + else { + if (readtoken() != TRP) + synexpect(TRP); + } + + (*nlpp)->n = n; + if (oldstyle) { + /* + * Start reading from old file again, ignoring any pushed back + * tokens left from the backquote parsing + */ + popfile(); + tokpushback = 0; + } + while (stackblocksize() <= savelen) + growstackblock(); + STARTSTACKSTR(out); + if (str) { + memcpy(out, str, savelen); + STADJUST(savelen, out); + INTOFF; + ckfree(str); + str = NULL; + INTON; + } + parsebackquote = savepbq; + handler = savehandler; + if (arinest || dblquote) + USTPUTC(CTLBACKQ | CTLQUOTE, out); + else + USTPUTC(CTLBACKQ, out); + if (oldstyle) + goto parsebackq_oldreturn; + else + goto parsebackq_newreturn; +} + +#ifdef BB_ASH_MATH_SUPPORT +/* + * Parse an arithmetic expansion (indicate start of one and set state) + */ +parsearith: { + + if (++arinest == 1) { + prevsyntax = syntax; + syntax = ARISYNTAX; + USTPUTC(CTLARI, out); + if (dblquote) + USTPUTC('"',out); + else + USTPUTC(' ',out); + } else { + /* + * we collapse embedded arithmetic expansion to + * parenthesis, which should be equivalent + */ + USTPUTC('(', out); + } + goto parsearith_return; +} +#endif + +} /* end of readtoken */ + + + +/* + * Returns true if the text contains nothing to expand (no dollar signs + * or backquotes). + */ + +static int +noexpand(char *text) +{ + char *p; + char c; + + p = text; + while ((c = *p++) != '\0') { + if (c == CTLQUOTEMARK) + continue; + if (c == CTLESC) + p++; + else if (SIT(c, BASESYNTAX) == CCTL) + return 0; + } + return 1; +} + + +/* + * Return of a legal variable name (a letter or underscore followed by zero or + * more letters, underscores, and digits). + */ + +char * +endofname(const char *name) +{ + char *p; + + p = (char *) name; + if (! is_name(*p)) + return p; + while (*++p) { + if (! is_in_name(*p)) + break; + } + return p; +} + + +/* + * Called when an unexpected token is read during the parse. The argument + * is the token that is expected, or -1 if more than one type of token can + * occur at this point. + */ + +static void synexpect(int token) +{ + char msg[64]; + int l; + + l = sprintf(msg, "%s unexpected", tokname(lasttoken)); + if (token >= 0) + sprintf(msg + l, " (expecting %s)", tokname(token)); + synerror(msg); + /* NOTREACHED */ +} + +static void +synerror(const char *msg) +{ + error("Syntax error: %s", msg); + /* NOTREACHED */ +} + + +/* + * called by editline -- any expansions to the prompt + * should be added here. + */ + +static void setprompt(int whichprompt) +{ + const char *prompt; + + switch (whichprompt) { + case 1: + prompt = ps1val(); + break; + case 2: + prompt = ps2val(); + break; + default: /* 0 */ + prompt = nullstr; + } + putprompt(prompt); +} + + +static const char *const *findkwd(const char *s) +{ + return bsearch(s, tokname_array + KWDOFFSET, + (sizeof(tokname_array) / sizeof(const char *)) - KWDOFFSET, + sizeof(const char *), pstrcmp); +} + +/* $NetBSD: redir.c,v 1.27 2002/11/24 22:35:42 christos Exp $ */ + +/* + * Code for dealing with input/output redirection. + */ + +#define EMPTY -2 /* marks an unused slot in redirtab */ +#ifndef PIPE_BUF +# define PIPESIZE 4096 /* amount of buffering in a pipe */ +#else +# define PIPESIZE PIPE_BUF +#endif + +/* + * Open a file in noclobber mode. + * The code was copied from bash. + */ +static inline int +noclobberopen(const char *fname) +{ + int r, fd; + struct stat finfo, finfo2; + + /* + * If the file exists and is a regular file, return an error + * immediately. + */ + r = stat(fname, &finfo); + if (r == 0 && S_ISREG(finfo.st_mode)) { + errno = EEXIST; + return -1; + } + + /* + * If the file was not present (r != 0), make sure we open it + * exclusively so that if it is created before we open it, our open + * will fail. Make sure that we do not truncate an existing file. + * Note that we don't turn on O_EXCL unless the stat failed -- if the + * file was not a regular file, we leave O_EXCL off. + */ + if (r != 0) + return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666); + fd = open(fname, O_WRONLY|O_CREAT, 0666); + + /* If the open failed, return the file descriptor right away. */ + if (fd < 0) + return fd; + + /* + * OK, the open succeeded, but the file may have been changed from a + * non-regular file to a regular file between the stat and the open. + * We are assuming that the O_EXCL open handles the case where FILENAME + * did not exist and is symlinked to an existing file between the stat + * and open. + */ + + /* + * If we can open it and fstat the file descriptor, and neither check + * revealed that it was a regular file, and the file has not been + * replaced, return the file descriptor. + */ + if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) && + finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) + return fd; + + /* The file has been replaced. badness. */ + close(fd); + errno = EEXIST; + return -1; +} + +/* + * Handle here documents. Normally we fork off a process to write the + * data to a pipe. If the document is short, we can stuff the data in + * the pipe without forking. + */ + +static inline int +openhere(union node *redir) +{ + int pip[2]; + size_t len = 0; + + if (pipe(pip) < 0) + error("Pipe call failed"); + if (redir->type == NHERE) { + len = strlen(redir->nhere.doc->narg.text); + if (len <= PIPESIZE) { + xwrite(pip[1], redir->nhere.doc->narg.text, len); + goto out; + } + } + if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { + close(pip[0]); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGHUP, SIG_IGN); +#ifdef SIGTSTP + signal(SIGTSTP, SIG_IGN); +#endif + signal(SIGPIPE, SIG_DFL); + if (redir->type == NHERE) + xwrite(pip[1], redir->nhere.doc->narg.text, len); + else + expandhere(redir->nhere.doc, pip[1]); + _exit(0); + } +out: + close(pip[1]); + return pip[0]; +} + +static int +openredirect(union node *redir) +{ + char *fname; + int f; + + switch (redir->nfile.type) { + case NFROM: + fname = redir->nfile.expfname; + if ((f = open(fname, O_RDONLY)) < 0) + goto eopen; + break; + case NFROMTO: + fname = redir->nfile.expfname; + if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) + goto ecreate; + break; + case NTO: + /* Take care of noclobber mode. */ + if (Cflag) { + fname = redir->nfile.expfname; + if ((f = noclobberopen(fname)) < 0) + goto ecreate; + break; + } + /* FALLTHROUGH */ + case NCLOBBER: + fname = redir->nfile.expfname; + if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) + goto ecreate; + break; + case NAPPEND: + fname = redir->nfile.expfname; + if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) + goto ecreate; + break; + default: +#ifdef DEBUG + abort(); +#endif + /* Fall through to eliminate warning. */ + case NTOFD: + case NFROMFD: + f = -1; + break; + case NHERE: + case NXHERE: + f = openhere(redir); + break; + } + + return f; +ecreate: + error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); +eopen: + error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); +} + +static inline void +dupredirect(union node *redir, int f) +{ + int fd = redir->nfile.fd; + + if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { + if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ + ash_copyfd(redir->ndup.dupfd, fd); + } + return; + } + + if (f != fd) { + ash_copyfd(f, fd); + close(f); + } + return; +} + +/* + * Process a list of redirection commands. If the REDIR_PUSH flag is set, + * old file descriptors are stashed away so that the redirection can be + * undone by calling popredir. If the REDIR_BACKQ flag is set, then the + * standard output, and the standard error if it becomes a duplicate of + * stdout, is saved in memory. + */ + +static void +redirect(union node *redir, int flags) +{ + union node *n; + struct redirtab *sv; + int i; + int fd; + int newfd; + int *p; + nullredirs++; + if (!redir) { + return; + } + sv = NULL; + INTOFF; + if (flags & REDIR_PUSH) { + struct redirtab *q; + q = ckmalloc(sizeof (struct redirtab)); + q->next = redirlist; + redirlist = q; + q->nullredirs = nullredirs - 1; + for (i = 0 ; i < 10 ; i++) + q->renamed[i] = EMPTY; + nullredirs = 0; + sv = q; + } + n = redir; + do { + fd = n->nfile.fd; + if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) && + n->ndup.dupfd == fd) + continue; /* redirect from/to same file descriptor */ + + newfd = openredirect(n); + if (fd == newfd) + continue; + if (sv && *(p = &sv->renamed[fd]) == EMPTY) { + i = fcntl(fd, F_DUPFD, 10); + + if (i == -1) { + i = errno; + if (i != EBADF) { + close(newfd); + errno = i; + error("%d: %m", fd); + /* NOTREACHED */ + } + } else { + *p = i; + close(fd); + } + } else { + close(fd); + } + dupredirect(n, newfd); + } while ((n = n->nfile.next)); + INTON; + if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0) + preverrout_fd = sv->renamed[2]; +} + + +/* + * Undo the effects of the last redirection. + */ + +void +popredir(int drop) +{ + struct redirtab *rp; + int i; + + if (--nullredirs >= 0) + return; + INTOFF; + rp = redirlist; + for (i = 0 ; i < 10 ; i++) { + if (rp->renamed[i] != EMPTY) { + if (!drop) { + close(i); + ash_copyfd(rp->renamed[i], i); + } + close(rp->renamed[i]); + } + } + redirlist = rp->next; + nullredirs = rp->nullredirs; + ckfree(rp); + INTON; +} + +/* + * Undo all redirections. Called on error or interrupt. + */ + +/* + * Discard all saved file descriptors. + */ + +void +clearredir(int drop) +{ + for (;;) { + nullredirs = 0; + if (!redirlist) + break; + popredir(drop); + } +} + + +/* + * Copy a file descriptor to be >= to. Returns -1 + * if the source file descriptor is closed, EMPTY if there are no unused + * file descriptors left. + */ + +int +ash_copyfd(int from, int to) +{ + int newfd; + + newfd = fcntl(from, F_DUPFD, to); + if (newfd < 0) { + if (errno == EMFILE) + return EMPTY; + else + error("%d: %m", from); + } + return newfd; +} + + +int +redirectsafe(union node *redir, int flags) +{ + int err; + volatile int saveint; + struct jmploc *volatile savehandler = handler; + struct jmploc jmploc; + + SAVEINT(saveint); + if (!(err = setjmp(jmploc.loc) * 2)) { + handler = &jmploc; + redirect(redir, flags); + } + handler = savehandler; + if (err && exception != EXERROR) + longjmp(handler->loc, 1); + RESTOREINT(saveint); + return err; +} + +/* $NetBSD: show.c,v 1.24 2003/01/22 20:36:04 dsl Exp $ */ + +#ifdef DEBUG +static void shtree(union node *, int, char *, FILE*); +static void shcmd(union node *, FILE *); +static void sharg(union node *, FILE *); +static void indent(int, char *, FILE *); +static void trstring(char *); + + +void +showtree(union node *n) +{ + trputs("showtree called\n"); + shtree(n, 1, NULL, stdout); +} + + +static void +shtree(union node *n, int ind, char *pfx, FILE *fp) +{ + struct nodelist *lp; + const char *s; + + if (n == NULL) + return; + + indent(ind, pfx, fp); + switch(n->type) { + case NSEMI: + s = "; "; + goto binop; + case NAND: + s = " && "; + goto binop; + case NOR: + s = " || "; +binop: + shtree(n->nbinary.ch1, ind, NULL, fp); + /* if (ind < 0) */ + fputs(s, fp); + shtree(n->nbinary.ch2, ind, NULL, fp); + break; + case NCMD: + shcmd(n, fp); + if (ind >= 0) + putc('\n', fp); + break; + case NPIPE: + for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { + shcmd(lp->n, fp); + if (lp->next) + fputs(" | ", fp); + } + if (n->npipe.backgnd) + fputs(" &", fp); + if (ind >= 0) + putc('\n', fp); + break; + default: + fprintf(fp, "", n->type); + if (ind >= 0) + putc('\n', fp); + break; + } +} + + +static void +shcmd(union node *cmd, FILE *fp) +{ + union node *np; + int first; + const char *s; + int dftfd; + + first = 1; + for (np = cmd->ncmd.args ; np ; np = np->narg.next) { + if (! first) + putchar(' '); + sharg(np, fp); + first = 0; + } + for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) { + if (! first) + putchar(' '); + switch (np->nfile.type) { + case NTO: s = ">"; dftfd = 1; break; + case NCLOBBER: s = ">|"; dftfd = 1; break; + case NAPPEND: s = ">>"; dftfd = 1; break; + case NTOFD: s = ">&"; dftfd = 1; break; + case NFROM: s = "<"; dftfd = 0; break; + case NFROMFD: s = "<&"; dftfd = 0; break; + case NFROMTO: s = "<>"; dftfd = 0; break; + default: s = "*error*"; dftfd = 0; break; + } + if (np->nfile.fd != dftfd) + fprintf(fp, "%d", np->nfile.fd); + fputs(s, fp); + if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { + fprintf(fp, "%d", np->ndup.dupfd); + } else { + sharg(np->nfile.fname, fp); + } + first = 0; + } +} + + + +static void +sharg(union node *arg, FILE *fp) +{ + char *p; + struct nodelist *bqlist; + int subtype; + + if (arg->type != NARG) { + out1fmt("\n", arg->type); + abort(); + } + bqlist = arg->narg.backquote; + for (p = arg->narg.text ; *p ; p++) { + switch (*p) { + case CTLESC: + putc(*++p, fp); + break; + case CTLVAR: + putc('$', fp); + putc('{', fp); + subtype = *++p; + if (subtype == VSLENGTH) + putc('#', fp); + + while (*p != '=') + putc(*p++, fp); + + if (subtype & VSNUL) + putc(':', fp); + + switch (subtype & VSTYPE) { + case VSNORMAL: + putc('}', fp); + break; + case VSMINUS: + putc('-', fp); + break; + case VSPLUS: + putc('+', fp); + break; + case VSQUESTION: + putc('?', fp); + break; + case VSASSIGN: + putc('=', fp); + break; + case VSTRIMLEFT: + putc('#', fp); + break; + case VSTRIMLEFTMAX: + putc('#', fp); + putc('#', fp); + break; + case VSTRIMRIGHT: + putc('%', fp); + break; + case VSTRIMRIGHTMAX: + putc('%', fp); + putc('%', fp); + break; + case VSLENGTH: + break; + default: + out1fmt("", subtype); + } + break; + case CTLENDVAR: + putc('}', fp); + break; + case CTLBACKQ: + case CTLBACKQ|CTLQUOTE: + putc('$', fp); + putc('(', fp); + shtree(bqlist->n, -1, NULL, fp); + putc(')', fp); + break; + default: + putc(*p, fp); + break; + } + } +} + + +static void +indent(int amount, char *pfx, FILE *fp) +{ + int i; + + for (i = 0 ; i < amount ; i++) { + if (pfx && i == amount - 1) + fputs(pfx, fp); + putc('\t', fp); + } +} + + + +/* + * Debugging stuff. + */ + + +FILE *tracefile; + + +void +trputc(int c) +{ + if (debug != 1) + return; + putc(c, tracefile); +} + +void +trace(const char *fmt, ...) +{ + va_list va; + + if (debug != 1) + return; + va_start(va, fmt); + (void) vfprintf(tracefile, fmt, va); + va_end(va); +} + +void +tracev(const char *fmt, va_list va) +{ + if (debug != 1) + return; + (void) vfprintf(tracefile, fmt, va); +} + + +void +trputs(const char *s) +{ + if (debug != 1) + return; + fputs(s, tracefile); +} + + +static void +trstring(char *s) +{ + char *p; + char c; + + if (debug != 1) + return; + putc('"', tracefile); + for (p = s ; *p ; p++) { + switch (*p) { + case '\n': c = 'n'; goto backslash; + case '\t': c = 't'; goto backslash; + case '\r': c = 'r'; goto backslash; + case '"': c = '"'; goto backslash; + case '\\': c = '\\'; goto backslash; + case CTLESC: c = 'e'; goto backslash; + case CTLVAR: c = 'v'; goto backslash; + case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; + case CTLBACKQ: c = 'q'; goto backslash; + case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; +backslash: putc('\\', tracefile); + putc(c, tracefile); + break; + default: + if (*p >= ' ' && *p <= '~') + putc(*p, tracefile); + else { + putc('\\', tracefile); + putc(*p >> 6 & 03, tracefile); + putc(*p >> 3 & 07, tracefile); + putc(*p & 07, tracefile); + } + break; + } + } + putc('"', tracefile); +} + + +void +trargs(char **ap) +{ + if (debug != 1) + return; + while (*ap) { + trstring(*ap++); + if (*ap) + putc(' ', tracefile); + else + putc('\n', tracefile); + } +} + + +void +opentrace(void) +{ + char s[100]; +#ifdef O_APPEND + int flags; +#endif + + if (debug != 1) { + if (tracefile) + fflush(tracefile); + /* leave open because libedit might be using it */ + return; + } + scopy("./trace", s); + if (tracefile) { + if (!freopen(s, "a", tracefile)) { + fprintf(stderr, "Can't re-open %s\n", s); + debug = 0; + return; + } + } else { + if ((tracefile = fopen(s, "a")) == NULL) { + fprintf(stderr, "Can't open %s\n", s); + debug = 0; + return; + } + } +#ifdef O_APPEND + if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) + fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); +#endif + setlinebuf(tracefile); + fputs("\nTracing started.\n", tracefile); +} +#endif /* DEBUG */ + + +/* $NetBSD: trap.c,v 1.28 2002/11/24 22:35:43 christos Exp $ */ + +/* + * Sigmode records the current value of the signal handlers for the various + * modes. A value of zero means that the current handler is not known. + * S_HARD_IGN indicates that the signal was ignored on entry to the shell, + */ + +#define S_DFL 1 /* default signal handling (SIG_DFL) */ +#define S_CATCH 2 /* signal is caught */ +#define S_IGN 3 /* signal is ignored (SIG_IGN) */ +#define S_HARD_IGN 4 /* signal is ignored permenantly */ +#define S_RESET 5 /* temporary - to reset a hard ignored sig */ + + + +/* + * The trap builtin. + */ + +int +trapcmd(int argc, char **argv) +{ + char *action; + char **ap; + int signo; + + nextopt(nullstr); + ap = argptr; + if (!*ap) { + for (signo = 0 ; signo < NSIG ; signo++) { + if (trap[signo] != NULL) { + const char *sn; + + sn = u_signal_names(0, &signo, 0); + if (sn == NULL) + sn = "???"; + out1fmt("trap -- %s %s\n", + single_quote(trap[signo]), sn); + } + } + return 0; + } + if (!ap[1]) + action = NULL; + else + action = *ap++; + while (*ap) { + if ((signo = decode_signal(*ap, 0)) < 0) + error("%s: bad trap", *ap); + INTOFF; + if (action) { + if (action[0] == '-' && action[1] == '\0') + action = NULL; + else + action = savestr(action); + } + if (trap[signo]) + ckfree(trap[signo]); + trap[signo] = action; + if (signo != 0) + setsignal(signo); + INTON; + ap++; + } + return 0; +} + + +/* + * Clear traps on a fork. + */ + +void +clear_traps(void) +{ + char **tp; + + for (tp = trap ; tp < &trap[NSIG] ; tp++) { + if (*tp && **tp) { /* trap not NULL or SIG_IGN */ + INTOFF; + ckfree(*tp); + *tp = NULL; + if (tp != &trap[0]) + setsignal(tp - trap); + INTON; + } + } +} + + +/* + * Set the signal handler for the specified signal. The routine figures + * out what it should be set to. + */ + +void +setsignal(int signo) +{ + int action; + char *t, tsig; + struct sigaction act; + + if ((t = trap[signo]) == NULL) + action = S_DFL; + else if (*t != '\0') + action = S_CATCH; + else + action = S_IGN; + if (rootshell && action == S_DFL) { + switch (signo) { + case SIGINT: + if (iflag || minusc || sflag == 0) + action = S_CATCH; + break; + case SIGQUIT: +#ifdef DEBUG + if (debug) + break; +#endif + /* FALLTHROUGH */ + case SIGTERM: + if (iflag) + action = S_IGN; + break; +#if JOBS + case SIGTSTP: + case SIGTTOU: + if (mflag) + action = S_IGN; + break; +#endif + } + } + + t = &sigmode[signo - 1]; + tsig = *t; + if (tsig == 0) { + /* + * current setting unknown + */ + if (sigaction(signo, 0, &act) == -1) { + /* + * Pretend it worked; maybe we should give a warning + * here, but other shells don't. We don't alter + * sigmode, so that we retry every time. + */ + return; + } + if (act.sa_handler == SIG_IGN) { + if (mflag && (signo == SIGTSTP || + signo == SIGTTIN || signo == SIGTTOU)) { + tsig = S_IGN; /* don't hard ignore these */ + } else + tsig = S_HARD_IGN; + } else { + tsig = S_RESET; /* force to be set */ + } + } + if (tsig == S_HARD_IGN || tsig == action) + return; + switch (action) { + case S_CATCH: + act.sa_handler = onsig; + break; + case S_IGN: + act.sa_handler = SIG_IGN; + break; + default: + act.sa_handler = SIG_DFL; + } + *t = action; + act.sa_flags = 0; + sigfillset(&act.sa_mask); + sigaction(signo, &act, 0); +} + +/* + * Ignore a signal. + */ + +void +ignoresig(int signo) +{ + if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { + signal(signo, SIG_IGN); + } + sigmode[signo - 1] = S_HARD_IGN; +} + + +/* + * Signal handler. + */ + +void +onsig(int signo) +{ + gotsig[signo - 1] = 1; + pendingsigs = signo; + + if (exsig || (signo == SIGINT && !trap[SIGINT])) { + if (!suppressint) + onint(); + intpending = 1; + } +} + + +/* + * Called to execute a trap. Perhaps we should avoid entering new trap + * handlers while we are executing a trap handler. + */ + +void +dotrap(void) +{ + char *p; + char *q; + int savestatus; + + savestatus = exitstatus; + q = gotsig; + while (pendingsigs = 0, barrier(), (p = memchr(q, 1, NSIG - 1))) { + *p = 0; + p = trap[p - q + 1]; + if (!p) + continue; + evalstring(p, 0); + exitstatus = savestatus; + } +} + + +/* + * Controls whether the shell is interactive or not. + */ + +void +setinteractive(int on) +{ + static int is_interactive; + + if (++on == is_interactive) + return; + is_interactive = on; + setsignal(SIGINT); + setsignal(SIGQUIT); + setsignal(SIGTERM); +#ifndef BB_FEATURE_SH_EXTRA_QUIET + if(is_interactive > 1) { + /* Looks like they want an interactive shell */ + static int do_banner; + + if(!do_banner) { + out1fmt( + "\n\n" BB_BANNER " Built-in shell (ash)\n" + "Enter 'help' for a list of built-in commands.\n\n"); + do_banner++; + } + } +#endif +} + + +#ifndef BB_FEATURE_SH_EXTRA_QUIET +/*** List the available builtins ***/ + +static int helpcmd(int argc, char **argv) +{ + int col, i; + + out1fmt("\nBuilt-in commands:\n-------------------\n"); + for (col = 0, i = 0; i < NUMBUILTINS; i++) { + col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), + builtincmd[i].name + 1); + if (col > 60) { + out1fmt("\n"); + col = 0; + } + } +#ifdef BB_FEATURE_SH_STANDALONE_SHELL + { + extern const struct BB_applet applets[]; + extern const size_t NUM_APPLETS; + + for (i = 0; i < NUM_APPLETS; i++) { + + col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name); + if (col > 60) { + out1fmt("\n"); + col = 0; + } + } + } +#endif + out1fmt("\n\n"); + return EXIT_SUCCESS; +} +#endif /* BB_FEATURE_SH_EXTRA_QUIET */ + +/* + * Called to exit the shell. + */ + +void +exitshell(void) +{ + struct jmploc loc; + char *p; + int status; + + status = exitstatus; + TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); + if (setjmp(loc.loc)) { + goto out; + } + handler = &loc; + if ((p = trap[0]) != NULL && *p != '\0') { + trap[0] = NULL; + evalstring(p, 0); + } + flushall(); +#ifdef BB_FEATURE_COMMAND_SAVEHISTORY + if (iflag && rootshell) { + const char *hp = lookupvar("HISTFILE"); + + if(hp != NULL ) + save_history ( hp ); + } +#endif +out: + _exit(status); + /* NOTREACHED */ +} + +static int decode_signal(const char *string, int minsig) +{ + int signo; + const char *name = u_signal_names(string, &signo, minsig); + + return name ? signo : -1; +} + +/* $NetBSD: var.c,v 1.32 2003/01/22 20:36:04 dsl Exp $ */ + +static struct var *vartab[VTABSIZE]; + +static int vpcmp(const void *, const void *); +static struct var **findvar(struct var **, const char *); + +/* + * Initialize the varable symbol tables and import the environment + */ + + +#ifdef BB_ASH_GETOPTS +/* + * Safe version of setvar, returns 1 on success 0 on failure. + */ + +int +setvarsafe(const char *name, const char *val, int flags) +{ + int err; + volatile int saveint; + struct jmploc *volatile savehandler = handler; + struct jmploc jmploc; + + SAVEINT(saveint); + if (setjmp(jmploc.loc)) + err = 1; + else { + handler = &jmploc; + setvar(name, val, flags); + err = 0; + } + handler = savehandler; + RESTOREINT(saveint); + return err; +} +#endif + +/* + * Set the value of a variable. The flags argument is ored with the + * flags of the variable. If val is NULL, the variable is unset. + */ + +static void +setvar(const char *name, const char *val, int flags) +{ + char *p, *q; + size_t namelen; + char *nameeq; + size_t vallen; + + q = endofname(name); + p = strchrnul(q, '='); + namelen = p - name; + if (!namelen || p != q) + error("%.*s: bad variable name", namelen, name); + vallen = 0; + if (val == NULL) { + flags |= VUNSET; + } else { + vallen = strlen(val); + } + INTOFF; + p = mempcpy(nameeq = ckmalloc(namelen + vallen + 2), name, namelen); + *p++ = '\0'; + if (vallen) { + p[-1] = '='; + p = mempcpy(p, val, vallen); + } + *p = '\0'; + setvareq(nameeq, flags | VNOSAVE); + INTON; +} + + +/* + * Same as setvar except that the variable and value are passed in + * the first argument as name=value. Since the first argument will + * be actually stored in the table, it should not be a string that + * will go away. + * Called with interrupts off. + */ + +void +setvareq(char *s, int flags) +{ + struct var *vp, **vpp; + + vpp = hashvar(s); + flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); + vp = *findvar(vpp, s); + if (vp) { + if (vp->flags & VREADONLY) { + if (flags & VNOSAVE) + free(s); + error("%.*s: is read only", strchrnul(s, '=') - s, s); + } + + if (flags & VNOSET) + return; + + if (vp->func && (flags & VNOFUNC) == 0) + (*vp->func)(strchrnul(s, '=') + 1); + + if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) + ckfree(vp->text); + + flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET); + } else { + if (flags & VNOSET) + return; + /* not found */ + vp = ckmalloc(sizeof (*vp)); + vp->next = *vpp; + vp->func = NULL; + *vpp = vp; + } + if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE))) + s = savestr(s); + vp->text = s; + vp->flags = flags; +} + + +/* + * Process a linked list of variable assignments. + */ + +static void +listsetvar(struct strlist *list_set_var, int flags) +{ + struct strlist *lp = list_set_var; + + if (!lp) + return; + INTOFF; + do { + setvareq(lp->text, flags); + } while ((lp = lp->next)); + INTON; +} + + +/* + * Find the value of a variable. Returns NULL if not set. + */ + +static char * +lookupvar(const char *name) +{ + struct var *v; + + if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) { + return strchrnul(v->text, '=') + 1; + } + return NULL; +} + + +/* + * Search the environment of a builtin command. + */ + +static char * +bltinlookup(const char *name) +{ + struct strlist *sp; + + for (sp = cmdenviron ; sp ; sp = sp->next) { + if (varequal(sp->text, name)) + return strchrnul(sp->text, '=') + 1; + } + return lookupvar(name); +} + + +/* + * Generate a list of variables satisfying the given conditions. + */ + +static char ** +listvars(int on, int off, char ***end) +{ + struct var **vpp; + struct var *vp; + char **ep; + int mask; + + STARTSTACKSTR(ep); + vpp = vartab; + mask = on | off; + do { + for (vp = *vpp ; vp ; vp = vp->next) + if ((vp->flags & mask) == on) { + if (ep == stackstrend()) + ep = growstackstr(); + *ep++ = (char *) vp->text; + } + } while (++vpp < vartab + VTABSIZE); + if (ep == stackstrend()) + ep = growstackstr(); + if (end) + *end = ep; + *ep++ = NULL; + return grabstackstr(ep); +} + + +/* + * POSIX requires that 'set' (but not export or readonly) output the + * variables in lexicographic order - by the locale's collating order (sigh). + * Maybe we could keep them in an ordered balanced binary tree + * instead of hashed lists. + * For now just roll 'em through qsort for printing... + */ + +static int +showvars(const char *sep_prefix, int on, int off) +{ + const char *sep; + char **ep, **epend; + + ep = listvars(on, off, &epend); + qsort(ep, epend - ep, sizeof(char *), vpcmp); + + sep = *sep_prefix ? spcstr : sep_prefix; + + for (; ep < epend; ep++) { + const char *p; + const char *q; + + p = strchrnul(*ep, '='); + q = nullstr; + if (*p) + q = single_quote(++p); + + out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q); + } + + return 0; +} + + + +/* + * The export and readonly commands. + */ + +static int +exportcmd(int argc, char **argv) +{ + struct var *vp; + char *name; + const char *p; + char **aptr; + int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; + int notp; + + notp = nextopt("p") - 'p'; + if (notp && ((name = *(aptr = argptr)))) { + do { + if ((p = strchr(name, '=')) != NULL) { + p++; + } else { + if ((vp = *findvar(hashvar(name), name))) { + vp->flags |= flag; + continue; + } + } + setvar(name, p, flag); + } while ((name = *++aptr) != NULL); + } else { + showvars(argv[0], flag, 0); + } + return 0; +} + + +/* + * Make a variable a local variable. When a variable is made local, it's + * value and flags are saved in a localvar structure. The saved values + * will be restored when the shell function returns. We handle the name + * "-" as a special case. + */ + +static inline void +mklocal(char *name) +{ + struct localvar *lvp; + struct var **vpp; + struct var *vp; + + INTOFF; + lvp = ckmalloc(sizeof (struct localvar)); + if (name[0] == '-' && name[1] == '\0') { + char *p; + p = ckmalloc(sizeof(optlist)); + lvp->text = memcpy(p, optlist, sizeof(optlist)); + vp = NULL; + } else { + char *eq; + + vpp = hashvar(name); + vp = *findvar(vpp, name); + eq = strchr(name, '='); + if (vp == NULL) { + if (eq) + setvareq(name, VSTRFIXED); + else + setvar(name, NULL, VSTRFIXED); + vp = *vpp; /* the new variable */ + lvp->flags = VUNSET; + } else { + lvp->text = vp->text; + lvp->flags = vp->flags; + vp->flags |= VSTRFIXED|VTEXTFIXED; + if (eq) + setvareq(name, 0); + } + } + lvp->vp = vp; + lvp->next = localvars; + localvars = lvp; + INTON; +} + +/* + * The "local" command. + */ + +static int +localcmd(int argc, char **argv) +{ + char *name; + + argv = argptr; + while ((name = *argv++) != NULL) { + mklocal(name); + } + return 0; +} + + +/* + * Called after a function returns. + * Interrupts must be off. + */ + +static void +poplocalvars(void) +{ + struct localvar *lvp; + struct var *vp; + + while ((lvp = localvars) != NULL) { + localvars = lvp->next; + vp = lvp->vp; + TRACE(("poplocalvar %s", vp ? vp->text : "-")); + if (vp == NULL) { /* $- saved */ + memcpy(optlist, lvp->text, sizeof(optlist)); + ckfree(lvp->text); + optschanged(); + } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { + unsetvar(vp->text); + } else { + if (vp->func) + (*vp->func)(strchrnul(lvp->text, '=') + 1); + if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) + ckfree(vp->text); + vp->flags = lvp->flags; + vp->text = lvp->text; + } + ckfree(lvp); + } +} + + +/* + * The unset builtin command. We unset the function before we unset the + * variable to allow a function to be unset when there is a readonly variable + * with the same name. + */ + +int +unsetcmd(int argc, char **argv) +{ + char **ap; + int i; + int flag = 0; + int ret = 0; + + while ((i = nextopt("vf")) != '\0') { + flag = i; + } + + for (ap = argptr; *ap ; ap++) { + if (flag != 'f') { + i = unsetvar(*ap); + ret |= i; + if (!(i & 2)) + continue; + } + if (flag != 'v') + unsetfunc(*ap); + } + return ret & 1; +} + + +/* + * Unset the specified variable. + */ + +int +unsetvar(const char *s) +{ + struct var **vpp; + struct var *vp; + int retval; + + vpp = findvar(hashvar(s), s); + vp = *vpp; + retval = 2; + if (vp) { + int flags = vp->flags; + + retval = 1; + if (flags & VREADONLY) + goto out; + if (flags & VUNSET) + goto ok; + if ((flags & VSTRFIXED) == 0) { + INTOFF; + if ((flags & (VTEXTFIXED|VSTACK)) == 0) + ckfree(vp->text); + *vpp = vp->next; + ckfree(vp); + INTON; + } else { + setvar(s, 0, 0); + vp->flags &= ~VEXPORT; + } +ok: + retval = 0; + } + +out: + return retval; +} + + + +/* + * Find the appropriate entry in the hash table from the name. + */ + +static struct var ** +hashvar(const char *p) +{ + unsigned int hashval; + + hashval = ((unsigned char) *p) << 4; + while (*p && *p != '=') + hashval += (unsigned char) *p++; + return &vartab[hashval % VTABSIZE]; +} + + + +/* + * Compares two strings up to the first = or '\0'. The first + * string must be terminated by '='; the second may be terminated by + * either '=' or '\0'. + */ + +int +varcmp(const char *p, const char *q) +{ + int c, d; + + while ((c = *p) == (d = *q)) { + if (!c || c == '=') + goto out; + p++; + q++; + } + if (c == '=') + c = 0; + if (d == '=') + d = 0; +out: + return c - d; +} + +static int +vpcmp(const void *a, const void *b) +{ + return varcmp(*(const char **)a, *(const char **)b); +} + +static struct var ** +findvar(struct var **vpp, const char *name) +{ + for (; *vpp; vpp = &(*vpp)->next) { + if (varequal((*vpp)->text, name)) { + break; + } + } + return vpp; +} +/* $NetBSD: setmode.c,v 1.29 2003/01/15 23:58:03 kleink Exp $ */ + +#include + +static const unsigned char timescmd_str[] = { + ' ', offsetof(struct tms, tms_utime), + '\n', offsetof(struct tms, tms_stime), + ' ', offsetof(struct tms, tms_cutime), + '\n', offsetof(struct tms, tms_cstime), + 0 +}; + +static int timescmd(int ac, char **av) +{ + long int clk_tck, s, t; + const unsigned char *p; + struct tms buf; + + clk_tck = sysconf(_SC_CLK_TCK); + times(&buf); + + p = timescmd_str; + do { + t = *(clock_t *)(((char *) &buf) + p[1]); + s = t / clk_tck; + out1fmt("%ldm%ld.%.3lds%c", + s/60, s%60, + ((t - s * clk_tck) * 1000) / clk_tck, + p[0]); + } while (*(p += 2)); + + return 0; +} + +#ifdef BB_ASH_MATH_SUPPORT +static int +dash_arith(const char *s) +{ + long result; + int errcode = 0; + + INTOFF; + result = arith(s, &errcode); + if (errcode < 0) { + if (errcode == -3) + error("exponent less than 0"); + else if (errcode == -2) + error("divide by zero"); + else if (errcode == -5) + error("expression recursion loop detected"); + else + synerror(s); + } + INTON; + + return (result); +} + + +/* + * The let builtin. partial stolen from GNU Bash, the Bourne Again SHell. + * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc. + * + * Copyright (C) 2003 Vladimir Oleynik + */ + +static int +letcmd(int argc, char **argv) +{ + char **ap; + long i; + + ap = argv + 1; + if(!*ap) + error("expression expected"); + for (ap = argv + 1; *ap; ap++) { + i = dash_arith(*ap); + } + + return (!i); +} +#endif /* BB_ASH_MATH_SUPPORT */ + +/* $NetBSD: miscbltin.c,v 1.31 2002/11/24 22:35:41 christos Exp $ */ + +/* + * Miscelaneous builtins. + */ + +#undef rflag + +#ifdef __GLIBC__ +#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 +typedef enum __rlimit_resource rlim_t; +#endif +#endif + + +/* + * The read builtin. The -e option causes backslashes to escape the + * following character. + * + * This uses unbuffered input, which may be avoidable in some cases. + */ + +static int +readcmd(int argc, char **argv) +{ + char **ap; + int backslash; + char c; + int rflag; + char *prompt; + const char *ifs; + char *p; + int startword; + int status; + int i; + + rflag = 0; + prompt = NULL; + while ((i = nextopt("p:r")) != '\0') { + if (i == 'p') + prompt = optionarg; + else + rflag = 1; + } + if (prompt && isatty(0)) { + out2str(prompt); + } + if (*(ap = argptr) == NULL) + error("arg count"); + if ((ifs = bltinlookup("IFS")) == NULL) + ifs = defifs; + status = 0; + startword = 1; + backslash = 0; + STARTSTACKSTR(p); + for (;;) { + if (read(0, &c, 1) != 1) { + status = 1; + break; + } + if (c == '\0') + continue; + if (backslash) { + backslash = 0; + if (c != '\n') + goto put; + continue; + } + if (!rflag && c == '\\') { + backslash++; + continue; + } + if (c == '\n') + break; + if (startword && *ifs == ' ' && strchr(ifs, c)) { + continue; + } + startword = 0; + if (ap[1] != NULL && strchr(ifs, c) != NULL) { + STACKSTRNUL(p); + setvar(*ap, stackblock(), 0); + ap++; + startword = 1; + STARTSTACKSTR(p); + } else { +put: + STPUTC(c, p); + } + } + STACKSTRNUL(p); + /* Remove trailing blanks */ + while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL) + *p = '\0'; + setvar(*ap, stackblock(), 0); + while (*++ap != NULL) + setvar(*ap, nullstr, 0); + return status; +} + + +static int umaskcmd(int argc, char **argv) +{ + static const char permuser[3] = "ugo"; + static const char permmode[3] = "rwx"; + static const short int permmask[] = { + S_IRUSR, S_IWUSR, S_IXUSR, + S_IRGRP, S_IWGRP, S_IXGRP, + S_IROTH, S_IWOTH, S_IXOTH + }; + + char *ap; + mode_t mask; + int i; + int symbolic_mode = 0; + + while (nextopt("S") != '\0') { + symbolic_mode = 1; + } + + INTOFF; + mask = umask(0); + umask(mask); + INTON; + + if ((ap = *argptr) == NULL) { + if (symbolic_mode) { + char buf[18]; + char *p = buf; + + for (i = 0; i < 3; i++) { + int j; + + *p++ = permuser[i]; + *p++ = '='; + for (j = 0; j < 3; j++) { + if ((mask & permmask[3 * i + j]) == 0) { + *p++ = permmode[j]; + } + } + *p++ = ','; + } + *--p = 0; + puts(buf); + } else { + out1fmt("%.4o\n", mask); + } + } else { + if (is_digit((unsigned char) *ap)) { + mask = 0; + do { + if (*ap >= '8' || *ap < '0') + error(illnum, argv[1]); + mask = (mask << 3) + (*ap - '0'); + } while (*++ap != '\0'); + umask(mask); + } else { + mask = ~mask & 0777; + if (!parse_mode(ap, &mask)) { + error("Illegal mode: %s", ap); + } + umask(~mask & 0777); + } + } + return 0; +} + +/* + * ulimit builtin + * + * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and + * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with + * ash by J.T. Conklin. + * + * Public domain. + */ + +struct limits { + const char *name; + int cmd; + int factor; /* multiply by to get rlim_{cur,max} values */ + char option; +}; + +static const struct limits limits[] = { +#ifdef RLIMIT_CPU + { "time(seconds)", RLIMIT_CPU, 1, 't' }, +#endif +#ifdef RLIMIT_FSIZE + { "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, +#endif +#ifdef RLIMIT_DATA + { "data(kbytes)", RLIMIT_DATA, 1024, 'd' }, +#endif +#ifdef RLIMIT_STACK + { "stack(kbytes)", RLIMIT_STACK, 1024, 's' }, +#endif +#ifdef RLIMIT_CORE + { "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, +#endif +#ifdef RLIMIT_RSS + { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' }, +#endif +#ifdef RLIMIT_MEMLOCK + { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, +#endif +#ifdef RLIMIT_NPROC + { "process(processes)", RLIMIT_NPROC, 1, 'p' }, +#endif +#ifdef RLIMIT_NOFILE + { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' }, +#endif +#ifdef RLIMIT_VMEM + { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' }, +#endif +#ifdef RLIMIT_SWAP + { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' }, +#endif + { (char *) 0, 0, 0, '\0' } +}; + +int +ulimitcmd(int argc, char **argv) +{ + int c; + rlim_t val = 0; + enum { SOFT = 0x1, HARD = 0x2 } + how = SOFT | HARD; + const struct limits *l; + int set, all = 0; + int optc, what; + struct rlimit limit; + + what = 'f'; + while ((optc = nextopt("HSatfdsmcnpl")) != '\0') + switch (optc) { + case 'H': + how = HARD; + break; + case 'S': + how = SOFT; + break; + case 'a': + all = 1; + break; + default: + what = optc; + } + + for (l = limits; l->name && l->option != what; l++) + ; + if (!l->name) + error("internal error (%c)", what); + + set = *argptr ? 1 : 0; + if (set) { + char *p = *argptr; + + if (all || argptr[1]) + error("too many arguments"); + if (strncmp(p, "unlimited\n", 9) == 0) + val = RLIM_INFINITY; + else { + val = (rlim_t) 0; + + while ((c = *p++) >= '0' && c <= '9') + { + val = (val * 10) + (long)(c - '0'); + if (val < (rlim_t) 0) + break; + } + if (c) + error("bad number"); + val *= l->factor; + } + } + if (all) { + for (l = limits; l->name; l++) { + getrlimit(l->cmd, &limit); + if (how & SOFT) + val = limit.rlim_cur; + else if (how & HARD) + val = limit.rlim_max; + + out1fmt("%-20s ", l->name); + if (val == RLIM_INFINITY) + out1fmt("unlimited\n"); + else + { + val /= l->factor; + out1fmt("%lld\n", (long long) val); + } + } + return 0; + } + + getrlimit(l->cmd, &limit); + if (set) { + if (how & HARD) + limit.rlim_max = val; + if (how & SOFT) + limit.rlim_cur = val; + if (setrlimit(l->cmd, &limit) < 0) + error("error setting limit (%m)"); + } else { + if (how & SOFT) + val = limit.rlim_cur; + else if (how & HARD) + val = limit.rlim_max; + + if (val == RLIM_INFINITY) + out1fmt("unlimited\n"); + else + { + val /= l->factor; + out1fmt("%lld\n", (long long) val); + } + } + return 0; +} + + +#ifdef BB_ASH_MATH_SUPPORT + +/* Copyright (c) 2001 Aaron Lehmann + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* This is my infix parser/evaluator. It is optimized for size, intended + * as a replacement for yacc-based parsers. However, it may well be faster + * than a comparable parser writen in yacc. The supported operators are + * listed in #defines below. Parens, order of operations, and error handling + * are supported. This code is threadsafe. The exact expression format should + * be that which POSIX specifies for shells. */ + +/* The code uses a simple two-stack algorithm. See + * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html + * for a detailed explaination of the infix-to-postfix algorithm on which + * this is based (this code differs in that it applies operators immediately + * to the stack instead of adding them to a queue to end up with an + * expression). */ + +/* To use the routine, call it with an expression string and error return + * pointer */ + +/* + * Aug 24, 2001 Manuel Novoa III + * + * Reduced the generated code size by about 30% (i386) and fixed several bugs. + * + * 1) In arith_apply(): + * a) Cached values of *numptr and &(numptr[-1]). + * b) Removed redundant test for zero denominator. + * + * 2) In arith(): + * a) Eliminated redundant code for processing operator tokens by moving + * to a table-based implementation. Also folded handling of parens + * into the table. + * b) Combined all 3 loops which called arith_apply to reduce generated + * code size at the cost of speed. + * + * 3) The following expressions were treated as valid by the original code: + * 1() , 0! , 1 ( *3 ) . + * These bugs have been fixed by internally enclosing the expression in + * parens and then checking that all binary ops and right parens are + * preceded by a valid expression (NUM_TOKEN). + * + * Note: It may be desireable to replace Aaron's test for whitespace with + * ctype's isspace() if it is used by another busybox applet or if additional + * whitespace chars should be considered. Look below the "#include"s for a + * precompiler test. + */ + +/* + * Aug 26, 2001 Manuel Novoa III + * + * Return 0 for null expressions. Pointed out by Vladimir Oleynik. + * + * Merge in Aaron's comments previously posted to the busybox list, + * modified slightly to take account of my changes to the code. + * + */ + +/* + * (C) 2003 Vladimir Oleynik + * + * - allow access to variable, + * used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6) + * - realize assign syntax (VAR=expr, +=, *= etc) + * - realize exponentiation (** operator) + * - realize comma separated - expr, expr + * - realise ++expr --expr expr++ expr-- + * - realise expr ? expr : expr (but, second expr calculate always) + * - allow hexdecimal and octal numbers + * - was restored loses XOR operator + * - remove one goto label, added three ;-) + * - protect $((num num)) as true zero expr (Manuel`s error) + * - always use special isspace(), see comment from bash ;-) + */ + + +#define arith_isspace(arithval) \ + (arithval == ' ' || arithval == '\n' || arithval == '\t') + + +typedef unsigned char operator; + +/* An operator's token id is a bit of a bitfield. The lower 5 bits are the + * precedence, and 3 high bits are an ID unique accross operators of that + * precedence. The ID portion is so that multiple operators can have the + * same precedence, ensuring that the leftmost one is evaluated first. + * Consider * and /. */ + +#define tok_decl(prec,id) (((id)<<5)|(prec)) +#define PREC(op) ((op) & 0x1F) + +#define TOK_LPAREN tok_decl(0,0) + +#define TOK_COMMA tok_decl(1,0) + +#define TOK_ASSIGN tok_decl(2,0) +#define TOK_AND_ASSIGN tok_decl(2,1) +#define TOK_OR_ASSIGN tok_decl(2,2) +#define TOK_XOR_ASSIGN tok_decl(2,3) +#define TOK_PLUS_ASSIGN tok_decl(2,4) +#define TOK_MINUS_ASSIGN tok_decl(2,5) +#define TOK_LSHIFT_ASSIGN tok_decl(2,6) +#define TOK_RSHIFT_ASSIGN tok_decl(2,7) + +#define TOK_MUL_ASSIGN tok_decl(3,0) +#define TOK_DIV_ASSIGN tok_decl(3,1) +#define TOK_REM_ASSIGN tok_decl(3,2) + +/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */ +#define convert_prec_is_assing(prec) do { if(prec == 3) prec = 2; } while(0) + +/* conditional is right associativity too */ +#define TOK_CONDITIONAL tok_decl(4,0) +#define TOK_CONDITIONAL_SEP tok_decl(4,1) + +#define TOK_OR tok_decl(5,0) + +#define TOK_AND tok_decl(6,0) + +#define TOK_BOR tok_decl(7,0) + +#define TOK_BXOR tok_decl(8,0) + +#define TOK_BAND tok_decl(9,0) + +#define TOK_EQ tok_decl(10,0) +#define TOK_NE tok_decl(10,1) + +#define TOK_LT tok_decl(11,0) +#define TOK_GT tok_decl(11,1) +#define TOK_GE tok_decl(11,2) +#define TOK_LE tok_decl(11,3) + +#define TOK_LSHIFT tok_decl(12,0) +#define TOK_RSHIFT tok_decl(12,1) + +#define TOK_ADD tok_decl(13,0) +#define TOK_SUB tok_decl(13,1) + +#define TOK_MUL tok_decl(14,0) +#define TOK_DIV tok_decl(14,1) +#define TOK_REM tok_decl(14,2) + +/* exponent is right associativity */ +#define TOK_EXPONENT tok_decl(15,1) + +/* For now unary operators. */ +#define UNARYPREC 16 +#define TOK_BNOT tok_decl(UNARYPREC,0) +#define TOK_NOT tok_decl(UNARYPREC,1) + +#define TOK_UMINUS tok_decl(UNARYPREC+1,0) +#define TOK_UPLUS tok_decl(UNARYPREC+1,1) + +#define PREC_PRE (UNARYPREC+2) + +#define TOK_PRE_INC tok_decl(PREC_PRE, 0) +#define TOK_PRE_DEC tok_decl(PREC_PRE, 1) + +#define PREC_POST (UNARYPREC+3) + +#define TOK_POST_INC tok_decl(PREC_POST, 0) +#define TOK_POST_DEC tok_decl(PREC_POST, 1) + +#define SPEC_PREC (UNARYPREC+4) + +#define TOK_NUM tok_decl(SPEC_PREC, 0) +#define TOK_RPAREN tok_decl(SPEC_PREC, 1) + +#define NUMPTR (*numstackptr) + +static inline int tok_have_assign(operator op) +{ + operator prec = PREC(op); + + convert_prec_is_assing(prec); + return (prec == PREC(TOK_ASSIGN) || + prec == PREC_PRE || prec == PREC_POST); +} + +static inline int is_right_associativity(operator prec) +{ + return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT) || + prec == PREC(TOK_CONDITIONAL)); +} + + +typedef struct ARITCH_VAR_NUM { + long val; + long contidional_second_val; + char contidional_second_val_initialized; + char *var; /* if NULL then is regular number, + else is varable name */ +} v_n_t; + + +typedef struct CHK_VAR_RECURSIVE_LOOPED { + const char *var; + struct CHK_VAR_RECURSIVE_LOOPED *next; +} chk_var_recursive_looped_t; + +static chk_var_recursive_looped_t *prev_chk_var_recursive; + + +static int arith_lookup_val(v_n_t *t) +{ + if(t->var) { + const char * p = lookupvar(t->var); + + if(p) { + int errcode; + + /* recursive try as expression */ + chk_var_recursive_looped_t *cur; + chk_var_recursive_looped_t cur_save; + + for(cur = prev_chk_var_recursive; cur; cur = cur->next) { + if(strcmp(cur->var, t->var) == 0) { + /* expression recursion loop detected */ + return -5; + } + } + /* save current lookuped var name */ + cur = prev_chk_var_recursive; + cur_save.var = t->var; + cur_save.next = cur; + prev_chk_var_recursive = &cur_save; + + t->val = arith (p, &errcode); + /* restore previous ptr after recursiving */ + prev_chk_var_recursive = cur; + return errcode; + } else { + /* allow undefined var as 0 */ + t->val = 0; + } + } + return 0; +} + +/* "applying" a token means performing it on the top elements on the integer + * stack. For a unary operator it will only change the top element, but a + * binary operator will pop two arguments and push a result */ +static inline int +arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr) +{ + long numptr_val; + v_n_t *numptr_m1; + long rez; + int ret_arith_lookup_val; + + if (NUMPTR == numstack) goto err; /* There is no operator that can work + without arguments */ + numptr_m1 = NUMPTR - 1; + + /* check operand is var with noninteger value */ + ret_arith_lookup_val = arith_lookup_val(numptr_m1); + if(ret_arith_lookup_val) + return ret_arith_lookup_val; + + rez = numptr_m1->val; + if (op == TOK_UMINUS) + rez *= -1; + else if (op == TOK_NOT) + rez = !rez; + else if (op == TOK_BNOT) + rez = ~rez; + else if (op == TOK_POST_INC || op == TOK_PRE_INC) + rez++; + else if (op == TOK_POST_DEC || op == TOK_PRE_DEC) + rez--; + else if (op != TOK_UPLUS) { + /* Binary operators */ + + /* check and binary operators need two arguments */ + if (numptr_m1 == numstack) goto err; + + /* ... and they pop one */ + --NUMPTR; + numptr_val = rez; + if (op == TOK_CONDITIONAL) { + if(! numptr_m1->contidional_second_val_initialized) { + /* protect $((expr1 ? expr2)) without ": expr" */ + goto err; + } + rez = numptr_m1->contidional_second_val; + } else if(numptr_m1->contidional_second_val_initialized) { + /* protect $((expr1 : expr2)) without "expr ? " */ + goto err; + } + numptr_m1 = NUMPTR - 1; + if(op != TOK_ASSIGN) { + /* check operand is var with noninteger value for not '=' */ + ret_arith_lookup_val = arith_lookup_val(numptr_m1); + if(ret_arith_lookup_val) + return ret_arith_lookup_val; + } + if (op == TOK_CONDITIONAL) { + numptr_m1->contidional_second_val = rez; + } + rez = numptr_m1->val; + if (op == TOK_BOR || op == TOK_OR_ASSIGN) + rez |= numptr_val; + else if (op == TOK_OR) + rez = numptr_val || rez; + else if (op == TOK_BAND || op == TOK_AND_ASSIGN) + rez &= numptr_val; + else if (op == TOK_BXOR || op == TOK_XOR_ASSIGN) + rez ^= numptr_val; + else if (op == TOK_AND) + rez = rez && numptr_val; + else if (op == TOK_EQ) + rez = (rez == numptr_val); + else if (op == TOK_NE) + rez = (rez != numptr_val); + else if (op == TOK_GE) + rez = (rez >= numptr_val); + else if (op == TOK_RSHIFT || op == TOK_RSHIFT_ASSIGN) + rez >>= numptr_val; + else if (op == TOK_LSHIFT || op == TOK_LSHIFT_ASSIGN) + rez <<= numptr_val; + else if (op == TOK_GT) + rez = (rez > numptr_val); + else if (op == TOK_LT) + rez = (rez < numptr_val); + else if (op == TOK_LE) + rez = (rez <= numptr_val); + else if (op == TOK_MUL || op == TOK_MUL_ASSIGN) + rez *= numptr_val; + else if (op == TOK_ADD || op == TOK_PLUS_ASSIGN) + rez += numptr_val; + else if (op == TOK_SUB || op == TOK_MINUS_ASSIGN) + rez -= numptr_val; + else if (op == TOK_ASSIGN || op == TOK_COMMA) + rez = numptr_val; + else if (op == TOK_CONDITIONAL_SEP) { + if (numptr_m1 == numstack) { + /* protect $((expr : expr)) without "expr ? " */ + goto err; + } + numptr_m1->contidional_second_val_initialized = op; + numptr_m1->contidional_second_val = numptr_val; + } + else if (op == TOK_CONDITIONAL) { + rez = rez ? + numptr_val : numptr_m1->contidional_second_val; + } + else if(op == TOK_EXPONENT) { + if(numptr_val < 0) + return -3; /* exponent less than 0 */ + else { + long c = 1; + + if(numptr_val) + while(numptr_val--) + c *= rez; + rez = c; + } + } + else if(numptr_val==0) /* zero divisor check */ + return -2; + else if (op == TOK_DIV || op == TOK_DIV_ASSIGN) + rez /= numptr_val; + else if (op == TOK_REM || op == TOK_REM_ASSIGN) + rez %= numptr_val; + } + if(tok_have_assign(op)) { + char buf[32]; + + if(numptr_m1->var == NULL) { + /* Hmm, 1=2 ? */ + goto err; + } + /* save to shell variable */ + sprintf(buf, "%ld", rez); + setvar(numptr_m1->var, buf, 0); + /* after saving, make previous value for v++ or v-- */ + if(op == TOK_POST_INC) + rez--; + else if(op == TOK_POST_DEC) + rez++; + } + numptr_m1->val = rez; + /* protect geting var value, is number now */ + numptr_m1->var = NULL; + return 0; +err: return(-1); +} + +/* longest must first */ +static const char op_tokens[] = { + '<','<','=',0, TOK_LSHIFT_ASSIGN, + '>','>','=',0, TOK_RSHIFT_ASSIGN, + '<','<', 0, TOK_LSHIFT, + '>','>', 0, TOK_RSHIFT, + '|','|', 0, TOK_OR, + '&','&', 0, TOK_AND, + '!','=', 0, TOK_NE, + '<','=', 0, TOK_LE, + '>','=', 0, TOK_GE, + '=','=', 0, TOK_EQ, + '|','=', 0, TOK_OR_ASSIGN, + '&','=', 0, TOK_AND_ASSIGN, + '*','=', 0, TOK_MUL_ASSIGN, + '/','=', 0, TOK_DIV_ASSIGN, + '%','=', 0, TOK_REM_ASSIGN, + '+','=', 0, TOK_PLUS_ASSIGN, + '-','=', 0, TOK_MINUS_ASSIGN, + '-','-', 0, TOK_POST_DEC, + '^','=', 0, TOK_XOR_ASSIGN, + '+','+', 0, TOK_POST_INC, + '*','*', 0, TOK_EXPONENT, + '!', 0, TOK_NOT, + '<', 0, TOK_LT, + '>', 0, TOK_GT, + '=', 0, TOK_ASSIGN, + '|', 0, TOK_BOR, + '&', 0, TOK_BAND, + '*', 0, TOK_MUL, + '/', 0, TOK_DIV, + '%', 0, TOK_REM, + '+', 0, TOK_ADD, + '-', 0, TOK_SUB, + '^', 0, TOK_BXOR, + /* uniq */ + '~', 0, TOK_BNOT, + ',', 0, TOK_COMMA, + '?', 0, TOK_CONDITIONAL, + ':', 0, TOK_CONDITIONAL_SEP, + ')', 0, TOK_RPAREN, + '(', 0, TOK_LPAREN, + 0 +}; +/* ptr to ")" */ +#define endexpression &op_tokens[sizeof(op_tokens)-7] + + +extern long arith (const char *expr, int *perrcode) +{ + register char arithval; /* Current character under analysis */ + operator lasttok, op; + operator prec; + + const char *p = endexpression; + int errcode; + + size_t datasizes = strlen(expr) + 2; + + /* Stack of integers */ + /* The proof that there can be no more than strlen(startbuf)/2+1 integers + * in any given correct or incorrect expression is left as an excersize to + * the reader. */ + v_n_t *numstack = alloca(((datasizes)/2)*sizeof(v_n_t)), + *numstackptr = numstack; + /* Stack of operator tokens */ + operator *stack = alloca((datasizes) * sizeof(operator)), + *stackptr = stack; + + *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ + *perrcode = errcode = 0; + + while(1) { + if ((arithval = *expr) == 0) { + if (p == endexpression) { + /* Null expression. */ + return 0; + } + + /* This is only reached after all tokens have been extracted from the + * input stream. If there are still tokens on the operator stack, they + * are to be applied in order. At the end, there should be a final + * result on the integer stack */ + + if (expr != endexpression + 1) { + /* If we haven't done so already, */ + /* append a closing right paren */ + expr = endexpression; + /* and let the loop process it. */ + continue; + } + /* At this point, we're done with the expression. */ + if (numstackptr != numstack+1) { + /* ... but if there isn't, it's bad */ + err: + return (*perrcode = -1); + } + if(numstack->var) { + /* expression is $((var)) only, lookup now */ + errcode = arith_lookup_val(numstack); + } + ret: + *perrcode = errcode; + return numstack->val; + } else { + /* Continue processing the expression. */ + if (arith_isspace(arithval)) { + /* Skip whitespace */ + goto prologue; + } + if((p = endofname(expr)) != expr) { + int var_name_size = (p-expr) + 1; /* trailing zero */ + + numstackptr->var = alloca(var_name_size); + safe_strncpy(numstackptr->var, expr, var_name_size); + expr = p; + num: + numstackptr->contidional_second_val_initialized = 0; + numstackptr++; + lasttok = TOK_NUM; + continue; + } else if (is_digit(arithval)) { + numstackptr->var = NULL; + numstackptr->val = strtol(expr, (char **) &expr, 0); + goto num; + } + for(p = op_tokens; ; p++) { + const char *o; + + if(*p == 0) { + /* strange operator not found */ + goto err; + } + for(o = expr; *p && *o == *p; p++) + o++; + if(! *p) { + /* found */ + expr = o - 1; + break; + } + /* skip tail uncompared token */ + while(*p) + p++; + /* skip zero delim */ + p++; + } + op = p[1]; + + /* post grammar: a++ reduce to num */ + if(lasttok == TOK_POST_INC || lasttok == TOK_POST_DEC) + lasttok = TOK_NUM; + + /* Plus and minus are binary (not unary) _only_ if the last + * token was as number, or a right paren (which pretends to be + * a number, since it evaluates to one). Think about it. + * It makes sense. */ + if (lasttok != TOK_NUM) { + switch(op) { + case TOK_ADD: + op = TOK_UPLUS; + break; + case TOK_SUB: + op = TOK_UMINUS; + break; + case TOK_POST_INC: + op = TOK_PRE_INC; + break; + case TOK_POST_DEC: + op = TOK_PRE_DEC; + break; + } + } + /* We don't want a unary operator to cause recursive descent on the + * stack, because there can be many in a row and it could cause an + * operator to be evaluated before its argument is pushed onto the + * integer stack. */ + /* But for binary operators, "apply" everything on the operator + * stack until we find an operator with a lesser priority than the + * one we have just extracted. */ + /* Left paren is given the lowest priority so it will never be + * "applied" in this way. + * if associativity is right and priority eq, applied also skip + */ + prec = PREC(op); + if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) { + /* not left paren or unary */ + if (lasttok != TOK_NUM) { + /* binary op must be preceded by a num */ + goto err; + } + while (stackptr != stack) { + if (op == TOK_RPAREN) { + /* The algorithm employed here is simple: while we don't + * hit an open paren nor the bottom of the stack, pop + * tokens and apply them */ + if (stackptr[-1] == TOK_LPAREN) { + --stackptr; + /* Any operator directly after a */ + lasttok = TOK_NUM; + /* close paren should consider itself binary */ + goto prologue; + } + } else { + operator prev_prec = PREC(stackptr[-1]); + + convert_prec_is_assing(prec); + convert_prec_is_assing(prev_prec); + if (prev_prec < prec) + break; + /* check right assoc */ + if(prev_prec == prec && is_right_associativity(prec)) + break; + } + errcode = arith_apply(*--stackptr, numstack, &numstackptr); + if(errcode) goto ret; + } + if (op == TOK_RPAREN) { + goto err; + } + } + + /* Push this operator to the stack and remember it. */ + *stackptr++ = lasttok = op; + + prologue: + ++expr; + } + } +} +#endif /* BB_ASH_MATH_SUPPORT */ + + +#ifdef DEBUG +const char *bb_applet_name = "debug stuff usage"; +int main(int argc, char **argv) +{ + return ash_main(argc, argv); +} +#endif + +/*- + * Copyright (c) 1989, 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Kenneth Almquist. + * + * 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. + */ diff --git a/basename.c b/basename.c new file mode 100644 index 000000000..bdbcec17a --- /dev/null +++ b/basename.c @@ -0,0 +1,52 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini basename implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +/* getopt not needed */ + +#include +#include "busybox.h" +#include + +extern int basename_main(int argc, char **argv) +{ + int m, n; + char *s; + + if ((argc < 2) || (**(argv + 1) == '-')) { + show_usage(); + } + + argv++; + + s = get_last_path_component(*argv); + + if (argc>2) { + argv++; + n = strlen(*argv); + m = strlen(s); + if (m>n && strncmp(s+m-n, *argv, n)==0) + s[m-n] = '\0'; + } + puts(s); + return EXIT_SUCCESS; +} diff --git a/busybox.c b/busybox.c new file mode 100644 index 000000000..f6e06425a --- /dev/null +++ b/busybox.c @@ -0,0 +1,172 @@ +/* vi: set sw=4 ts=4: */ +#include +#include +#include +#include +#include +#include "busybox.h" +#ifdef BB_LOCALE_SUPPORT +#include +#endif + +int been_there_done_that = 0; /* Also used in applets.c */ +const char *applet_name; + +#ifdef BB_FEATURE_INSTALLER +/* + * directory table + * this should be consistent w/ the enum, busybox.h::Location, + * or else... + */ +static const char usr_bin [] ="/usr/bin"; +static const char usr_sbin[] ="/usr/sbin"; +static const char* const install_dir[] = { + &usr_bin [8], /* "", equivalent to "/" for concat_path_file() */ + &usr_bin [4], /* "/bin" */ + &usr_sbin[4], /* "/sbin" */ + usr_bin, + usr_sbin +}; + +/* abstract link() */ +typedef int (*__link_f)(const char *, const char *); + +/* create (sym)links for each applet */ +static void install_links(const char *busybox, int use_symbolic_links) +{ + __link_f Link = link; + + char *fpc; + int i; + int rc; + + if (use_symbolic_links) + Link = symlink; + + for (i = 0; applets[i].name != NULL; i++) { + fpc = concat_path_file( + install_dir[applets[i].location], applets[i].name); + rc = Link(busybox, fpc); + if (rc!=0 && errno!=EEXIST) { + perror_msg("%s", fpc); + } + free(fpc); + } +} + +#endif /* BB_FEATURE_INSTALLER */ + +int main(int argc, char **argv) +{ + const char *s; + + applet_name = argv[0]; + + if (applet_name[0] == '-') + applet_name++; + + for (s = applet_name; *s != '\0';) { + if (*s++ == '/') + applet_name = s; + } + +#ifdef BB_LOCALE_SUPPORT +#ifdef BB_INIT + if(getpid()!=1) /* Do not set locale for `init' */ +#endif + { + setlocale(LC_ALL, ""); + } +#endif + + run_applet_by_name(applet_name, argc, argv); + error_msg_and_die("applet not found"); +} + + +int busybox_main(int argc, char **argv) +{ + int col = 0, len, i; + +#ifdef BB_FEATURE_INSTALLER + /* + * This style of argument parsing doesn't scale well + * in the event that busybox starts wanting more --options. + * If someone has a cleaner approach, by all means implement it. + */ + if (argc > 1 && (strcmp(argv[1], "--install") == 0)) { + int use_symbolic_links = 0; + int rc = 0; + char *busybox; + + /* to use symlinks, or not to use symlinks... */ + if (argc > 2) { + if ((strcmp(argv[2], "-s") == 0)) { + use_symbolic_links = 1; + } + } + + /* link */ + busybox = xreadlink("/proc/self/exe"); + if (busybox) { + install_links(busybox, use_symbolic_links); + free(busybox); + } else { + rc = 1; + } + return rc; + } +#endif /* BB_FEATURE_INSTALLER */ + + argc--; + + /* If we've already been here once, exit now */ + if (been_there_done_that == 1 || argc < 1) { + const struct BB_applet *a = applets; + + fprintf(stderr, "%s\n\n" + "Usage: busybox [function] [arguments]...\n" + " or: [function] [arguments]...\n\n" + "\tBusyBox is a multi-call binary that combines many common Unix\n" + "\tutilities into a single executable. Most people will create a\n" + "\tlink to busybox for each function they wish to use, and BusyBox\n" + "\twill act like whatever it was invoked as.\n" + "\nCurrently defined functions:\n", full_version); + + while (a->name != 0) { + col += + fprintf(stderr, "%s%s", ((col == 0) ? "\t" : ", "), + (a++)->name); + if (col > 60 && a->name != 0) { + fprintf(stderr, ",\n"); + col = 0; + } + } + fprintf(stderr, "\n\n"); + exit(0); + } + + /* Flag that we've been here already */ + been_there_done_that = 1; + + /* Move the command line down a notch */ + len = argv[argc] + strlen(argv[argc]) - argv[1]; + memmove(argv[0], argv[1], len); + memset(argv[0] + len, 0, argv[1] - argv[0]); + + /* Fix up the argv pointers */ + len = argv[1] - argv[0]; + memmove(argv, argv + 1, sizeof(char *) * (argc + 1)); + for (i = 0; i < argc; i++) + argv[i] -= len; + + return (main(argc, argv)); +} + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/busybox.h b/busybox.h new file mode 100644 index 000000000..1ef90bbd1 --- /dev/null +++ b/busybox.h @@ -0,0 +1,112 @@ +/* vi: set sw=4 ts=4: */ +/* + * Busybox main internal header 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 + * + * Based in part on code from sash, Copyright (c) 1999 by David I. Bell + * Permission has been granted to redistribute this code under the GPL. + * + */ +#ifndef _BB_INTERNAL_H_ +#define _BB_INTERNAL_H_ 1 + +#include "Config.h" + +#include +#include +#include +#include + +#define BB_BANNER "BusyBox v" BB_VER " (" BB_BT ")" + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +#include + + +enum Location { + _BB_DIR_ROOT = 0, + _BB_DIR_BIN, + _BB_DIR_SBIN, + _BB_DIR_USR_BIN, + _BB_DIR_USR_SBIN +}; + +struct BB_applet { + const char* name; + int (*main)(int argc, char** argv); + enum Location location; +}; +/* From busybox.c */ +extern const struct BB_applet applets[]; + +/* Automagically pull in all the applet function prototypes and + * applet usage strings. These are all of the form: + * extern int foo_main(int argc, char **argv); + * extern const char foo_usage[]; + * These are all autogenerated from the set of currently defined applets. + */ +#define PROTOTYPES +#include "applets.h" +#undef PROTOTYPES + +#ifdef BB_FEATURE_BUFFERS_GO_ON_STACK +#define RESERVE_BB_BUFFER(buffer,len) char buffer[len] +#define RESERVE_BB_UBUFFER(buffer,len) unsigned char buffer[len] +#define RELEASE_BB_BUFFER(buffer) ((void)0) +#else +#ifdef BB_FEATURE_BUFFERS_GO_IN_BSS +#define RESERVE_BB_BUFFER(buffer,len) static char buffer[len] +#define RESERVE_BB_UBUFFER(buffer,len) static unsigned char buffer[len] +#define RELEASE_BB_BUFFER(buffer) ((void)0) +#else +#define RESERVE_BB_BUFFER(buffer,len) char *buffer=xmalloc(len) +#define RESERVE_BB_UBUFFER(buffer,len) unsigned char *buffer=xmalloc(len) +#define RELEASE_BB_BUFFER(buffer) free (buffer) +#endif +#endif + + +/* Bit map related macros -- libc5 doens't provide these... sigh. */ +#ifndef setbit +#define NBBY CHAR_BIT +#define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY)) +#define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY))) +#define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY))) +#define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0) +#endif + +#ifndef RB_POWER_OFF +/* Stop system and switch power off if possible. */ +#define RB_POWER_OFF 0x4321fedc +#endif + + +/* Pull in the utility routines from libbb */ +#include "libbb/libbb.h" + +/* Try to pull in PATH_MAX */ +#include +/* for PATH_MAX on systems that don't have it in limits.h */ +#include +#ifndef PATH_MAX +#define PATH_MAX 256 +#endif + +#endif /* _BB_INTERNAL_H_ */ diff --git a/busybox.mkll b/busybox.mkll new file mode 100755 index 000000000..4e15e1611 --- /dev/null +++ b/busybox.mkll @@ -0,0 +1,24 @@ +#!/bin/sh +# Make busybox links list file. + +# input $1: full path to Config.h +# input $2: full path to applets.h +# output (stdout): list of pathnames that should be linked to busybox + +# Maintainer: Larry Doolittle + +export LC_ALL=POSIX +export LC_CTYPE=POSIX + +CONFIG_H=${1:-Config.h} +APPLETS_H=${2:-applets.h} +gcc -E -DMAKE_LINKS -include $CONFIG_H $APPLETS_H | + awk '/^[ \t]*LINK/{ + dir=substr($2,8) + gsub("_","/",dir) + if(dir=="/ROOT") dir="" + file=$3 + gsub("\"","",file) + if (file=="busybox") next + print tolower(dir) "/" file + }' diff --git a/busybox.sh b/busybox.sh new file mode 100755 index 000000000..9ab0f4bdb --- /dev/null +++ b/busybox.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +export LC_ALL=POSIX +export LC_CTYPE=POSIX + +RAW=` \ + $CC -E -dM ${1:-Config.h} | \ + sed -n -e '/^.*BB_FEATURE.*$/d;s/^#define.*\/\1.c/gp;' \ + | tr A-Z a-z | sort +` +test "${RAW}" != "" || exit +if [ -d "$BB_SRC_DIR" ]; then cd $BB_SRC_DIR; fi +# By running $RAW through "ls", we avoid listing +# source files that don't exist. +ls $RAW 2>/dev/null | tr '\n' ' ' + diff --git a/busybox.spec b/busybox.spec new file mode 100644 index 000000000..c44823acc --- /dev/null +++ b/busybox.spec @@ -0,0 +1,44 @@ +%define name busybox +%define epoch 0 +%define version 0.60.3 +%define release %(date -I | sed -e 's/-/_/g') +%define serial 1 + +Name: %{name} +#Epoch: %{epoch} +Version: %{version} +Release: %{release} +Serial: %{serial} +Copyright: GPL +Group: System/Utilities +Summary: BusyBox is a tiny suite of Unix utilities in a multi-call binary. +URL: http://busybox.net/ +Source: ftp://busybox.net/busybox/%{name}-%{version}.tar.gz +Buildroot: /var/tmp/%{name}-%{version} +Packager : Erik Andersen + +%Description +BusyBox combines tiny versions of many common UNIX utilities into a single +small executable. It provides minimalist replacements for most of the utilities +you usually find in fileutils, shellutils, findutils, textutils, grep, gzip, +tar, etc. BusyBox provides a fairly complete POSIX environment for any small +or emdedded system. The utilities in BusyBox generally have fewer options then +their full featured GNU cousins; however, the options that are provided behave +very much like their GNU counterparts. + +%Prep +%setup -q -n %{name}-%{version} + +%Build +make + +%Install +rm -rf $RPM_BUILD_ROOT +make PREFIX=$RPM_BUILD_ROOT install + +%Clean +rm -rf $RPM_BUILD_ROOT + +%Files +%defattr(-,root,root) +/ diff --git a/busybox/.cvsignore b/busybox/.cvsignore deleted file mode 100644 index 71269c542..000000000 --- a/busybox/.cvsignore +++ /dev/null @@ -1,4 +0,0 @@ -busybox -busybox.links -_install -applet_source_list diff --git a/busybox/.indent.pro b/busybox/.indent.pro deleted file mode 100644 index 492ecf1c7..000000000 --- a/busybox/.indent.pro +++ /dev/null @@ -1,33 +0,0 @@ ---blank-lines-after-declarations ---blank-lines-after-procedures ---break-before-boolean-operator ---no-blank-lines-after-commas ---braces-on-if-line ---braces-on-struct-decl-line ---comment-indentation25 ---declaration-comment-column25 ---no-comment-delimiters-on-blank-lines ---cuddle-else ---continuation-indentation4 ---case-indentation0 ---else-endif-column33 ---space-after-cast ---line-comments-indentation0 ---declaration-indentation1 ---dont-format-first-column-comments ---dont-format-comments ---honour-newlines ---indent-level4 -/* changed from 0 to 4 */ ---parameter-indentation4 ---line-length78 /* changed from 75 */ ---continue-at-parentheses ---no-space-after-function-call-names ---dont-break-procedure-type ---dont-star-comments ---leave-optional-blank-lines ---dont-space-special-semicolon ---tab-size4 -/* additions by Mark */ ---case-brace-indentation0 ---leave-preprocessor-space diff --git a/busybox/AUTHORS b/busybox/AUTHORS deleted file mode 100644 index 4258e5aa5..000000000 --- a/busybox/AUTHORS +++ /dev/null @@ -1,81 +0,0 @@ -List of the authors of code contained in BusyBox. - -If you have code in BusyBox, you should be listed here. If you should be -listed, or the description of what you have done needs more detail, or is -incorect, _please_ let me know. - - -Erik - ------------ - -Erik Andersen , - Tons of new stuff, major rewrite of most of the - core apps, tons of new apps as noted in header files. - -Edward Betts - expr, hostid, logname, tty, wc, whoami, yes - -John Beppu - du, head, nslookup, sort, tee, uniq - -Brian Candler - tiny-ls(ls) - -Randolph Chung - fbset, ping, hostname, and mkfifo - -Dave Cinege - more(v2), makedevs, dutmp, modularization, auto links file, - various fixes, Linux Router Project maintenance - -Larry Doolittle - pristine source directory compilation, lots of patches and fixes. - -Karl M. Hegbloom - cp_mv.c, the test suite, various fixes to utility.c, &c. - -Daniel Jacobowitz - mktemp.c - -Matt Kraai - documentation, bugfixes - -John Lombardo - dirname, tr - -Glenn McGrath - ar, dpkg, dpkg-deb - -Bruce Perens - Original author of BusyBox. His code is still in many apps. - -Kent Robotti - reset, tons and tons of bug reports and patchs. - -Chip Rosenthal , - wget - Contributed by permission of Covad Communications - -Pavel Roskin - Lots of bugs fixes and patches. - -Gyepi Sam - Remote logging feature for syslogd - -Linus Torvalds - mkswap, fsck.minix, mkfs.minix - -Mark Whitley - grep, sed, cut, xargs, style-guide, new-applet-HOWTO, bug fixes, etc. - -Charles P. Wright - gzip, mini-netcat(nc) - -Enrique Zanardi - tarcat (since removed), loadkmap, various fixes, Debian maintenance - -Vladimir Oleynik - cmdedit; ports: ash, stty, traceroute; locale, various fixes - and irreconcilable critic of everything not perfect. - -Tim Riker - bug fixes, member of fan club diff --git a/busybox/Changelog b/busybox/Changelog deleted file mode 100644 index 314bc8ab7..000000000 --- a/busybox/Changelog +++ /dev/null @@ -1,1276 +0,0 @@ -0.60.2.pre - - Stable Release - - - New Applets & New Features: - none. :) - - Known Problems (to be fixed in 0.60.2) - * msh can segfault on constructs such as - for i in `ls *.c` ; do echo $i ; done - due to a memory allocation problem. This only seems to cause - problems when the backtick expands to be several k in size. - - Bugfixes: - * Matt Kraai - -- Fix sed s/[/]// handling (noted by Dumas Patrice). - -- Fix dirname(3) improper consts, allow libc version to override. - -- Fixed invoking applets when their names contain a leading dash - and a full pathname. - -- Fix ash exec - -- Fixed basename to be SUSv2 compliant (which specifies that the - extension should stay if it is identical to the basename. - -- Fixed rmdir, since SuS2 says rmdir must provide -p - * Ethan Benson - -- Fix mount's noauto option to not automount as "usbdevfs" - * Vladimir Oleynik - -- Add support for `busybox --help APPLET' - -- Fixed route so it properly displays all route entries - -- Fix for ash leading redirections (i.e. '2>/dev/null ls rubbish') - * Laurence Anderson - -- Removed some traces of no-longer existant rpmunpack (which - has been obsoleted by the rpm2cpio applet). - -- Fixed unarchive.c to use the correct buffer when calling - dirname, improve an error message, and plug some memory leaks. - -- Fixed rpm2cpio.c mkfs_minix.c fsck_minix.c fbset.c to use - standard types (s/u16/u_int16_t/g s/u32/u_int32_t/g etc) - - - - -Erik Andersen, --not yet released-- - - - - - -0.60.1 - - Stable Release - - - New Applets & New Features: - none. :) - - Known Problems (to be fixed in 0.60.2) - * msh can segfault on constructs such as - for i in `ls *.c` ; do echo $i ; done - due to a memory allocation problem. This only seems to cause - problems when the backtick expands to be several k in size. - - - Bugfixes: - * Matt Kraai - -- Fixed msh to support underscores in variable names. - -- Fixed a sed problem with unsatisfied backrefs (the problem was - noted by Martin Bene). - -- Removed BB_SH define entirely. Now one simply picks the shell - or shells they want as BB_ in Config.h - -- Fixed head to use ferror(3) to check for errors, not errno. - * Shu-Hao Chang - -- Fixed sed handling of multiple -e commands - * Magick - -- Fixed an init bug with AskFirst and /dev/null - * Jaspreet Singh - -- Fixed both a segfault and cosmetic bug in route - * Erik Andersen - -- Made the insmod options BB_FEATURE_NEW_MODULE_INTERFACE and - BB_FEATURE_OLD_MODULE_INTERFACE mutually exclusive - -- xgetcwd.c now includes sys/param.h to ensure PATH_MAX is defined - -- Fixed a potential segfault with lash + BB_FEATURE_CLEAN_UP - -- Removed uint64_t from dos2unix, avoiding C lib compat. problems. - * Glenn McGrath - -- Rewrite of tftp (commands match atftp, accepts -b, can use - non-standard ports, and is smaller). - -- Fixed unarchive exclude list handling - * Manuel Novoa III - -- rewrite of simplify_path so it behaves itself (fixing some - problems with mount and other applets). - -- Fixed ifconfig 'broadcast +' handling and disabled it by default - * Matthias ? - -- Fixed syslogd to log all messages from a single connection, not - just the first. - - - -Erik Andersen, 23 August 2001 - - - - -0.60.0 - - Note: - - For this release I have bumped the version number to 0.60.0. This - reflects the fact that this release is intended to form a new stable - BusyBox release series. If you need to rely on a stable version of - BusyBox, you should plan on using the stable 0.60.x series. If bugs - show up then I will release 0.60.1, then 0.60.2, etc... This is also - intended to deal with the fact that the BusyBox build system will be - getting a major overhaul for the next release and I don't want that to - break products that people are shipping. To avoid that, the new build - system will be released as part of a new BusyBox development series - that will have some not-yet-decided-on odd version number. Once things - stabablize and the new build system is working for everyone, then I - will release that as a new stable release series. - - Critical Bugfixes: - * Matt Kraai - -- Fixed wget output file opening (wget failed in 0.52). - -- Fixed a memory leak in syslogd (found by Adam Slattery). - * Vladimir Oleynik, Matt Kraai, Erik Andersen - -- several nasty bugs in ash and msh. msh could not assign - any variables and had debug code still enabled. ash - had several compile errors (depending on selected options) - and variable assignment problems as well. - - New Applets: - * David McCullough -- modprobe - * Vladimir Oleynik -- traceroute - * Erik Andersen -- pidof - - New Scripts: - * David Schleef, Erik Andersen, Stuart Hughes -- depmod.pl - This is a replacement for the depmod program from the modutils - package, but is fully cross platform and is designed to run on - your host system (not on the target). - - Other Changes: - * Erik Andersen - -- fixed busybox.spec so it should now work on redhat systems - -- fixed dos2unix and unix2dos so they should work once again - -- Adjustments to make busybox more uClinux friendly. Busybox - should now work on uClinux systems without needing and source - code changes (applets that won't work on uClinux systems are - now automagicaly disabled). - -- various things (cleanups, libc compatibility work, etc, etc) - * Jim Gleason - -- Fixed for sed, where it failed to preserve whether or not the - line was previously altered when running a subst command. - * Matt Kraai - -- Made tar read 20 512byte blocks at a time (like GNU tar) - -- Allow msh.c assignments with the export and readonly commands. - -- Added BB_FEATURE_DEVFS to enable devfs device names. - -- Better devfs support - -- Don't save/restore vi readonly flag if vi is compiled read-only. - -- Reworked rdate option handling (is now smaller). - -- Size reduction in ping - -- Always write dd counts to stderr - -- Allow multiple shells to be enabled - * Aaron Lehmann - -- slimmed down md5sum - -- contributed a nice new (hand written, not lex/yacc) Posix math - support for ash, which is once again a full posix shell. - * Felix von Leitner -- patches to make busybox - work with dietlibc. - * David McCullough - -- Adjustments to make busybox more uClinux friendly - * Glenn McGrath - -- Fixed gzip so when a filename is '-' it will use stdin/stdout - -- dpkg rewrite. Should now be compatable with the real dpkg, - but needs more testing. - -- Updates to archiving tools (gunzip/gzip/cpio/ar/etc) - -- Rewrote uuencode, will allow base64 encoding to be used by wget - * Vladimir Oleynik - -- Fixed tr to support 'tr a-z A-Z' syntax, - -- Many ash corrections, optimizations, and cleanups. - -- optimizations for traceroute, md5sum, chown, ping - -- cmdedit updates and API change - -- Namespace cleanup (i.e. adding 'static' private function calls) - -- added "stopped jobs" warning to ash on exit - * Adam Slattery - -- Fixed ping compile problem - * Robert J. Osborne - -- fixed a vi bug with delete and escape sequences on empty files. - - - -Erik Andersen, 31 July 2001 - - - -0.52 - - Critical Bugfixes: - * Glenn McGrath -- Fixed gunzip, zcat when reading from stdin - * Marc Karasek and Kanoj (kernel serial.c maintainer) -- fixed init - problem on serial consoles with 2.4.3+ kernels. - - New Applets: - * Laurence Anderson -- rpm2cpio applet, this obsoletes rpmunpack - which has now been removed from BusyBox - * Laurence Anderson and Glenn McGrath -- cpio applet, currently - only supports unpacking the ascii cpio format. - * Vladimir Oleynik and Erik Andersen -- added ash, the most correct - busybox shell. - * Larry Doolittle -- hush, small shell designed specifically - for busybox. Quite usable but still a work in progress. - * Erik Andersen -- msh, minix shell. A very small but capable shell - that only uses vfork, so it can be used on uClinux systems. - - Other Changes: - * Sterling Huxley -- Several bugfixes for the vi applet. - * Glenn McGrath -- Restructure unarchiving code to make more code - common to the ar, cpio, dpkg, dpkg-deb applets. - tar applet has not yet been assimilated... - * Matt Kraai -- Rewrote cp, dirname, mkdir, mv, and rm. - * Paul J.Y. Lahaie -- Fixed an endian-ness - bug in md5sum (in 0.51, md5sum on big endian machines was broken) - * Mark Whitley -- rewrote cut, major updates to grep and sed. - * Erik Andersen -- bunches of insmod fixes. It should now always - work (no more segfault or missing symbols problems). - * Bernhard Kuhn and Jinux Kim - added uClinux/m68k insmod support. - * Manuel Novoa III -- rewrote make_human_readable so ls, du, and df - should work as expected. Eliminated use of floats. - * Aaron Lehmann -- Scrubbed gzip.c - * Alan Modra -- fixed an hard to spot - bug breaking gunzip checksum checking. - * Gennady Feldman -- Fixed 'syslog -C' - * Gernot Poerner -- Added mount bind support. - * Adam Heath -- wget arbitrary header support - * John Beppu -- updated the automagical doc generator - * Zillions of other bugfixes, optimizations, and cleanups. - - - - -Erik Andersen, 7 July 2001 - - -0.51 - Critical Bugfixes: - * Erik Andersen -- Fixed a bug that could crash the shell in 0.50 - when pressing on an empty line. - * Gennady Feldman -- Fixed a bug that could crash the shell in 0.50 - when performing an 'export' in the shell. - * Gennady Feldman -- fixed a syslogd bug where syslogd could cause - the init process to block (which can break systems badly). - - New Applets: - * Sterling Huxley -- contributed a new vi applet! This is a very - functional vi implementation in Only 22k. - * Erik Andersen -- added env applet - - Other changes: - * Erik Andersen -- Split utility.c into libbb, which provides a - much cleaner was for us to include shared functionality. - * Erik Andersen -- Reorganized how and when busybox includes - syscalls, aiding portability and (in this case) making the - busybox work on ia64 systems. - * Erik Andersen -- dpkg.c cleanup to use the updated gunzip interface. - * Erik Andersen -- Cleanups for libc5, glibc, and uClibc. - * Erik Andersen and Matt Kraai -- Cleanups for the human-readable - output from ls, du, and df. - * Laurence Anderson -- Fixed wget HTTP 1.1 - support and added chunked encoding so it is now RFC compliant. - * John Beppu -- The busybox.pod documentation is now automagically - generated from the source code. This makes it _much_ simpler. - Now to update the docs, just update the usage message... - * Dirk Behme -- Adjusted MIPS insmod - support a bit for Mips RS3. - * Christophe Boyanique -- egrep invoked the "init" applet in 0.50! - * Larry Doolittle -- Added -Wshadow and fixed a number of shadowed - variables - * David Douthitt -- fixed 'find -print' - * Gennady Feldman -- fixes for the syslogd circular buffer code - * Jeff Garzik -- a number of structural cleanups, fixes for -Wshadow - bugs, and similar problems. - * Matt Kraai -- Added a new 'shutdown' action to busybox init. Now - you can specify arbitrary behavior for 'ctrlaltdel' so now - pressing CTL-ALT-DEL can do something else (or nothing). - * Andreas Neuhaus -- fix for merging - kernel command line environment variables into child environment - for init.c - * Glenn McGrath -- Fixed problems with dpkg and dpkg-deb applets - * Glenn McGrath -- Don't try to automount devfs - * Vladimir Oleynik -- optimizations for more.c - * Vladimir Oleynik -- Added locale support to the shell, and fixed - locale support in several other places - * Vladimir Oleynik -- moved struct applet from busybox.c to applets.c - * Vladimir Oleynik -- A size optimization for rdate - * Vladimir Oleynik -- Fixed printf applets's locale handling - * Vladimir Oleynik -- More cmdedit updates - * Vladimir Oleynik -- Fixed `du' applet so it continues running - after permission errors. - * Vladimir Oleynik -- Reduced stack usage in recursive_action() - * Pierre Peiffer -- made - find_pid_by_name() cope with swapped out processes. - * Jari Ruusu -- updates so that setting - D_FILE_OFFSET_BITS=64 now works as expected. - * Anthony Towns -- fixed a bug with - sed address range handling - * Dmitry Zakharov -- a number of updates - to wget: support for ftp downloads, basic HTTP basic auth, handling - of http redirects, when attempting to continue an aborted download - but server doesn't support restarts then reopen output file in - write mode, bugfix: when content-length not given, wget didn't - download anything, if -c is not specified, it no longer default to - restarting an aborted download. - - - -Erik Andersen, 10 April 2001 - - -0.50 - * Erik Andersen -- added ifconfig interface status reporting - * Erik Andersen -- Debian packaging updates - * Erik Andersen -- lash environment variable expansion rewritten, - with lots of help/fixes/testing from Larry Doolittle. - * Erik Andersen -- Fix use of busybox with dmalloc debugging lib - * Erik Andersen -- fixed ls behavior for broken or very narrow terminals - * Erik Andersen -- stub umount2 and pivot_root if they are not available - * Erik Andersen -- libc5 fixes - * Erik Andersen -- make init work with devfsd - * Erik Andersen -- fixed df for nfs and dos where blksize = 512 - * Erik Andersen -- Make sure libpwd.a is linked _last_ so it - overrides the system pwd/grp - * Christophe Boyanique -- added an optional egrep alias for grep. - * Christophe Boyanique -- added optional 'rm -i' support. - * Kenneth Chalmers and Erik Andersen -- fixed ln so it - behaves when given no arguments (prints usage) and when - given just one arg (tries to make a link in the cwd). - * Magnus Damm -- added a tftp applet - * Magnus Damm -- powerpc support for busybox insmod. - * David Douthitt -- fixed a build error in df.c when - BB_FEATURE_HUMAN_READABLE was disabled - * John Beppu -- wrote autodocifier.pl, which will be used to auto- - generate the documentation from the source code, making life - much simpler for all. - * Magnus Damm -- Fixed an 'inner scope var - masking outer scope var with same name' bug that prevented - the loopback device from being unmounted if mount() failed. - * Larry Doolittle -- rewrote ifconfig to make it smaller - * Larry Doolittle and Erik Andersen -- cleanups to pristine source - * Larry Doolittle -- many bugfixes resulting from regression testing - * Gennady Feldman -- split syslogd.c into syslogd and klogd - * Gennady Feldman -- make syslogd single threaded -- no more forking - * Jeff Garzik -- getopt-ified rmmod. - * Jeff Garzik -- glibc 2.2 warning cleanups - * Jeff Garzik -- namespace pollution cleanup (staticified variables). - * Erik Gustavsson -- allow env variables set on the - kernel command line to be inherited into init and its children. - * Erik Habbinga -- fixed an uninitialized substitution delimiter in sed. - * Chris Jaeger -- Makefile cleanup to make option setting less error-prone - * Chris Jaeger -- Carefully check NFS_MOUNT_VERSION - depending on what kernel is being used. - * Quinn Jensen -- MIPS support for busybox insmod. - * Evin Robertson -- new pivot_root applet - * Kent Robotti -- usage message cleanups - * Kent Robotti -- reworked dos2unix/unix2dos - * Evin Robertson and Manuel Novoa III -- reworked how usage messages - are stored to save several k of space. - * Matt Kraai -- Keep trying if an NFS mount fails - * Matt Kraai -- fixed insmod so it won't try to insmod directories. - * Matt Kraai -- added nc listening support - * Matt Kraai and David Douthitt -- reworked fine to support -type, - -perm, -mtime, and other improvements. - * Matt Kraai -- added find_applet_by_name and saved some memory thereby - * Matt Kraai -- added chomp to reduce redundant code elsewhere - * Matt Kraai -- Removed trailing \n chars from error_msg{,_and_die} messages. - * John Lombardo -- fixed OOM in insmod. - * Glenn McGrath -- bypass /proc in mount, now uses sysfs. - * Glenn McGrath -- several updates to dpkg and dpkg-deb. - * Manuel Novoa III -- several size optimizations: parse_mode, - process_escape_sequence, format, and get_kernel_revision. - * Manuel Novoa III -- rewrote ifconfig again to make it smaller still - * Manuel Novoa III -- added ifconfig -a, updated interface reporting - * Vladimir N. Oleynik -- Fixed a bug where init set PATH incorrectly - * Vladimir N. Oleynik -- cleanups to route, cmdedit, mkdir, - mkfs_minix, mkswap, chmod_chown_chgrp and utility.c - * Vladimir N. Oleynik -- many fixes to cmdedit. so tab completion - is now working and general editing is much improved, and to - improve complex prompt handling. - * Vladimir N. Oleynik -- added route status reporting. - * Vladimir N. Oleynik -- fixed wget to use xfopen - * Vladimir N. Oleynik -- new stty applet - * Vladimir N. Oleynik -- fixed find, it used to stop on perm errors. - * Vladimir N. Oleynik -- locale forced to posix for scripts - * Vladimir N. Oleynik -- saved 128 bytes by moving error checking - for several my_* functions into utility.c - * Bjorn Wesen -- new ifconfig and route applet (taken from - work done by Axis Communications). - * Mark Whitley -- Added a 'How to contribute to Busybox' doc - and updated the style guide. - * Mark Whitley -- implemented grep -A, -B, and -C - * Mark Whitley -- overhauled the test suite. - - - -Erik Andersen, 15 March 2001 - -0.49 - - * Matt Kraai -- new sort.c - * Matt Kraai -- new tail.c - * Glenn McGrath -- new 'dpkg-deb' applet - * Glenn McGrath -- new ar code - * spoon -- new watchdog applet - * Vladimir N. Oleynik -- fixed cmdedit.c so now - scrolling and tab completion in lash work properly. Also several - byte saving optimizations. - * Erik Andersen -- disabled many less commonly used applets by default - * Mark Whitley -- more thrashing about to get clean perror_msg usage - * Matt Kraai -- new command line munging - * Larry Doolittle -- keep some locales from messing up busybox.sh - * Matt Kraai -- cleaned up dd and tail with new parse_number routine - * Mark Whitley -- remove debugging messages from deallocvt - * Matt Kraai and Mark Whitley -- new document "How to Add a New Applet - to BusyBox" - * David Douthitt -- fixed "grep -qv" bug - * Larry Doolittle -- fixed insmod bug with old kernels - * Matt Kraai -- logger remixed to use getopt, selection of stdin made - util-linux compatible - * Erik Andersen -- many more internal symbols classified static to - avoid namespace pollution - * Matt Kraai -- nc listening support - * Erik Andersen -- made sed understand arbitrary regexp delimiters - * Matt Kraai et al. -- more tar improvements and bug fixes, now - handles regexp file exclusion - * Larry Doolittle -- new script (multibuild.pl) to automate build rule - checking - * Matt Kraai -- update/cleanup of the docs on how to use init - * Erik Andersen -- renamed all sh.c symbols per the style guide, - better if-then-else-fi handling - * Erik Andersen -- cleaner division of labor between cmdedit.c and sh.c - * Larry Doolittle -- shell data structure cleanup, fixed buglets - in read, exec, and piped builtins - * Erik Andersen -- md5sum was broken in 0.48. Now fixed (and doesn't - use getline, shrinking static compiles (since nothing else used it). - * ?? -- squashed memory leak in shell prompt handling - * Mark Whitley -- Updates to style guide - * Mark Whitley -- Big cleanup in utility.c: style guide compliance, - de-macro-ifying some variables and functions - * Erik Andersen -- ls now honors BB_FEATURE_AUTOWIDTH so it can find - the width and height of the console. - * Erik Andersen -- insmod now ignores -L and accepts the -o option. - * Erik Andersen -- updates so you can now select from the Makefile - whether or not to use the system's passwd and group functions. - Since most systems use GNU libc, this can save you from having to - install the /etc/nsswitch.conf configuration file and the required - libnss_* libraries. Adds 1.5k. You can now, also, disable this, - causing busybox to use the system's pwd.h and grp.h functions. - - - -Erik Andersen, 27 January 2001 - -0.48 - - * Glenn McGrath -- tar now supports uncompressing tar files, - define BB_FEATURE_TAR_GZIP to use the -z option. - * Matt Kraai -- fix all usage of TRUE and FALSE so all apps now - return EXIT_SUCCESS or EXIT_FAILURE to the system. - Now TRUE and FALSE are set to the C standard where TRUE=1. - * me -- Fixed uname problem causing the kernel version to be - mis-detected (causing problems with poweroff, init, - and other things). - * Alcove, Julien Gaulmin and - Nicolas Ferre -- insmod support on ARM - and StrongArm, and suport for lsmod on older 2.0.x kernels. - * Kent Robotti -- Renamed unrpm to original rpmunpack, so you can use - an included shell script called unrpm as a front end to it. There's - also a shell script called undeb included for debian packages. - * Matt Kraai -- fix an infinite loop with ls -aR - * Larry Doolittle -- Shaved off about 100 bytes and 200 bytes heap - from date.c. Also document the "-d" option in the usage message. - * Gennady Feldman -- fixed dd to use blocksize when reading/writing, - (it was reading the whole thing and then writing it out). Also - updated usage information (was missing conv=notrunc) and added - conv=sync feature. - * Larry Doolittle (in collaboration with Matt Kraai) -- allow for a - pristine source directory -- where all the .o files and such are - not placed into the source tree. Thanks Larry! - * Larry Doolittle -- use the applet definitions in applets.h - to autogenerate the applet function and usage prototypes. - * Sebastien Huet, Arne Bernin, and Kent Robotti -- Add in tar -X and - fixed a bug breaking tar --exclude. - * Jonas Holmberg -- echo option handling made GNU-echo compatible - * Aleksey Demidov -- date option handling made - GNU-date compatible - * me -- Progress meter (optional) in wget - * Doolittle/me -- programs invoked by full path name take - precedence over applets unless BB_FEATURE_SH_BUILTINS_ALWAYS_WIN - * Gaute B Strokkenes -- applets found using a - binary search instead of linear search. Much faster! - * new applets: cmp readlink - * Mark Whitley -- Removed advertising clause of Berkeley license - according to decision by the Regents of the University of - California; included reference - * tail's confusing special treatment of single digit options removed; - people should use -n instead - * Larry Doolittle -- \r handled now in echo and tr - * Matt Kraai -- rewrite of uniq - * Mark Whitley -- remix of xargs - * Jim Gleason -- fixed tar so it no longer breaks - hard links. - * Matt Kraai -- logger now logs all arguments, not just the first - * Gennady Feldman -- syslogd no longer logs to localhost if compiled - for remote logging... - * Richard June -- support for 'gzip -d' - * various artists -- Other good stuff that I forgot to document. - - - -Erik Andersen, 13 December 2000 - -0.47 - - * A bug in syslogd was fixed that allowed it to potentially fork-bomb - your system. Anyone using 0.46 syslogd should upgrade. - * Renamed busybox.defs.h to the more sensible "Config.h" - * Improved portability between different libcs. - * Many apps ported to use getopt() - * Common handling of '--help' - * All usage messages centralized. - * Added a bunch of new commands: - * 'rdate' contributed by Sterling Huxley - * 'wget' contributed by Chip Rosenthal , - and Covad Communications - * 'getopt' from "Alfred M. Szmidt" - * dos2unix, unix2dos, reset, and unrpm.c (and lots of help - debugging) thanks to Kent Robotti . - * 'renice' command, thanks to Dave Cinege - * 'xargs' (written by me) - * 'expr' contributed by Edward Betts , based - on GNY expr - * lsmod now uses the query_module syscall, rather then /proc (me) - * syslogd can now log messages to remote hosts -- patch thanks - to Gyepi Sam - * chroot can now call the builtin shell - Pavel Roskin - * 'make install' now creates relative symlinks, and added a new - 'make install-hardlinks' target to (tada) install hardlinks. - * Rewrite of 'tail' to make it simpler, smaller, and more robust. - It now weighs only 2.25k (3k when full featured). The code is - cleaner too, thanks to Allen Soard - * Add optional ls file sorting, thanks to a patch from - Sterling Huxley - * Fixed chmod option parsing so things like 'chmod -r /tmp/file' - now work (previously it thought -r was an option). Doh! - * Fixed tar handling of stdin and stdout - * Renamed "internal.h" to the more sensible "busybox.h" - * Preliminary support for GNU HURD. - * Updated my devps and devmtab kernel patches for the latest 2.2.x - kernel, for those wanting to go proc-less. - * Tons of other bugfixes. - - - -Erik Andersen, 25 September 2000 - - -0.46 - - * Better portability. Now should compile cleanly with libc5, - GNU libc 2.0 and 2.1, and various Linux kernels including - 2.0.x, 2.2.x, and to 2.4.0-test*. (patch for 2.4.x kernels - to make /proc/mounts behave included in the kernel-patches dir). - * Fixed a _horrible_ bug where 'tar -tvf' could unlink - local files that matched tarball contents!!! Fix thanks - to Marius Groeger - * Fixed a nasty bug in tar when could mess up saved symlinks. - * Fixed tar creation support when reading from stdin ('tar -cf - . ') - thanks to Daniel Quinlan - * Updates to handle Linux 2.4.0 kernels (kludged around the - "none" entries in /proc/mounts, added a hack to make sysinfo - work with both old and new kernels). - * Fixed insmod module option parsing for options lacking an '='. - Fix thanks to Marc Nijdam - * Fixed segfault with 'cut -f 1 -d:' and added 'cut -s' suport. - Fix thanks to Arne Bernin - * Several fixes from Marius Groeger - - Added support for "sh -c command args..." - - Fixed globbing, i.e. 'echo * *' and 'echo "******"' now work. - - Added shell environment variable substitution - - Added the "read" shell builtin. - * Fixed cursor editing in cmdedit.c. The following keyboard sequence - used to create an infinite loop: ls, cursor up, left, down. - * Added support for being a login shell, so things like - '-su' or '-sh' (stuff where argv[0][0]=='-') will now always - invoke the shell. Now you can use BusyBox as a login shell. - * ls.c now ignores '-g', since some ftp clients like that sort - of thing. Patch thanks to David Vrabel - * Fix to init.c from Stuart Menefy so that - it always sets the controlling terminal before running any programs - * Several fixes from Matt Kraai - - Fixed tr so it recognizes standard escape sequences. - Merged common escape seq. code from tr and echo into utility.c. - - Major work in updating/cleaning up the docs, and getting the - new SGML based docs into shape. - - cleanup of ar.c - - BusyBox should now poweroff when asked to do so. - - Fixed 'ln -n' and 'ln -s' so they both work properly. - * Reorganized signal names in kill.c for better architecture support - -- patch thanks to simon wood - * In 0.43, backspace and delete worked properly, but with 0.45, - it just echoed a ^? for backspace, and ^H for control-h. This - was due to a broken macro in init.c, that is now fixed. - * Removed sfdisk from BusyBox. It was buggy, fat, and we really - couldn't maintain it very well, so including it was not really - very appropriate. Those wanting an fdisk are invited to - grab a copy from util-linux. - * Added 'dumpkmap' to allow people to dump a binary keymap, which can - then be loaded in by 'loadkmap' -- submitted by - Arne Bernin - * Fixed NFS so it supports 2.4.x kernels and NFSv3. - * Brand, new versions of grep and sed which use libc regex routines, - thanks to Mark Whitley . The hand-tooled - "regexp.[ch]" files have been removed. Much help on these from - Matt Kraai as well. - - - -Erik Andersen, 11 July 2000 - - -0.45 - * Now compiles vs libc5 (which can save lots of space for - embedded systems). - * Added BB_FEATURE_TRIVIAL_HELP which compiles out most all of the - help messages (i.e --help). Saves 17k over a full compile. - * Added cut and tr from minix, since due to the license change, - we can now use minix code. Minix tr saves 4k. - * insmod now works. It costs 29k, but imagine an initrd with a - staticly linked busybox containing only insmod and sh, a few /dev - entries, and a kernel module or two... It doesn't get smaller - then this folks (I pity the fool that writes insmod in asm ;-). - Many kudos go to Ron Alder for finishing this off! - * Added a mini ar archive utility, especially written for BusyBox by - Glenn McGrath - * Added mktemp, contributed by Daniel Jacobowitz - * Added setkeycodes, for those that have wierd keyboard buttons. - * Added md5sum, uuencode and uudecode -- thanks to Alfred M. Szmidt - for contributing these. - * Added 'grep -v' option (inverted search) and updated - docs accordingly. -beppu - * Wrote which - * Replaced the telnet implementation with one written by - Tomi Ollila It works great and costs 3k. - * BusyBox sh (lash) now supports being used as a standalone shell. When - BB_FEATURE_SH_STANDALONE_SHELL is defined, all the busybox commands may - be invoked as shell internals. Best used when compiling staticly - (i.e. DOSTATIC=true) - * BusyBox sh (lash) internals now behave as expected wrt pipes - and redirects. - * Fixed ping warnings -- fix from Sascha Ziemann - * Fixed update segfault - * Fixed mknod -- minor number was always 0 - * Fixed tar option parsing, so both "tar xvf foo.tar" and - "tar -xvf foo.tar" now work (i.e. no "-" before options) - (this was very broken in 0.43). - * Several contributions from Randolph Chung . - * cp/mv now accepts the -f flag - * tail can now accept - commands (e.g. -10) for better - compatibility with the standard tail command - * added a simple id implementation; doesn't support sup. groups yet - * logname used getlogin(3) which uses utmp. Now it doesn't. - * whoami used getpwuid(3) which uses libc NSS. Now it behaves. - * Add support for "noatime" and "nodiratime" mount flags to mount. - * Changed 'umount -f' to mean force, and actually use umount2. - * Changed 'umount -l' to mean "Do not free loop device". - * Fixed basename to support stripping of suffixes. Patch thanks - to xiong jianxin - * cp -fa now works as expected for symlinks (it didn't before) - * zcat now works (wasn't working since option parsing was broken) - * Renamed "mnc" to the more correct "nc" (for netcat). - * Makefile intelligence updates - * Changed the way init parses /etc/inittab entries to avoid problems - with commands that contain colons in them. Fix thanks to - Pavel Roskin - * Fixed a warning in utility.c due to char being unsigned on Linux/PPC, - Fix thanks to Pavel Roskin - * Made "killall" complain (not error and exit) about processes that it - cannot find by name -- Pavel Roskin - * Fixed more and ps to have sensible terminal width defaults, thanks - to Pavel Roskin. - * Fixed all fatalError() calls lacking a "\n", thanks to Pavel Roskin. - * Fixed a segfault in yes when no args were given -- Pavel Roskin. - * Simplified freeramdisk and added argument checking -- Pavel Roskin. - * Fixed segfault caused by "touch -c" - * Fixed segfault caused by "rm -f" - * Fixed segfault caused by "ln -s -s" and similar abuses. Further fixes - and "--" support from Pavel Roskin. - * Fixed segfault caused by "cp -a -a" and similar abuses. - * Implemented "rm -- ". Implementation fixed by Pavel Roskin. - * "which" rewritten to use stat(). Fixes to improve its compatability - with traditional implementations -- Pavel Roskin. - * "mount" now reports errors from nfsmount() and assumes NFS mount - if ':' is present in the device name - Pavel Roskin - * Fixed exit status for killall - Pavel Roskin - * Fixed 'swapon -a' and 'swapoff -a', which were broken. - * Fixed 'mount -a' so it works as expected. - * Implemented 'ls -R' (enabled by enabling BB_FEATURE_LS_RECURSIVE) - * Implemented "ping -s", fixed error messages and argument parsing - - Pavel Roskin - * Syslogd will not go to background if "-n" is given. Better help - and argument checking -- Pavel Roskin - * Fixed a small bug that could cause tar to emit warning messages - and not extract the first file in a directory in some cases - of nested directories. Thanks to Kevin Traas - for helping track this one down. - * More doc updates - * Fixed grep "Line too long" problem -- John Beppu - * Fixed 'grep -q -i B some_file' so it works - * math takes input from stdin if no args are given. -- John Beppu - * math was renamed to dc. Although it deviates from dc's behaviour, - this will probably be remedied in the future. -- John Beppu - - - -Erik Andersen, June 21, 2000 - - -0.44 - Previously, an erronous announcement of BusyBox 0.44 was made, so to - avoid possible confusion, we are skipping straight to 0.45, and calling - it good. - - -Erik Andersen - - -0.43 - * Major update to the provided documentation. - * Busybox now includes a shell! It currently costs 7.5 k (plus an - additional 2.5 k if you compile in command line editing). Handles - job control, has the usual set of builtins, and does everything - except for handling programming statements (if, while, etc...) - * Busybox can now work perfectly when /proc is disabled, thereby - saving a bunch of memory (kernel /proc support is not thin). This - is done by making use of some nice kernel patches I wrote up to - support the features that busybox requires and that /proc usually - provides. To enable this, turn on BB_FEATURE_USE_DEVPS_PATCH and - patch your kernel with the devps patch in the kernel-patches/ - directory. - * Wrote basename, dirname, killall, and uptime. - * tar has been completely rewritten by me. Both tar creation and - extraction are now well behaved. Costs 7.6k with all optional - tar features enabled, and 5k for just tar extraction support. - * Added freeramdisk, which will free up all memory associated - with a ram disk. Contributed by Emanuele Caratti - and then adjusted a bit by me. - * Added tr from John Lombardo - * Added echo and test (from me). - * Added usleep contributed by Nicolas Pitre - * BusyBox's bss size has been majorly reduced (was 384668, is now 28740). - * Several fixes from Pavel Roskin : - - When `tail' fails to open a file it now exits. - - When `syslogd' is given the `-n' option it should still use - fork() for running klogd. - * nslookup types are now changed to u_int32_t (instead of uint32_t) - changed per a patch from Pascal Bellard - * Fixed "du" so it gives the same answers as GNU "du" (busybox du used - to count hard-linked files more then once). Many thanks to - Friedrich Vedder for the fix. - * Removed /proc dependancies for init and free (while maintaining - exactly the same functionality). /proc takes up 90k of kernel - space, so it is nice to avoid using it at all costs. - * init no longer tries to mount /proc (unless there is less the 1 meg - free). Use of /proc (or not) is policy that should be set up in - /etc/fstab (or in hardcoded scripts), not in init. - * Fixed rebooting when init runs as an initrd. - * Fixes and updates from Karl M. Hegbloom - - update.c rewritten to look more like update-2.11 - - moveed the inode hash out of du.c and into utility.c to make - it a common resource that can be used by other apps. - - cp_mv.c now checks inodes to see if a source and dest are - the same, and prints an error (instead of endlessly looping). - - mv now attempts to do a rename, and will fall back to doing - a copy only if the rename fails. - - Syslogd now supports multiple concurrent connections - * Several fixes from Pavel Roskin : - - Fixes to sort. Removed "-g", fixed and added "-r" - - Fixes to the makefile for handling "strip" - * An initial telnet implementation was added by - Randolph Chung . - * Fixed a bug where "sed 's/foo/bar/g'" (i.e. a script w/o a "-e") - * ps now supports BB_FEATURE_AUTOWIDTH, and can adjust its width - to match the terminal (defaults to width=79 when this is off). - * ps now accepts (and ignores) all options except for "--help" (which - as would be expected displays help). - * Fixed mount'ing loop devices when the filesystem type was not - specified. It used to revert to non-loop after the first try. - * all mallocs now use xmalloc (and so are OOM error safe), and - the common error handling saves a few bytes. Thanks to - Bob Tinsley for the patch. - * Fix "+" parsing bug in date, from "Merle F. McClelland" . - * Fix symlink following bug in chmod -R and friends. - * Now allows SYSV style 'chown foo:bar' in addition to 'chown foo.bar' - * Fixed a bug in the busybox globbing routine such that 'find /dir -name [i]' - no longer segfaults. - - - -Erik Andersen - - -0.42 - - * Fairly massive restructuring of umount.c to deal with remounting - busy devices read-only. Adds a -r option to control that; it is - optionally compiled in with BB_FEATURE_REMOUNT - * Added a bunch of functions to mtab.c to interact with the - {get,set,end}mntent interface; as it turns out, those functions do - not appear to be re-entrant, and that causes a lot of problems with - the way umount was originally written. - * Makes init send TERM and KILL (instead of HUP and KILL) on reboot - to be more consistent with sysvinit - * Changes to init.c to use the new -r option to umount. Also increased - the sleep time between the time the TERM and KILL signals are sent - - - Randolph Chung - - - * cp.c, mv.c: removed, replaced by cp_mv.c which has been - extensively rewritten from the original cp.c. - * Fixed cp and mv so if the source and destination are a the - same directory it will print an error and continue. - * Also added a warning message to the `mv' usage string saying that - this is not GNU mv, and it will break hard links. cp also breaks - hard links. - * ln.c: implemented `-n' switch, no-deref symlinks. - * include: and use PATH_MAX everywhere. busybox: File - * name buffer overrun guards to prevent future crashes. - - Always check exit status. - - Purge all use of `creat()', replace with `open()'. - * utility.c - - recursiveAction was overriding the value of followLinks thus - ignoring it. - - isDirectory now takes a followLinks boolean, updated all callers - - copyFile had the followLinks logic reversed. - * messages.c: New file. Put common error message strings all in - one place in an attempt to shrink the binary a little. - - -Karl M. Hegbloom - - - * changed fsck_minix.c to reduce its .bss size significantly - -beppu -piptigger - * Made tar creation support in busybox tar optional. You no longer - * _have_ to put a "-" in front of tar options. Tar could inadvertently - * change permissions and ownership on - certain directories pointed to by symlinks. - * Made grep and grep -h do the right thing wrt printing - the file name (it failed to print files names in many cases). - * Fix a namespace aliasing problem wereby if du was built in, the - symlink for both du and dutmp would be installed, or then rm was - built in, the symlinks for both rm and rmmod would be installed. - * Added a closelog() to init.c after loging -- fix thanks to - Taketoshi Sano - * Rewrote and simplified logger. Added the "-t" option, and made it - behave itself a bit better. - * Optional support contributed by Ben Collins - for the kernel init chroot patch by Werner Almesberger, which - allows init to chroot to a new device, and umount the old one. - * Fixed bug that wouldn't let one chown a symlink -- it would - always dereference before. -beppu - * Fixed a bug where init could have reference already freed memory. - Found and fixed by Taketoshi Sano - * Several contributions from Friedrich Vedder - * Added (and documented) "-n" option for head - * Cleanup for a number of usage messages -- also - contributed Friedrich Vedder - * Cosmetic fix to busybox.c (Don't print a comma at the - end of line if there are no more application names). - * Fixed a stupid bug in "head" option handling ("head -n" - would segfault). - * Moved commonly used functions "xmalloc()" and "exit()" - to utility.c (with proper #ifdef's). - * Created a tiny tail implementation, removing -c, -q, -v, and making - tail -f work only with a single file. This reduced tail from 6k to - 2.4k. The bigger/more featured tail can still be had by disabling - BB_FEATURE_SIMPLE_TAIL in busybox.defs.h - * Ping now falls back to doing the right thing if /etc/protocols - turns up missing. - * Fixed mount and umount. Previously they could leak loop device - allocations, causing the system to quickly run out. Fix for umount - by Ben Collins , and mount was fixed by me. - * ls formatting on eight charactor user names fixed by - Randolph Chung . - * cp could, when copying symlinks, change permissions of the - files pointed to by the symlinks. - * Several fixes from Pavel Roskin : - - `chown' with 1 argument displayed the error incorrectly - - `fdflush', `length' and `printf' crashed if run without arguments - - `fdflush' tried to flush itself using *argv - - added "skip" and "seek" to dd. - - ls no longer messus up output when combining files and - directories on the command line - * swapoff -a was not working. Now it is. - * init did not cleanly unmount filesystems on reboot. Now it does. - * "sed -ne s/foo/bar/" worked but "sed -n -e s/foo/bar/" didn't. - Now both work. - * Some architectures (PowerPc) assume chars are unsigned, so they could - not distinguish between EOF and '\0xFF' in sed. Sed now uses ints. - * Began converting error handling to use some common routines - in utility.c - * syslogd now has better message handling and ignores SIGHUP. - * install.sh had a bug preventing installation to the specified - target directory. Fix from Gilbert Coville - * You can now spefify alternative strip commands -- change - also from Gilbert Coville. - - - -Erik Andersen - -0.41 - * New Apps: wc, hostid, logname, tty, whoami, yes -- all contributed - by Edward Betts - * Fixed a bug in both cp and mv preventing 'cp foo/README bar' - type commands (file in a directory to another directory) from - working. - * Fixed a logger bug that caused garbage to be written to the syslog - (unless you used busybox syslog, which hid the bug). Thanks to - Alex Holden for the fix. - * /bin/true and /bin/false were echoing a blank line when run. - Now fixed. - * mkdir -p would print an error when asked to mkdir an existing dir - with no interveining subdirectories. - * Fixed "syslogd -O" so that it works. Added -o loop option for mount, - * and support in umount for loop - devices. Support is toggled by MOUNT_LOOP feature -- Ben Collins - - * Several fixes from Marco Pantaleoni compile in - * fullWrite() not only if BB_TAR is defined, but also - if BB_CP or BB_MV are (fullWrite() is referenced by copyFile()) - * add some compiler optimizations to further reduce executable size - (as a side note, on my machines the largest code is generated - by gcc 2.95.2 with -Os ! The smallest by plain gcc 2.7.2.3 with - -O2 -m386 ...) - * Compile now won't fail if busybox.def.h defines - BB_FEATURE_LINUXRC but not BB_INIT. (init_main used to be - referenced, but not compiled) - * Fixed a bug in setting TERM for serial console support. TERM now - defaults to "ansi" for serial consoles. - * Fixed a bug in handling the CONSOLE env. variable for serial - * consoles. - - -Erik Andersen, Jan 15, 2000 - -0.40 - * New Apps: sort, uniq. -beppu New Apps: lsmod, rmmod -erik New Apps: - * fbset contributed by Randolph Chung . New App:: - * loadacm contributed by Peter Novodvorsky - for loading application character maps for Unicode fonts. - * Major init re-work. init now supports inittab (slightly different - but similar to sysvinit), allowing me to get all the policy out of - init and into the conf file. It works just fine without inittab - being present, but if you dont like the default behavior you can - now do something about it. Init is much cleaner as a result. - * Fixed an bug in syslogd causing it to stop after 20 minutes. -erik - * Fixed an embarrasing segfault in head -beppu Fixed the embarrasing - * failure of 'logger -p'. -erik Added the -s option to du -beppu - * Re-worked the source tree a bit so it will compile under glibc 2.0.7 - with the 2.0.x Linux kernel. - * Added 'grep -q' thanks to a patch from "Konstantin Boldyshev" - . - * Grep -i previously failed on UPPER CASE patterns due to a silly - regexp implementation bug that is now fixed. - * Fixed a bug where tar would set, and then clear SGID and SUID bits. - * Fixed a bug where tar would not set the user and group on device - special files. - * Fixed a bug where tar would not restore the time to files. Fixed a - * major security problem with tar -- it changed ownership - of any file pointed to by a symlink to 777 (like say libc....) - Ouch!!! - * cp and mv were very broken when moving directories. I have rewritten - them so they should now work as expected. - * sed now supports addresses (numeric or regexp, with negation) and - has an append command, thanks to Marco Pantaleoni - * Fixed dmesg. It wasn't parsing its options (-n or -s) properly. - * Some cosmetic fixes to ls output formatting to make it behave more - like GNU ls. - * Fixed a stupid segfault in kill. Several fixes from Friedrich Vedder - * : - - Added gunzip -t, removed gunzip.c dead code, - - fixed several typos - - Glibc 2.0.7 and libc5 compile fixes - * Fixed a bug where 'mknod --help' would segfault. - - - -Erik Andersen, Jan 07, 2000 - -0.39 - * New Apps: ping, hostname, and mkfifo contributed by Randolph Chung - . 3 items off the TODO list! - * I wrote free (just calls "cat /proc/meminfo"). Added tail, based on - * tail from GNU textutils-1.19, but adjusted - to suit my evil purposes. Costs 6k. I'll make it smaller - sometime. - * on reboot, init called 'umount -a -n', which caused errors - when BB_MTAB was not enabled. Changed to 'umount -a', which does - the right thing. - * init will now try to run /sbin/getty if it is present (for easy - integration with the about-to-be-released tinylogin.) - * kill now behaves itself properly, added 'kill -l' to list signals 'ls - * -l' was failing on long directories, since my_getid was leaking - one file descriptor per file. Oops. - * Fixed rebooting from init. I'd accidently left some debugging code - * in - which blocked reboots. - * Fixed reboot, halt (and added poweroff) such that they handle it when - init is not at PID 1 (like when running in an initrd). - * Added a prelinary du implementation. Some parameter parsing - stuff still needs to be added. -beppu (John Beppu - ) - * Implemented tee. -beppu Implemented head. -beppu - - -Erik Andersen, Dec 10, 1999 - -0.38 - * Fixed a segfault in 'umount -a' when a badly formed /etc/fstab - file existed. - * df will not exit on error, but will stat all mounted filesystems. - * Fixed tar so uid/gid/permissions on extracted tarballs will be - correct. - * Fixed find -name so it properly uses shell wildcard patterns - (i.e. `*', `?', and `[]') instead of regular expressions, which - was causing some confusing and unexpected behavior. - * Added klogd to syslogd, so now the log will contain both system and - kernel messages. - * syslogd now creates the /dev/log socket to make sure it is there, and - is actually a socket with the right permissions. - * I've taken a first step to making busybox not need the /proc - filesystem. Most apps don't need it. Those that _require_ it, - will complain if you enable them when you disable - BB_FEATURE_USE_PROCFS. - - -Erik Andersen, Dec 5, 1999 - -0.37 - * Wrote a micro syslogd, and a logger util (to log things to the syslog - from the command line or scripts) With both compiled in, costs 4k. - * Fixed 'make install' so symlinks are installed in their proper - * locations. Changed the build system slightly so that features can - * now be enabled - or disabled from the busybox.defs.h header file, without trying to - compile in a source file named after that featue (unless that file - exists). - * Several options are now moved into busybox.defs.h Now 'rm -R' and 'rm - * -r' both work. dd now properly handles input beyond 1 block from - * stdin. Fixed a bug where tar unpacked everything a directories. - * Moved some code - from createPath into mkdir where it belonged, thereby making tar - work properly. - * Fixed an off-by-one bug in cat. Given a list of file it wouldn't cat - * out the - last file in the list. - * Fixed 'ls -ln' so numeric group/uid are presented properly, and fixed - * 'ls -l' - so when uid/gid is not in /etc/{passwd,group} the numeric group/uid - are presented properly. - * Also added a TODO. - - - -Erik Andersen, Nov 25, 1999 - -0.36 - * fixed dd so it properly defaults to stdin and stdout when no - if= and of= are set (fix thanks to Eric Delaunay). - * Don't try to close the file descriptor of a pipein tar. (fix also - * from - Eric Delaunay). - * Made createPath be quiet (again thanks to Eric Delaunay). If - * BB_CONSOLE_CMD_IF_RC_SCRIPT_EXITS is defined, then whatever - command you define it as will be run if the init script exits. - * Updated install.sh to make it more robust (thanks to Adam Di Carlo) - * NFS support added to mount by Eric Delaunay. It costs 10k when - * compiled - in, but that is still a big win for those that use NFS. - * Made 'rm -f' be silent for non-existant files (thanks to Eric - * Delaunay). changed zcat.c to gunzip.c. It now obeys the principle - * of least surprise - and acts as god intended gunzip and zcat to act. They answer - --help and obey the '-c' flag. - * Fixed a bug in mv which caused it to not move files when the - * destination - was a directory. - * Fixed a decimal-instead-of-octal bug causing mkdir to make - * directories - with very wrong permissions. - * chmod would overwrite file permissions instead of modifying them. - Now it properly modifies permissions. - * Init now sends warnings destined for the console to /dev/console to - * ensure - they show up on whatever the active console it. Otherwise - important messages (for example that the system is rebooting) were - not seen when switched to a different VT. - - -Erik Andersen, Nov 17, 1999 - -0.35 - * gzip now obeys the principle of least surprise and acts like god - * intended - (i.e. it accepts a file name, answers --help, and obeys the '-c' - flag and only then outputs to stdout). - * Fixed more.c to compile autowidth on sparc and set initial winsize - to 0,0 in case the TIOCGWINSZ ioctl fails. Fix thanks to Eric - Delaunay. - * Fixed tar so it now works as expected (it had TRUE/FALSE backwards) - * tar now accepts --help chmod, chown, and chgrp usage now works - * General usage (i.e. --help) cleanups for most apps umount now parses - * options correctly tar can now unpack tarballs containing device - * special files, - sockets, and fifos (though it can't pack them up) thanks to Matt - Porter. Creating archives containing these is still left to the - interested student. - * fixed up the license in more.c to properly point to Bruce Perens. - - -Erik Andersen, Nov 11, 1999 - -0.34 - * ls -l now displays link names outside the current directory, - Patch thanks to Eric Delaunay - * init now properly handles sparc serial consoles and does a - better job of finding the real console device rather than using - /dev/console which doesn't support job control. Patch also thanks - to Eric Delaunay. - * more started to read from stdin after the last file was finished, and - options were not parsed correctly (fix thanks to Eric Delaunay). - * more will now use the terminal size if BB_FEATURE_AUTOWIDTH is on. - * rm wouldn't remove a symlink unless the symlink was valid. This was - a side effect of the busybox 0.32 recursiveAction() fix. Things - should now work correctly. - * grep wouldn't grep stdin. Now it does. sed wouldn't sed stdin. Now - * it does. sed was appending a \n to the end of lines with - * replacements. - Now it doesn't do that. - * ls -l now bypasses libc6 nss when displaying user/group names. - Now uses my_getpwuid and my_getgrgid. - - -Erik Andersen, Nov 8, 1999 - -0.33 - * Fixed a bug where init could hang instead of rebooting. - * Removed some debugging noise from init.c - * Fixed ln so it works now (it was very broken). - * Fixed df so it won't segfault when there is no /etc/fstab, - * If BB_MTAB is not defined, df and mount will whine if /etc/fstab - is not installed (since they cannot fixup "/dev/root" to - state the real root device name) - * merged some redundant code from mtab.c/df.c into utility.c - - -Erik Andersen, Nov 5, 1999 - -0.32 - * More changes -- many thanks to Lineo for paying me to work on - busybox. If you have any problems please let me know ASAP at - andersen@lineo.com or andersee@debian.org - * usage() now prints the BusyBox version. This will help folks - realize that they are not in Kansas anymore. - * Fixed mkdir -m option so that it works. kill segfaulted w/o any - * arguments. Now it doesn't do that. kill wasn't properly accepting - * signal names. It does now. Added new apps chvt and deallocvt (I - * should probably add open) Major rewrite of init.c. Code is now - * readable by mere mortals IMHO. Wrote sed -- weighs only 1.8k (5.8k - * with full regular expressions!). Fixed a stupid seg-fault in sync - * Fixed mount -- mount -a failed to parse and apply mount options Fixed - * umount -n (patch thanks to Matthew Grant ) - * umount -a no longer umounts /proc Added BB_MTAB, allowing (at the - * cost of ~1.5k and the need for a rw /etc) - folks to use a real /etc/mtab file instead of a symlink to - /proc/mounts. mount, and umount will add/remove entries and df - will now use /etc/mtab if BB_MTAB is defined. - * Fixed a nice bug in recursiveAction() which caused it to infinitely - hunt through /proc/../fd/* creating new file descriptors if it - followed the /dev/fd link over to /proc. recursiveAction() now - lstat's the file when followLinks==FALSE so it won't follow links - as the name suggests. Fix thanks to Matt Porter - . - - - -Erik Andersen, Nov 4, 1999 - -0.31 - * I added a changelog for version 0.30. adjusted find internals to - * make it smaller, and removed - some redundancy. - * Fixed a segfault in ps when /etc/passwd or /etc/group - are absent. Now will warn you and carry on. - * Added in optional _real_ regular expression support (to be - the basis for a future sed utility). When compiled in it adds - 3.9k, but makes grep much more capable. - * Checked out using nftw(3) for recursive stuff, but unfortunatly - it wasn't supported before GNU libc 2.1, and some folks use glibc - 2.0.7 since it is much smaller than that latest and greatest. - - -Erik Andersen, Oct 21, 1999 - -0.30 - Major changes -- lots of stuff rewritten. Many thanks to Lineo for - paying me to make these updates. If you have any problems with busybox, - or notice any bugs -- please let me know so I can fix it. These - changes include: - - Core Changes: - * busybox can now invoke apps in two ways: via symlinks to the - busybox binary, and as 'busybox [function] [arguments]...' - * When invoked as busybox, the list of currently compiled in - functions is printed out (no this is not bloat -- the list has - to be there anyway to map invocation name to function). - * busybox no longer parses command lines for apps or displays their - usage info. Each app gets to handle (or not handle) this for - itself. - * Eliminated monadic, dyadic, descend, block_device, and - postprocess. It was cumbersome to have so many programs - cobbled together in this way. Without them, the app is much - more granular. - * All shared code now lives in utility.c, and is properly - ifdef'ed to be only included for those apps requiring it. - * Eliminated struct FileInfo (the basis of monadic, dyadic, etc) - so now each app has the function prototype of (da-dum): extern - int foo_main(int argc, char** argv); which speeds integration - of new apps. - * Adjusted the Makefile to make it easier to - {en|dis}able debugging. - * Changed default compiler optimization to -Os - (optimize for smaller binaries). - - App Changes: - * To cope with the new app function prototype and the removal of - monadic, dyadic, etc, the following apps were re-written: - * cat - Works same as always. chgrp, chmod, chown - - * rewrite. Combined into a single - source file. Absorbed patches from Enrique Zanardi - that removes the dependency on - libc6 libnss* libraries. - * cp - Can now do 'cp -a' can can copy devices, - pipes, symlinks, as well as recursive or non-recursive - dir copies. - * fdflush - adjusted to remove dependancy on struct - * FileInfo. find - Now includes some basic regexp matching - which will be the basic of a future mini-sed. - * ln - Same functionality. mkdir - Added -p flag to - * feature set. mv - rewrite. rm - Added -f flag to - * feature set. rmdir - Same functionality. swapon, - * swapoff - Combined into a single binary. No longer - uses /etc/swaps. swap{on|off} -a uses /etc/fstab - instead. - * touch - Same functionality. date - adjusted with a patch - * from Matthew Grant - to accomodate glibc timezone support. I then ripped out GNU - getopt. - * mkswap -- new version merged from util-linux. Can now make - >128Meg swaps. - * Replaced the old and star, unstar, and tarcat with the tar - implementation from sash. Now tar behaves as god intended it - to (i.e. tar -xvf and tar -cf work). - * dd -- rewritten. Can with with files, stdin, stdout. Added the - * following new apps: loadfont -- added from debian boot floppies - * chroot -- added based on a patch from Paolo Molaro - * grep -- I just wrote it. Only matches - * simple strings ps -- I just wrote it. Has _no_ options at all, - * but works. fsck_minix, mkfs_minix -- added from util-linux, but - * I ripped out - internationalization and such to make them smaller. - * sfdisk -- Added from util-linux (minus - * internationalization and such). Probably some other - * changes that I forgot to document... - - -Erik Andersen, Oct 20, 1999 - -0.29 - This version was a messy pre-alpha. stay away or it will bite you. - -Erik Andersen, Sep 24, 1999 - -0.28 - mini-netcat (mnc) rewritten. - -0.27 - Mount now supports -a, and -t auto. - Mount now updates mtab correctly for 'ro'. - More checks screen rows size, outputs bytes percentage. - Printf added as module. -0.26 - Touch now creates files. -c option for no create. - diff --git a/busybox/Config.h b/busybox/Config.h deleted file mode 100644 index e832eae7a..000000000 --- a/busybox/Config.h +++ /dev/null @@ -1,483 +0,0 @@ -/* vi: set sw=4 ts=4: */ -// This file defines the feature set to be compiled into busybox. -// When you turn things off here, they won't be compiled in at all. -// -//// This file is parsed by sed. You MUST use single line comments. -// i.e., //#define BB_BLAH -// -// -// BusyBox Applications -//#define BB_ADJTIMEX -//#define BB_AR -//#define BB_ASH -#define BB_BASENAME -#define BB_CAT -#define BB_CHGRP -#define BB_CHMOD -#define BB_CHOWN -#define BB_CHROOT -#define BB_CHVT -#define BB_CLEAR -//#define BB_CMP -#define BB_CP -//#define BB_CPIO -#define BB_CUT -#define BB_DATE -//#define BB_DC -#define BB_DD -//#define BB_DEALLOCVT -#define BB_DF -#define BB_DIRNAME -#define BB_DMESG -//#define BB_DOS2UNIX -//#define BB_DPKG -//#define BB_DPKG_DEB -//#define BB_DUTMP -#define BB_DU -//#define BB_DUMPKMAP -#define BB_ECHO -#define BB_ENV -//#define BB_EXPR -//#define BB_FBSET -//#define BB_FDFLUSH -#define BB_FIND -#define BB_FREE -//#define BB_FREERAMDISK -//#define BB_FSCK_MINIX -//#define BB_GETOPT -#define BB_GREP -#define BB_GUNZIP -#define BB_GZIP -#define BB_HALT -#define BB_HEAD -//#define BB_HOSTID -//#define BB_HOSTNAME -//#define BB_HUSH -#define BB_ID -//#define BB_IFCONFIG -#define BB_INIT -//#define BB_INSMOD -#define BB_KILL -#define BB_KILLALL -#define BB_KLOGD -//#define BB_LASH -//#define BB_LENGTH -#define BB_LN -//#define BB_LOADACM -//#define BB_LOADFONT -//#define BB_LOADKMAP -#define BB_LOGGER -//#define BB_LOGNAME -#define BB_LS -#define BB_LSMOD -//#define BB_MAKEDEVS -//#define BB_MD5SUM -#define BB_MKDIR -//#define BB_MKFIFO -//#define BB_MKFS_MINIX -#define BB_MKNOD -#define BB_MKSWAP -//#define BB_MKTEMP -#define BB_MODPROBE -#define BB_MORE -#define BB_MOUNT -#define BB_MSH -//#define BB_MT -#define BB_MV -//#define BB_NC -//#define BB_NSLOOKUP -#define BB_PIDOF -//#define BB_PING -//#define BB_PIVOT_ROOT -#define BB_POWEROFF -//#define BB_PRINTF -#define BB_PS -#define BB_PWD -//#define BB_RDATE -//#define BB_READLINK -#define BB_REBOOT -//#define BB_RENICE -#define BB_RESET -#define BB_RM -#define BB_RMDIR -//#define BB_RMMOD -//#define BB_ROUTE -//#define BB_RPM2CPIO -#define BB_SED -//#define BB_SETKEYCODES -#define BB_SLEEP -#define BB_SORT -//#define BB_STTY -#define BB_SWAPONOFF -#define BB_SYNC -#define BB_SYSLOGD -#define BB_TAIL -#define BB_TAR -//#define BB_TEE -//#define BB_TEST -//#define BB_TELNET -//#define BB_TFTP -#define BB_TOUCH -//#define BB_TR -//#define BB_TRACEROUTE -#define BB_TRUE_FALSE -#define BB_TTY -//#define BB_UNIX2DOS -//#define BB_UUENCODE -//#define BB_UUDECODE -#define BB_UMOUNT -#define BB_UNIQ -#define BB_UNAME -//#define BB_UPDATE -#define BB_UPTIME -//#define BB_USLEEP -//#define BB_VI -//#define BB_WATCHDOG -#define BB_WC -//#define BB_WGET -#define BB_WHICH -#define BB_WHOAMI -#define BB_XARGS -#define BB_YES -// End of Applications List -// -// -// -// --------------------------------------------------------- -// This is where feature definitions go. Generally speaking, -// turning this stuff off makes things a bit smaller (and less -// pretty/useful). -// -// -// If you enabled one or more of the shells, you may select which one -// should be run when sh is invoked: -//#define BB_FEATURE_SH_IS_ASH -//#define BB_FEATURE_SH_IS_HUSH -//#define BB_FEATURE_SH_IS_LASH -#define BB_FEATURE_SH_IS_MSH -// -// BusyBox will, by default, malloc space for its buffers. This costs code -// size for the call to xmalloc. You can use the following feature to have -// them put on the stack. For some very small machines with limited stack -// space, this can be deadly. For most folks, this works just fine... -//#define BB_FEATURE_BUFFERS_GO_ON_STACK -// The third alternative for buffer allocation is to use BSS. This works -// beautifully for computers with a real MMU (and OS support), but wastes -// runtime RAM for uCLinux. This behavior was the only one available for -// BusyBox versions 0.48 and earlier. -//#define BB_FEATURE_BUFFERS_GO_IN_BSS -// -// Turn this on to use Erik's very cool devps, and devmtab kernel drivers, -// thereby eliminating the need for the /proc filesystem and thereby saving -// lots and lots memory for more important things. NOTE: If you enable this -// feature, you _must_ have patched the kernel to include the devps patch that -// is included in the busybox/kernel-patches directory. You will also need to -// create some device special files in /dev on your embedded system: -// mknod /dev/mtab c 10 22 -// mknod /dev/ps c 10 21 -// I emailed Linus and this patch will not be going into the stock kernel. -//#define BB_FEATURE_USE_DEVPS_PATCH -// -// show verbose usage messages -//#define BB_FEATURE_VERBOSE_USAGE -// -// Use termios to manipulate the screen ('more' is prettier with this on) -//#define BB_FEATURE_USE_TERMIOS -// -// calculate terminal & column widths (for more and ls) -#define BB_FEATURE_AUTOWIDTH -// -// show username/groupnames for ls -#define BB_FEATURE_LS_USERNAME -// -// show file timestamps in ls -#define BB_FEATURE_LS_TIMESTAMPS -// -// enable ls -p and -F -#define BB_FEATURE_LS_FILETYPES -// -// sort the file names -#define BB_FEATURE_LS_SORTFILES -// -// enable ls -R -#define BB_FEATURE_LS_RECURSIVE -// -// enable ls -L -#define BB_FEATURE_LS_FOLLOWLINKS -// -// Disable for a smaller (but less functional) ping -#define BB_FEATURE_FANCY_PING -// -// Make init use a simplified /etc/inittab file (recommended). -#define BB_FEATURE_USE_INITTAB -// -//Enable init being called as /linuxrc -#define BB_FEATURE_LINUXRC -// -//Have init enable core dumping for child processes (for debugging only) -//#define BB_FEATURE_INIT_COREDUMPS -// -//Make sure nothing is printed to the console on boot -//#define BB_FEATURE_EXTRA_QUIET -// -// enable syslogd -R remotehost -#define BB_FEATURE_REMOTE_LOG -// -// enable syslogd -C -//#define BB_FEATURE_IPC_SYSLOG -// -//Disable for a simple tail implementation (2.34k vs 3k for the full one). -//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. -#define BB_FEATURE_FANCY_TAIL -// -// Enable support for loop devices in mount -#define BB_FEATURE_MOUNT_LOOP -// -// Enable support for a real /etc/mtab file instead of /proc/mounts -//#define BB_FEATURE_MTAB_SUPPORT -// -// Enable support for mounting remote NFS volumes. -// You may need to mount with "-o nolock" if you are -// not running a local portmapper daemon... -// -// If you are using uClibc, be sure that you've already compiled -// uClibc with INCLUDE_RPC=true (contained in the Config file) -//#define BB_FEATURE_NFSMOUNT -// -// Enable support forced filesystem unmounting -// (i.e., in case of an unreachable NFS system). -#define BB_FEATURE_MOUNT_FORCE -// -// Enable support for creation of tar files. -#define BB_FEATURE_TAR_CREATE -// -// Enable support for "--exclude" and "-X" for excluding files -#define BB_FEATURE_TAR_EXCLUDE -// -// Enable support for tar -z option (currently only works for inflating) -#define BB_FEATURE_TAR_GZIP -// -// Enable reverse sort -#define BB_FEATURE_SORT_REVERSE -// -// Enable uniqe sort -#define BB_FEATURE_SORT_UNIQUE -// -// Enable command line editing in the shell. -// Only relevant if a shell is enabled. On by default. -#define BB_FEATURE_COMMAND_EDITING -// -// Enable tab completion in the shell. This is now working quite nicely. -// This feature adds a bit over 4k. Only relevant if a shell is enabled. -#define BB_FEATURE_COMMAND_TAB_COMPLETION -// -// Attempts to match usernames in a ~-prefixed path -//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION -// -//Allow the shell to invoke all the compiled in BusyBox applets as if they -//were shell builtins. Nice for staticly linking an emergency rescue shell, -//among other things. Off by default. -// Only relevant if a shell is enabled. -//#define BB_FEATURE_SH_STANDALONE_SHELL -// -//When this is enabled, busybox shell applets can be called using full path -//names. This causes applets (i.e., most busybox commands) to override -//real commands on the filesystem. For example, if you run run /bin/cat, it -//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_ -//busybox. Some systems want this, others do not. Choose wisely. :-) This -//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled. -// Only relevant if a shell is enabled. Off by default. -//#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN -// -// Uncomment this option for a fancy shell prompt that includes the -// current username and hostname. On systems that don't have usernames -// or hostnames, this can look hideous. -// Only relevant if a shell is enabled. -//#define BB_FEATURE_SH_FANCY_PROMPT -// -//Turn on extra fbset options -//#define BB_FEATURE_FBSET_FANCY -// -//Turn on fbset readmode support -//#define BB_FEATURE_FBSET_READMODE -// -// Support insmod/lsmod/rmmod for post 2.1 kernels -//#define BB_FEATURE_NEW_MODULE_INTERFACE -// -// Support insmod/lsmod/rmmod for pre 2.1 kernels -//#define BB_FEATURE_OLD_MODULE_INTERFACE -// -// Support module version checking -//#define BB_FEATURE_INSMOD_VERSION_CHECKING -// -// Support for uClinux memory usage optimization, which will load the image -// directly into the kernel memory. This divides memory requrements by three. -// If you are not running uClinux (i.e., your CPU has an MMU) leave this -// disabled... -//#define BB_FEATURE_INSMOD_LOADINKMEM -// -// Support for Minix filesystem, version 2 -//#define BB_FEATURE_MINIX2 -// -// Enable ifconfig status reporting output -- this feature adds 7k. -//#define BB_FEATURE_IFCONFIG_STATUS -// -// Enable ifconfig slip-specific options "keepalive" and "outfill" -//#define BB_FEATURE_IFCONFIG_SLIP -// -// Enable ifconfig options "mem_start", "io_addr", and "irq". -//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ -// -// Enable ifconfig option "hw". Currently works for only with "ether". -//#define BB_FEATURE_IFCONFIG_HW -// -// Allows "broadcast +" to set broadcast automatically based on hostaddr -// and netmask, at a cost of about 100 bytes of code (i386). -//#define BB_FEATURE_IFCONFIG_BROADCAST_PLUS -// -// Enable busybox --install [-s] -// to create links (or symlinks) for all the commands that are -// compiled into the binary. (needs /proc filesystem) -//#define BB_FEATURE_INSTALLER -// -// Enable a nifty progress meter in wget (adds just under 2k) -#define BB_FEATURE_WGET_STATUSBAR -// -// Enable HTTP authentication in wget -#define BB_FEATURE_WGET_AUTHENTICATION -// -// Clean up all memory before exiting -- usually not needed -// as the OS can clean up... Don't enable this unless you -// have a really good reason for cleaning things up manually. -//#define BB_FEATURE_CLEAN_UP -// -// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G) -#define BB_FEATURE_HUMAN_READABLE -// -// Support for the find -type option. -#define BB_FEATURE_FIND_TYPE -// -// Support for the find -perm option. -#define BB_FEATURE_FIND_PERM -// -// Support for the find -mtine option. -#define BB_FEATURE_FIND_MTIME -// -// Support for the -A -B and -C context flags in grep -//#define BB_FEATURE_GREP_CONTEXT -// -// Support for the EGREP applet (alias to the grep applet) -//#define BB_FEATURE_GREP_EGREP_ALIAS -// -// Tell tftp what commands that should be supported. -#define BB_FEATURE_TFTP_PUT -#define BB_FEATURE_TFTP_GET -// -// features for vi -#define BB_FEATURE_VI_COLON // ":" colon commands, no "ex" mode -#define BB_FEATURE_VI_YANKMARK // Yank/Put commands and Mark cmds -#define BB_FEATURE_VI_SEARCH // search and replace cmds -#define BB_FEATURE_VI_USE_SIGNALS // catch signals -#define BB_FEATURE_VI_DOT_CMD // remember previous cmd and "." cmd -#define BB_FEATURE_VI_READONLY // vi -R and "view" mode -#define BB_FEATURE_VI_SETOPTS // set-able options, ai ic showmatch -#define BB_FEATURE_VI_SET // :set -#define BB_FEATURE_VI_WIN_RESIZE // handle window resize -// -// Enable a if you system have setuped locale -//#define BB_LOCALE_SUPPORT -// -// Support for TELNET to pass TERM type to remote host. Adds 384 bytes. -#define BB_FEATURE_TELNET_TTYPE -// -// Support for devfs. -//#define BB_FEATURE_DEVFS -// -// End of Features List -// -// -// -// -// -// -//--------------------------------------------------- -// Nothing beyond this point should ever be touched by -// mere mortals so leave this stuff alone. -// -#include -#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__ - #undef BB_RPM2CPIO /* Uses gz_open(), which uses fork() */ - #undef BB_DPKG_DEB /* Uses gz_open(), which uses fork() */ - #undef BB_ASH /* Uses fork() */ - #undef BB_HUSH /* Uses fork() */ - #undef BB_LASH /* Uses fork() */ - #undef BB_INIT /* Uses fork() */ - #undef BB_FEATURE_TAR_GZIP /* Uses fork() */ - #undef BB_SYSLOGD /* Uses daemon() */ - #undef BB_KLOGD /* Uses daemon() */ - #undef BB_UPDATE /* Uses daemon() */ -#endif -#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH - #if defined BB_FEATURE_COMMAND_EDITING - #define BB_CMDEDIT - #else - #undef BB_FEATURE_COMMAND_EDITING - #undef BB_FEATURE_COMMAND_TAB_COMPLETION - #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION - #undef BB_FEATURE_SH_FANCY_PROMPT - #endif -#else - #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN - #undef BB_FEATURE_SH_STANDALONE_SHELL - #undef BB_FEATURE_SH_FANCY_PROMPT -#endif -// -#if (defined BB_ASH || defined BB_HUSH || defined BB_MSH) && ! defined BB_TEST - #define BB_TEST -#endif -// -#ifdef BB_KILLALL - #ifndef BB_KILL - #define BB_KILL - #endif -#endif -// -#ifndef BB_INIT - #undef BB_FEATURE_LINUXRC -#endif -// -#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT - #define BB_NFSMOUNT -#endif -// -#if defined BB_FEATURE_AUTOWIDTH - #ifndef BB_FEATURE_USE_TERMIOS - #define BB_FEATURE_USE_TERMIOS - #endif -#endif -// -#if defined BB_INSMOD || defined BB_LSMOD - #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE - #define BB_FEATURE_NEW_MODULE_INTERFACE - #endif -#endif -// -#ifdef BB_UNIX2DOS - #define BB_DOS2UNIX -#endif -// -#ifdef BB_SYSLOGD - #if defined BB_FEATURE_IPC_SYSLOG - #define BB_LOGREAD - #endif -#endif -// -#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH -# define shell_main ash_main -#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH -# define shell_main hush_main -#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH -# define shell_main lash_main -#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH -# define shell_main msh_main -#endif diff --git a/busybox/INSTALL b/busybox/INSTALL deleted file mode 100644 index e17bd80d3..000000000 --- a/busybox/INSTALL +++ /dev/null @@ -1,8 +0,0 @@ -1) Check Config.h and adjust if you need a different functionality than - defined by default. - -2) Check the Makefile - -3) make - -4) make install diff --git a/busybox/LICENSE b/busybox/LICENSE deleted file mode 100644 index 8e5a143d0..000000000 --- a/busybox/LICENSE +++ /dev/null @@ -1,378 +0,0 @@ -Original release code (unless otherwise noted) -Copyright 1995, 1996 Bruce Perens - -mkswap -Copyright 1991 Linus Torvalds - -tiny-ls(ls) -Copyright 1996 Brian Candler - -tarcat, loadkmap, various fixes, Debian maintenance -Copyright 1998 Enrique Zanardi - -more(v2), makedevs, dutmp, modularization, auto links file, -various fixes, Linux Router Project maintenance -Copyright 1998 Dave Cinege - -mini-gzip(gzip), mini-netcat(mnc) -Copyright 1998 Charles P. Wright - -Tons of new stuff as noted in header files -Copyright (C) 1999,2000,2001 by Lineo, inc. and written by -Erik Andersen , - - - -Please feed suggestions, bug reports, insults, and bribes back to: - Erik Andersen - - - - - -Busybox may be used and distributed under the GNU General Public License. - ---------------------------------------------------------------------------- - - - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. - diff --git a/busybox/Makefile b/busybox/Makefile deleted file mode 100644 index d231f69e7..000000000 --- a/busybox/Makefile +++ /dev/null @@ -1,443 +0,0 @@ -# Makefile for busybox -# -# Copyright (C) 1999,2000,2001 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 -# - -PROG := busybox -VERSION := 0.60.2.pre -BUILDTIME := $(shell TZ=UTC date -u "+%Y.%m.%d-%H:%M%z") -export VERSION - -# With a modern GNU make(1) (highly recommended, that's what all the -# developers use), all of the following configuration values can be -# overridden at the command line. For example: -# make CROSS=powerpc-linux- BB_SRC_DIR=$HOME/busybox PREFIX=/mnt/app - -# If you want to add some simple compiler switches (like -march=i686), -# especially from the command line, use this instead of CFLAGS directly. -# For optimization overrides, it's better still to set OPTIMIZATION. -CFLAGS_EXTRA = - -# If you want a static binary, turn this on. -DOSTATIC = false - -# Set the following to `true' to make a debuggable build. -# Leave this set to `false' for production use. -DODEBUG = false - -# Setting this to `true' will cause busybox to directly use the system's -# password and group functions. Assuming you use GNU libc, when this is -# `true', you will need to install the /etc/nsswitch.conf configuration file -# and the required libnss_* libraries. This generally makes your embedded -# system quite a bit larger... If you leave this off, busybox will directly use -# the /etc/password, /etc/group files (and your system will be smaller, and I -# will get fewer emails asking about how glibc NSS works). Enabling this adds -# just 1.4k to the binary size (which is a _lot_ less then glibc NSS costs). -# Note that if you want hostname resolution to work with glibc, you still need -# the libnss_* libraries. -USE_SYSTEM_PWD_GRP = true - -# This enables compiling with dmalloc ( http://dmalloc.com/ ) -# which is an excellent public domain mem leak and malloc problem -# detector. To enable dmalloc, before running busybox you will -# want to first set up your environment. -# eg: `export DMALLOC_OPTIONS=debug=0x14f47d83,inter=100,log=logfile` -# Do not enable this for production builds... -DODMALLOC = false - -# Electric-fence is another very useful malloc debugging library. -# Do not enable this for production builds... -DOEFENCE = false - -# If you want large file summit support, turn this on. -# This has no effect if you don't have a kernel with lfs -# support, and a system with libc-2.1.3 or later. -# Some of the programs that can benefit from lfs support -# are dd, gzip, mount, tar, and mkfs_minix. -# LFS allows you to use the above programs for files -# larger than 2GB! -DOLFS = false - -# If you have a "pristine" source directory, point BB_SRC_DIR to it. -# Experimental and incomplete; tell the mailing list -# if you do or don't like it so far. -BB_SRC_DIR = - -# If you are running a cross compiler, you may want to set this -# to something more interesting, like "powerpc-linux-". -CROSS = -CC = $(CROSS)gcc -AR = $(CROSS)ar -STRIPTOOL = $(CROSS)strip - -# To compile vs uClibc, just use the compiler wrapper built by uClibc... -# Everything should compile and work as expected these days... -#CC = ../uClibc/extra/gcc-uClibc/i386-uclibc-gcc - -# To compile vs some other alternative libc, you may need to use/adjust -# the following lines to meet your needs... -# -# If you are using Red Hat 6.x with the compatible RPMs (for developing under -# Red Hat 5.x and glibc 2.0) uncomment the following. Be sure to read about -# using the compatible RPMs (compat-*) at http://www.redhat.com ! -#LIBCDIR=/usr/i386-glibc20-linux -# -# The following is used for libc5 (if you install altgcc and libc5-altdev -# on a Debian system). -#LIBCDIR=/usr/i486-linuxlibc1 -# -# For other libraries, you are on your own... -#LDFLAGS+=-nostdlib -#LIBRARIES = $(LIBCDIR)/lib/libc.a -lgcc -#CROSS_CFLAGS+=-nostdinc -I$(LIBCDIR)/include -I$(GCCINCDIR) -#GCCINCDIR = $(shell gcc -print-search-dirs | sed -ne "s/install: \(.*\)/\1include/gp") - -# use '-Os' optimization if available, else use -O2 -OPTIMIZATION := $(shell if $(CC) -Os -S -o /dev/null -xc /dev/null >/dev/null 2>&1; \ - then echo "-Os"; else echo "-O2" ; fi) - -WARNINGS = -Wall -Wshadow - -ARFLAGS = -r - -# -#-------------------------------------------------------- -# If you're going to do a lot of builds with a non-vanilla configuration, -# it makes sense to adjust parameters above, so you can type "make" -# by itself, instead of following it by the same half-dozen overrides -# every time. The stuff below, on the other hand, is probably less -# prone to casual user adjustment. -# - -ifeq ($(strip $(DOLFS)),true) - # For large file summit support - CFLAGS+=-D_FILE_OFFSET_BITS=64 -endif -ifeq ($(strip $(DODMALLOC)),true) - # For testing mem leaks with dmalloc - CFLAGS+=-DDMALLOC - LIBRARIES = -ldmalloc - # Force debug=true, since this is useless when not debugging... - DODEBUG = true -else - ifeq ($(strip $(DOEFENCE)),true) - LIBRARIES = -lefence - # Force debug=true, since this is useless when not debugging... - DODEBUG = true - endif -endif -ifeq ($(strip $(DODEBUG)),true) - CFLAGS += $(WARNINGS) -g -D_GNU_SOURCE - LDFLAGS += -Wl,-warn-common - STRIP = -else - CFLAGS += $(WARNINGS) $(OPTIMIZATION) -fomit-frame-pointer -D_GNU_SOURCE - LDFLAGS += -s -Wl,-warn-common - STRIP = $(STRIPTOOL) --remove-section=.note --remove-section=.comment $(PROG) -endif -ifeq ($(strip $(DOSTATIC)),true) - LDFLAGS += --static - # - #use '-ffunction-sections -fdata-sections' and '--gc-sections' (if they - # work) to try and strip out any unused junk. Doesn't do much for me, - # but you may want to give it a shot... - # - #ifeq ($(shell $(CC) -ffunction-sections -fdata-sections -S \ - # -o /dev/null -xc /dev/null 2>/dev/null && $(LD) \ - # --gc-sections -v >/dev/null && echo 1),1) - # CFLAGS += -ffunction-sections -fdata-sections - # LDFLAGS += --gc-sections - #endif -endif - -ifndef $(PREFIX) - PREFIX = `pwd`/_install -endif - -# Additional complications due to support for pristine source dir. -# Include files in the build directory should take precedence over -# the copy in BB_SRC_DIR, both during the compilation phase and the -# shell script that finds the list of object files. -# Work in progress by . -# -ifneq ($(strip $(BB_SRC_DIR)),) - VPATH = $(BB_SRC_DIR) -endif -#ifneq ($(strip $(VPATH)),) -# CFLAGS += -I- -I. $(patsubst %,-I%,$(subst :, ,$(VPATH))) -#endif - -# We need to set APPLET_SOURCES to something like -# $(shell busybox.sh Config.h) -# but in a manner that works with VPATH and BB_SRC_DIR. -# Possible ways to approach this: -# -# 1. Explicitly search through .:$(VPATH) for busybox.sh and config.h, -# then $(shell $(BUSYBOX_SH) $(CONFIG_H) $(BB_SRC_DIR)) -# -# 2. Explicity search through .:$(VPATH) for slist.mk, -# then $(shell $(MAKE) -f $(SLIST_MK) VPATH=$(VPATH) BB_SRC_DIR=$(BB_SRC_DIR)) -# -# 3. Create slist.mk in this directory, with commands embedded in -# a $(shell ...) command, and $(MAKE) it immediately. -# -# 4. Use a real rule within this makefile to create a file that sets -# APPLET_SOURCE_LIST, then include that file. Has complications -# with the first trip through the makefile (before processing the -# include) trying to do too much, and a spurious warning the first -# time make is run. -# -# This is option 3: -# -#APPLET_SOURCES = $(shell \ -# echo -e 'all: busybox.sh Config.h\n\t@ $$(SHELL) $$^ $$(BB_SRC_DIR)' >slist.mk; \ -# make -f slist.mk VPATH=$(VPATH) BB_SRC_DIR=$(BB_SRC_DIR) \ -#) -# And option 4: --include applet_source_list - -OBJECTS = $(APPLET_SOURCES:.c=.o) busybox.o usage.o applets.o -CFLAGS += $(CROSS_CFLAGS) -CFLAGS += -DBB_VER='"$(VERSION)"' -CFLAGS += -DBB_BT='"$(BUILDTIME)"' -ifdef BB_INIT_SCRIPT - CFLAGS += -DINIT_SCRIPT='"$(BB_INIT_SCRIPT)"' -endif - -ifneq ($(strip $(USE_SYSTEM_PWD_GRP)),true) - PWD_GRP = pwd_grp - PWD_GRP_DIR = $(BB_SRC_DIR:=/)$(PWD_GRP) - PWD_LIB = libpwd.a - PWD_CSRC=__getpwent.c pwent.c getpwnam.c getpwuid.c putpwent.c getpw.c \ - fgetpwent.c __getgrent.c grent.c getgrnam.c getgrgid.c fgetgrent.c \ - initgroups.c setgroups.c - PWD_OBJS=$(patsubst %.c,$(PWD_GRP)/%.o, $(PWD_CSRC)) -ifneq ($(strip $(BB_SRC_DIR)),) - PWD_CFLAGS = -I- -I. -endif - PWD_CFLAGS += -I$(PWD_GRP_DIR) -else - CFLAGS += -DUSE_SYSTEM_PWD_GRP -endif - -LIBBB = libbb -LIBBB_LIB = libbb.a -LIBBB_CSRC= ask_confirmation.c chomp.c concat_path_file.c copy_file.c \ -copy_file_chunk.c libc5.c device_open.c error_msg.c \ -error_msg_and_die.c fgets_str.c find_mount_point.c find_pid_by_name.c \ -find_root_device.c full_read.c full_write.c get_console.c \ -get_last_path_component.c get_line_from_file.c gz_open.c human_readable.c \ -isdirectory.c kernel_version.c loop.c mode_string.c module_syscalls.c mtab.c \ -mtab_file.c my_getgrnam.c my_getgrgid.c my_getpwnam.c my_getpwnamegid.c \ -my_getpwuid.c parse_mode.c parse_number.c perror_msg.c perror_msg_and_die.c \ -print_file.c process_escape_sequence.c read_package_field.c recursive_action.c \ -safe_read.c safe_strncpy.c syscalls.c syslog_msg_with_name.c time_string.c \ -trim.c unzip.c vdprintf.c verror_msg.c vperror_msg.c wfopen.c xfuncs.c \ -xgetcwd.c xreadlink.c xregcomp.c interface.c remove_file.c last_char_is.c \ -copyfd.c vherror_msg.c herror_msg.c herror_msg_and_die.c xgethostbyname.c \ -dirname.c make_directory.c create_icmp_socket.c u_signal_names.c arith.c \ -simplify_path.c -LIBBB_OBJS=$(patsubst %.c,$(LIBBB)/%.o, $(LIBBB_CSRC)) -ifeq ($(strip $(BB_SRC_DIR)),) - LIBBB_CFLAGS += -I$(LIBBB) -else - LIBBB_CFLAGS = -I- -I. -I./$(LIBBB) -I$(BB_SRC_DIR)/$(LIBBB) -I$(BB_SRC_DIR) -endif - -LIBBB_MSRC=libbb/messages.c -LIBBB_MESSAGES= full_version name_too_long omitting_directory not_a_directory \ -memory_exhausted invalid_date invalid_option io_error dash_dash_help \ -write_error too_few_args name_longer_than_foo unknown can_not_create_raw_socket -LIBBB_MOBJ=$(patsubst %,$(LIBBB)/%.o, $(LIBBB_MESSAGES)) - -LIBBB_ARCSRC=libbb/unarchive.c -LIBBB_ARCOBJ= archive_offset seek_sub_file extract_archive unarchive \ -get_header_ar get_header_cpio get_header_tar deb_extract -LIBBB_AROBJS=$(patsubst %,$(LIBBB)/%.o, $(LIBBB_ARCOBJ)) - - -# Put user-supplied flags at the end, where they -# have a chance of winning. -CFLAGS += $(CFLAGS_EXTRA) - -.EXPORT_ALL_VARIABLES: - -all: applet_source_list busybox busybox.links doc - -applet_source_list: busybox.sh Config.h - (echo -n "APPLET_SOURCES := "; CC="$(CC)" BB_SRC_DIR="$(BB_SRC_DIR)" $(SHELL) $^) > $@ - -doc: olddoc - -# Old Docs... -olddoc: docs/busybox.pod docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html - -docs/busybox.pod : docs/busybox_header.pod usage.h docs/busybox_footer.pod - - ( cat docs/busybox_header.pod; \ - docs/autodocifier.pl usage.h; \ - cat docs/busybox_footer.pod ) > docs/busybox.pod - -docs/BusyBox.txt: docs/busybox.pod - @echo - @echo BusyBox Documentation - @echo - -mkdir -p docs - -pod2text $< > $@ - -docs/BusyBox.1: docs/busybox.pod - - mkdir -p docs - - pod2man --center=BusyBox --release="version $(VERSION)" \ - $< > $@ - -docs/BusyBox.html: docs/busybox.lineo.com/BusyBox.html - - mkdir -p docs - -@ rm -f docs/BusyBox.html - -@ ln -s busybox.lineo.com/BusyBox.html docs/BusyBox.html - -docs/busybox.lineo.com/BusyBox.html: docs/busybox.pod - -@ mkdir -p docs/busybox.lineo.com - - pod2html --noindex $< > \ - docs/busybox.lineo.com/BusyBox.html - -@ rm -f pod2htm* - - -# New docs based on DOCBOOK SGML -newdoc: docs/busybox.txt docs/busybox.pdf docs/busybox/busyboxdocumentation.html - -docs/busybox.txt: docs/busybox.sgml - @echo - @echo BusyBox Documentation - @echo - - mkdir -p docs - (cd docs; sgmltools -b txt busybox.sgml) - -docs/busybox.dvi: docs/busybox.sgml - - mkdir -p docs - (cd docs; sgmltools -b dvi busybox.sgml) - -docs/busybox.ps: docs/busybox.sgml - - mkdir -p docs - (cd docs; sgmltools -b ps busybox.sgml) - -docs/busybox.pdf: docs/busybox.ps - - mkdir -p docs - (cd docs; ps2pdf busybox.ps) - -docs/busybox/busyboxdocumentation.html: docs/busybox.sgml - - mkdir -p docs - (cd docs/busybox.lineo.com; sgmltools -b html ../busybox.sgml) - - -busybox: $(PWD_LIB) $(LIBBB_LIB) $(OBJECTS) - $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBBB_LIB) $(PWD_LIB) $(LIBRARIES) - $(STRIP) - -# Without VPATH, rule expands to "/bin/sh busybox.mkll Config.h applets.h" -# but with VPATH, some or all of those file names are resolved to the -# directories in which they live. -busybox.links: busybox.mkll Config.h applets.h - - $(SHELL) $^ >$@ - -nfsmount.o cmdedit.o: %.o: %.h -ash.o hush.o lash.o msh.o: cmdedit.h -$(OBJECTS): %.o: %.c Config.h busybox.h applets.h Makefile -ifeq ($(strip $(BB_SRC_DIR)),) - $(CC) $(CFLAGS) -I. $(patsubst %,-I%,$(subst :, ,$(BB_SRC_DIR))) -c $< -o $*.o -else - $(CC) $(CFLAGS) -I- -I. $(patsubst %,-I%,$(subst :, ,$(BB_SRC_DIR))) -c $< -o $*.o -endif - -$(PWD_OBJS): %.o: %.c Config.h busybox.h applets.h Makefile - - mkdir -p $(PWD_GRP) - $(CC) $(CFLAGS) $(PWD_CFLAGS) -c $< -o $*.o - -$(LIBBB_OBJS): %.o: %.c Config.h busybox.h applets.h Makefile libbb/libbb.h - - mkdir -p $(LIBBB) - $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -c $< -o $*.o - -$(LIBBB_MOBJ): $(LIBBB_MSRC) - - mkdir -p $(LIBBB) - $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -DL_$(patsubst libbb/%,%,$*) -c $< -o $*.o - -$(LIBBB_AROBJS): $(LIBBB_ARCSRC) - - mkdir -p $(LIBBB) - $(CC) $(CFLAGS) $(LIBBB_CFLAGS) -DL_$(patsubst libbb/%,%,$*) -c $< -o $*.o - -libpwd.a: $(PWD_OBJS) - $(AR) $(ARFLAGS) $@ $^ - -libbb.a: $(LIBBB_MOBJ) $(LIBBB_AROBJS) $(LIBBB_OBJS) - $(AR) $(ARFLAGS) $@ $^ - -usage.o: usage.h - -libbb/loop.o: libbb/loop.h - -libbb/loop.h: mk_loop_h.sh - @ $(SHELL) $< > $@ - -test tests: - # old way of doing it - #cd tests && $(MAKE) all - # new way of doing it - cd tests && ./tester.sh - -clean: - - cd tests && $(MAKE) clean - - rm -f docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html \ - docs/busybox.lineo.com/BusyBox.html - - rm -f docs/busybox.txt docs/busybox.dvi docs/busybox.ps \ - docs/busybox.pdf docs/busybox.lineo.com/busybox.html - - rm -f multibuild.log Config.h.orig *.gdb *.elf - - rm -rf docs/busybox _install libpwd.a libbb.a pod2htm* - - rm -f busybox.links libbb/loop.h *~ slist.mk core applet_source_list - - find -name \*.o -exec rm -f {} \; - -distclean: clean - - cd tests && $(MAKE) distclean - - rm -f busybox applet_source_list - -install: install.sh busybox busybox.links - $(SHELL) $< $(PREFIX) - -install-hardlinks: install.sh busybox busybox.links - $(SHELL) $< $(PREFIX) --hardlinks - -debug_pristine: - @ echo VPATH=\"$(VPATH)\" - @ echo OBJECTS=\"$(OBJECTS)\" - -dist release: distclean doc - cd ..; \ - rm -rf busybox-$(VERSION); \ - cp -a busybox busybox-$(VERSION); \ - \ - find busybox-$(VERSION)/ -type d \ - -name CVS \ - -print \ - -exec rm -rf {} \; ; \ - \ - find busybox-$(VERSION)/ -type f \ - -name .\#* \ - -print \ - -exec rm -f {} \; ; \ - \ - tar -cvzf busybox-$(VERSION).tar.gz busybox-$(VERSION)/; - -.PHONY: tags -tags: - ctags -R . diff --git a/busybox/README b/busybox/README deleted file mode 100644 index b45ef57f4..000000000 --- a/busybox/README +++ /dev/null @@ -1,152 +0,0 @@ -Please see the LICENSE file for copyright information. - -BusyBox combines tiny versions of many common UNIX utilities into a single -small executable. It provides minimalist replacements for most of the utilities -you usually find in fileutils, shellutils, findutils, textutils, grep, gzip, -tar, etc. BusyBox provides a fairly complete POSIX environment for any small or -embedded system. The utilities in BusyBox generally have fewer options than -their full featured GNU cousins; however, the options that are included provide -the expected functionality and behave very much like their GNU counterparts. - -BusyBox has been written with size-optimization and limited resources in mind. -It is also extremely modular so you can easily include or exclude commands (or -features) at compile time. This makes it easy to customize your embedded -systems. To create a working system, just add /dev, /etc, and a kernel. - -BusyBox was originally written to support the Debian Rescue/Install disks, but -it also makes an excellent environment for any small or embedded system. - -As of version 0.20 there is now a version number. : ) Also as of version 0.20, -BusyBox is now modularized to easily allow you to build only the components you -need, thereby reducing binary size. To turn off unwanted BusyBox components, -simply edit the file "Config.h" and comment out the components you do not need -using C++ style (//) comments. - -After the build is complete, a busybox.links file is generated. This is -used by 'make install' to create symlinks to the busybox binary for all -compiled in functions. By default, 'make install' will place the symlink -forest into `pwd`/_install unless you have defined the PREFIX environment -variable (i.e., 'make PREFIX=/tmp/foo install') - ----------------- - -Supported architectures: - - Busybox in general will build on any architecture supported by gcc. It has - a few specialized features added for __sparc__ and __alpha__. insmod - functionality is currently limited to x86, ARM, SH3/4, powerpc, m68k, - and MIPS. - -Supported libcs: - - glibc-2.0.x, glibc-2.1.x, Linux-libc5, uClibc. People are looking at - newlib and diet-libc, but consider them unsupported, untested, or worse. - -Supported kernels: - - Full functionality requires Linux 2.0.x, 2.2.x, or 2.4.x. A large fraction - of the code should run on just about anything. - ----------------- - -Shells: - -lash is the very smallest shell (adds just 10k) and it is quite usable as -a command prompt, but it is not suitable for any but the most trivial -scripting (such as an initrd that calls insmod a few times) since it does -not understand Bourne shell grammer. It does handle pipes, redirects, and -job control though. Adding in command editing makes it a very nice -lightweight command prompt. - -hush is also quite small (just 18k) and it has very complete Bourne shell -grammer. It handles if/then/else/fi just fine, but doesn't handle loops -like for/do/done or case/esac and such. It also currently has a problem -with job control. Using hush is not yet recommended. - -msh: The minix shell (adds just 30k) is quite complete and handles things -like for/do/done, case/esac and all the things you expect a Bourne shell to -do. It is not always pedantically correct about Bourne shell grammer (try -running the shell testscript "tests/sh.testcases" on it and compare vs bash) -but for most things it works quite well. It also uses only vfork, so it can -be used on uClinux systems. This was only recently added, so there is still -room to shrink it further... - -ash: This adds about 60k in the default configuration and is the most -complete and most pedantically correct shell included with busybox. This -shell was also recently added, and several people (mainly Vladimir and Erik) -have been working on it. There are a number of configurable things at the -top of ash.c as well, so check those out if you want to tweak things. - ----------------- - -Getting help: - -When you find you need help, you can check out the BusyBox mailing list -archives at http://opensource.lineo.com/lists/busybox/ or even join -the mailing list if you are interested. - ----------------- - -Bugs: - -If you find bugs, please submit a bug report. Full instructions on how to -report a bug are found at http://bugs.lineo.com/Reporting.html. - -For the impatient: To submit a bug, simply send an email describing the problem -to submit@bugs.lineo.com. Bug reports should look something like this: - - To: submit@bugs.lineo.com - From: diligent@testing.linux.org - Subject: /bin/true doesn't work - - Package: busybox - Version: 0.51 - - When I invoke '/bin/true' it doesn't work. I expected it to return - a "0" but it returned a "1" instead. Here is the transcript: - $ /bin/true ; echo $? - 1 - With GNU /bin/true, I get the following output: - $ /bin/true ; echo $? - 0 - I am using Debian 2.2r2, kernel version 2.2.18, and the latest - uClibc from CVS. Thanks for the wonderful program! - -Diligent - -Note the careful description and use of examples showing not only what BusyBox -does, but also a counter example showing what an equivalent GNU app does. Bug -reports lacking such detail may take a _long_ time to be fixed... Thanks for -understanding. - ----------------- - -FTP: - -Source for the latest released version can always be downloaded from - ftp://ftp.lineo.com/pub/busybox. - ----------------- - -CVS: - -BusyBox now has its own publicly browsable CVS tree at: - http://opensource.lineo.com/cgi-bin/cvsweb/busybox/ - -Anonymous CVS access is available. For instructions, check out: - http://opensource.lineo.com/cvs_anon.html - -For those that are actively contributing there is even CVS write access: - http://opensource.lineo.com/cvs_write.html - ----------------- - -Please feed suggestions, bug reports, insults, and bribes back to: - Erik Andersen - - - - - -Many thanks to go to Lineo for paying me to work on busybox. - - diff --git a/busybox/TODO b/busybox/TODO deleted file mode 100644 index 3d9af20a7..000000000 --- a/busybox/TODO +++ /dev/null @@ -1,57 +0,0 @@ -TODO list for busybox in no particular order. Just because something -is listed here doesn't mean that it is going to be added to busybox, -or that doing so is even a good idea. It just means that I _might_ get -around to it some time. If you have any good ideas, please let me know. - -* login/sulogin/passwd/getty/etc are part of tinylogin, and so are not - needed or wanted in busybox (or else I'd have to link to libcrypt). - -* We _were_ going to split networking apps into a new package called - netkit-tiny. Per discussions on the mailing list, this isn't going - to happen. False alarm. Sorry about the confusion. - - - -Erik - ------------ - -Possible apps to include some time: - -* hwclock -* start-stop-daemon -* group/commonize strings, remove dups (for i18n, l10n) - ------------ - -With sysvinit, reboot, poweroff and halt all used a named pipe, -/dev/initctl, to communicate with the init process. Busybox -currently uses signals to communicate with init. This makes -busybox incompatible with sysvinit. We should probably use -a named pipe as well so we can be compatible. - ------------------------ - -Run the following: - - rm -f busybox && make LDFLAGS+=-nostdlib 2>&1 | \ - sed -ne 's/.*undefined reference to `\(.*\)..*/\1/gp' | sort | uniq - -reveals the list of all external (i.e., libc) things that BusyBox depends on. -It would be a very nice thing to reduce this list to an absolute minimum, to -reduce the footprint of busybox, especially when staticly linking with -libraries such as uClibc. - ------------------------ - -Compile with debugging on, run 'nm --size-sort ./busybox' -and then start with the biggest things and make them smaller... - ------------------------ - - du.c probably ought to have an -x switch like GNU du does... - ------------------------ - -xargs could use a -l option - ------------------------------------------------------------------- diff --git a/busybox/adjtimex.c b/busybox/adjtimex.c deleted file mode 100644 index e3c160d87..000000000 --- a/busybox/adjtimex.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * adjtimex.c - read, and possibly modify, the Linux kernel `timex' variables. - * - * Originally written: October 1997 - * Last hack: March 2001 - * Copyright 1997, 2000, 2001 Larry Doolittle - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2, - * June 1991) as published by the Free Software Foundation. At the - * time of writing, that license was published by the FSF with the URL - * http://www.gnu.org/copyleft/gpl.html, and is incorporated herein by - * reference. - * - * 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 adjtimex(1) is very similar in intent to adjtimex(8) by Steven - * Dick and Jim Van Zandt - * (see http://metalab.unc.edu/pub/Linux/system/admin/time/adjtimex*). - * That version predates this one, and is _much_ bigger and more - * featureful. My independently written version was very similar to - * Steven's from the start, because they both follow the kernel timex - * structure. I further tweaked this version to be equivalent to Steven's - * where possible, but I don't like getopt_long, so the actual usage - * syntax is incompatible. - * - * Amazingly enough, my Red Hat 5.2 sys/timex (and sub-includes) - * don't actually give a prototype for adjtimex(2), so building - * this code (with -Wall) gives a warning. Later versions of - * glibc fix this issue. - * - * This program is too simple for a Makefile, just build with: - * gcc -Wall -O adjtimex.c -o adjtimex - * - * busyboxed 20 March 2001, Larry Doolittle - * It will autosense if it is built in a busybox environment, based - * on the BB_VER preprocessor macro. - */ - -#include -#include -#include -#include - -#if __GNU_LIBRARY__ < 5 -#include -extern int adjtimex(struct timex *buf); -#else -#include -#endif - -#ifdef BB_VER -#include "busybox.h" -#endif - -static struct {int bit; char *name;} statlist[] = { - { STA_PLL, "PLL" }, - { STA_PPSFREQ, "PPSFREQ" }, - { STA_PPSTIME, "PPSTIME" }, - { STA_FLL, "FFL" }, - { STA_INS, "INS" }, - { STA_DEL, "DEL" }, - { STA_UNSYNC, "UNSYNC" }, - { STA_FREQHOLD, "FREQHOLD" }, - { STA_PPSSIGNAL, "PPSSIGNAL" }, - { STA_PPSJITTER, "PPSJITTER" }, - { STA_PPSWANDER, "PPSWANDER" }, - { STA_PPSERROR, "PPSERROR" }, - { STA_CLOCKERR, "CLOCKERR" }, - { 0, NULL } }; - -static char *ret_code_descript[] = { - "clock synchronized", - "insert leap second", - "delete leap second", - "leap second in progress", - "leap second has occurred", - "clock not synchronized" }; - -#ifdef BB_VER -#define main adjtimex_main -#else -void usage(char *prog) -{ - fprintf(stderr, - "Usage: %s [ -q ] [ -o offset ] [ -f frequency ] [ -p timeconstant ] [ -t tick ]\n", - prog); -} -#define show_usage() usage(argv[0]) -#endif - -int main(int argc, char ** argv) -{ - struct timex txc; - int quiet=0; - int c, i, ret, sep; - char *descript; - txc.modes=0; - for (;;) { - c = getopt( argc, argv, "qo:f:p:t:"); - if (c == EOF) break; - switch (c) { - case 'q': - quiet=1; - break; - case 'o': - txc.offset = atoi(optarg); - txc.modes |= ADJ_OFFSET_SINGLESHOT; - break; - case 'f': - txc.freq = atoi(optarg); - txc.modes |= ADJ_FREQUENCY; - break; - case 'p': - txc.constant = atoi(optarg); - txc.modes |= ADJ_TIMECONST; - break; - case 't': - txc.tick = atoi(optarg); - txc.modes |= ADJ_TICK; - break; - default: - show_usage(); - exit(1); - } - } - if (argc != optind) { /* no valid non-option parameters */ - show_usage(); - exit(1); - } - - ret = adjtimex(&txc); - - if (ret < 0) perror("adjtimex"); - - if (!quiet && ret>=0) { - printf( - " mode: %d\n" - "-o offset: %ld\n" - "-f frequency: %ld\n" - " maxerror: %ld\n" - " esterror: %ld\n" - " status: %d ( ", - txc.modes, txc.offset, txc.freq, txc.maxerror, - txc.esterror, txc.status); - - /* representative output of next code fragment: - "PLL | PPSTIME" */ - sep=0; - for (i=0; statlist[i].name; i++) { - if (txc.status & statlist[i].bit) { - if (sep) fputs(" | ",stdout); - fputs(statlist[i].name,stdout); - sep=1; - } - } - - descript = "error"; - if (ret >= 0 && ret <= 5) descript = ret_code_descript[ret]; - printf(" )\n" - "-p timeconstant: %ld\n" - " precision: %ld\n" - " tolerance: %ld\n" - "-t tick: %ld\n" - " time.tv_sec: %ld\n" - " time.tv_usec: %ld\n" - " return value: %d (%s)\n", - txc.constant, - txc.precision, txc.tolerance, txc.tick, - (long)txc.time.tv_sec, (long)txc.time.tv_usec, ret, descript); - } - return (ret<0); -} diff --git a/busybox/applets.c b/busybox/applets.c deleted file mode 100644 index f3e56a9f3..000000000 --- a/busybox/applets.c +++ /dev/null @@ -1,116 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include "busybox.h" - -#undef APPLET -#undef APPLET_NOUSAGE -#undef PROTOTYPES -#include "applets.h" - -struct BB_applet *applet_using; - -/* The -1 arises because of the {0,NULL,0,-1} entry above. */ -const size_t NUM_APPLETS = (sizeof (applets) / sizeof (struct BB_applet) - 1); - -extern void show_usage(void) -{ - const char *format_string; - const char *usage_string = usage_messages; - int i; - - for (i = applet_using - applets; i > 0; ) { - if (!*usage_string++) { - --i; - } - } - format_string = "%s\n\nUsage: %s %s\n\n"; - if(*usage_string == 0) - format_string = "%s\n\nNo help available.\n\n"; - fprintf(stderr, format_string, - full_version, applet_using->name, usage_string); - exit(EXIT_FAILURE); -} - -static int applet_name_compare(const void *x, const void *y) -{ - const char *name = x; - const struct BB_applet *applet = y; - - return strcmp(name, applet->name); -} - -extern const size_t NUM_APPLETS; - -struct BB_applet *find_applet_by_name(const char *name) -{ - return bsearch(name, applets, NUM_APPLETS, sizeof(struct BB_applet), - applet_name_compare); -} - -void run_applet_by_name(const char *name, int argc, char **argv) -{ - static int recurse_level = 0; - extern int been_there_done_that; /* From busybox.c */ - - recurse_level++; - /* Do a binary search to find the applet entry given the name. */ - if ((applet_using = find_applet_by_name(name)) != NULL) { - applet_name = applet_using->name; - if (argv[1] && strcmp(argv[1], "--help") == 0) { - if (strcmp(applet_using->name, "busybox")==0) { - if(argv[2]) - applet_using = find_applet_by_name(argv[2]); - else - applet_using = NULL; - } - if(applet_using) - show_usage(); - been_there_done_that=1; - busybox_main(0, NULL); - } - exit((*(applet_using->main)) (argc, argv)); - } - /* Just in case they have renamed busybox - Check argv[1] */ - if (recurse_level == 1) { - run_applet_by_name("busybox", argc, argv); - } - recurse_level--; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/applets.h b/busybox/applets.h deleted file mode 100644 index 7d7517385..000000000 --- a/busybox/applets.h +++ /dev/null @@ -1,478 +0,0 @@ -/* - * applets.h - a listing of all busybox applets. - * - * If you write a new applet, you need to add an entry to this list to make - * busybox aware of it. - * - * It is CRUCIAL that this listing be kept in ascii order, otherwise the binary - * search lookup contributed by Gaute B Strokkenes stops working. If you value - * your kneecaps, you'll be sure to *make sure* that any changes made to this - * file result in the listing remaining in ascii order. You have been warned. - */ - -#undef APPLET -#undef APPLET_ODDNAME -#undef APPLET_NOUSAGE - - -#if defined(PROTOTYPES) - #define APPLET(a,b,c) extern int b(int argc, char **argv); - #define APPLET_NOUSAGE(a,b,c) extern int b(int argc, char **argv); - #define APPLET_ODDNAME(a,b,c,d) extern int b(int argc, char **argv); - extern const char usage_messages[]; -#elif defined(MAKE_USAGE) - #ifdef BB_FEATURE_VERBOSE_USAGE - #define APPLET(a,b,c) a##_trivial_usage "\n\n" a##_full_usage "\0" - #define APPLET_NOUSAGE(a,b,c) "\0" - #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\n\n" d##_full_usage "\0" - #else - #define APPLET(a,b,c) a##_trivial_usage "\0" - #define APPLET_NOUSAGE(a,b,c) "\0" - #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\0" - #endif -#elif defined(MAKE_LINKS) -# define APPLET(a,b,c) LINK c a -# define APPLET_NOUSAGE(a,b,c) LINK c a -# define APPLET_ODDNAME(a,b,c,d) LINK c a -#else - const struct BB_applet applets[] = { - #define APPLET(a,b,c) {#a,b,c}, - #define APPLET_NOUSAGE(a,b,c) {a,b,c}, - #define APPLET_ODDNAME(a,b,c,d) {a,b,c}, -#endif - - - -#ifdef BB_TEST - APPLET_NOUSAGE("[", test_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_ADJTIMEX - APPLET(adjtimex, adjtimex_main, _BB_DIR_SBIN) -#endif -#ifdef BB_AR - APPLET(ar, ar_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_ASH - APPLET_NOUSAGE("ash", ash_main, _BB_DIR_BIN) -#endif -#ifdef BB_BASENAME - APPLET(basename, basename_main, _BB_DIR_USR_BIN) -#endif - APPLET_NOUSAGE("busybox", busybox_main, _BB_DIR_BIN) -#ifdef BB_CAT - APPLET(cat, cat_main, _BB_DIR_BIN) -#endif -#ifdef BB_CHGRP - APPLET(chgrp, chgrp_main, _BB_DIR_BIN) -#endif -#ifdef BB_CHMOD - APPLET(chmod, chmod_main, _BB_DIR_BIN) -#endif -#ifdef BB_CHOWN - APPLET(chown, chown_main, _BB_DIR_BIN) -#endif -#ifdef BB_CHROOT - APPLET(chroot, chroot_main, _BB_DIR_USR_SBIN) -#endif -#ifdef BB_CHVT - APPLET(chvt, chvt_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_CLEAR - APPLET(clear, clear_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_CMP - APPLET(cmp, cmp_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_CP - APPLET(cp, cp_main, _BB_DIR_BIN) -#endif -#ifdef BB_CPIO - APPLET(cpio, cpio_main, _BB_DIR_BIN) -#endif -#ifdef BB_CUT - APPLET(cut, cut_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_DATE - APPLET(date, date_main, _BB_DIR_BIN) -#endif -#ifdef BB_DC - APPLET(dc, dc_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_DD - APPLET(dd, dd_main, _BB_DIR_BIN) -#endif -#ifdef BB_DEALLOCVT - APPLET(deallocvt, deallocvt_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_DF - APPLET(df, df_main, _BB_DIR_BIN) -#endif -#ifdef BB_DIRNAME - APPLET(dirname, dirname_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_DMESG - APPLET(dmesg, dmesg_main, _BB_DIR_BIN) -#endif -#ifdef BB_DOS2UNIX - APPLET(dos2unix, dos2unix_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_DPKG - APPLET(dpkg, dpkg_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_DPKG_DEB - APPLET_ODDNAME("dpkg-deb", dpkg_deb_main, _BB_DIR_USR_BIN, dpkg_deb) -#endif -#ifdef BB_DU - APPLET(du, du_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_DUMPKMAP - APPLET(dumpkmap, dumpkmap_main, _BB_DIR_BIN) -#endif -#ifdef BB_DUTMP - APPLET(dutmp, dutmp_main, _BB_DIR_USR_SBIN) -#endif -#ifdef BB_ECHO - APPLET(echo, echo_main, _BB_DIR_BIN) -#endif -#if defined(BB_FEATURE_GREP_EGREP_ALIAS) && defined(BB_GREP) - APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN) -#endif -#ifdef BB_ENV - APPLET(env, env_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_EXPR - APPLET(expr, expr_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TRUE_FALSE - APPLET(false, false_main, _BB_DIR_BIN) -#endif -#ifdef BB_FBSET - APPLET(fbset, fbset_main, _BB_DIR_USR_SBIN) -#endif -#ifdef BB_FDFLUSH - APPLET(fdflush, fdflush_main, _BB_DIR_BIN) -#endif -#ifdef BB_FIND - APPLET(find, find_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_FREE - APPLET(free, free_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_FREERAMDISK - APPLET(freeramdisk, freeramdisk_main, _BB_DIR_SBIN) -#endif -#ifdef BB_FSCK_MINIX - APPLET_ODDNAME("fsck.minix", fsck_minix_main, _BB_DIR_SBIN, fsck_minix) -#endif -#ifdef BB_GETOPT - APPLET(getopt, getopt_main, _BB_DIR_BIN) -#endif -#ifdef BB_GREP - APPLET(grep, grep_main, _BB_DIR_BIN) -#endif -#ifdef BB_GUNZIP - APPLET(gunzip, gunzip_main, _BB_DIR_BIN) -#endif -#ifdef BB_GZIP - APPLET(gzip, gzip_main, _BB_DIR_BIN) -#endif -#ifdef BB_HALT - APPLET(halt, halt_main, _BB_DIR_SBIN) -#endif -#ifdef BB_HEAD - APPLET(head, head_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_HOSTID - APPLET(hostid, hostid_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_HOSTNAME - APPLET(hostname, hostname_main, _BB_DIR_BIN) -#endif -#ifdef BB_HUSH - APPLET_NOUSAGE("hush", hush_main, _BB_DIR_BIN) -#endif -#ifdef BB_ID - APPLET(id, id_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_IFCONFIG - APPLET(ifconfig, ifconfig_main, _BB_DIR_SBIN) -#endif -#ifdef BB_INIT - APPLET(init, init_main, _BB_DIR_SBIN) -#endif -#ifdef BB_INSMOD - APPLET(insmod, insmod_main, _BB_DIR_SBIN) -#endif -#ifdef BB_KILL - APPLET(kill, kill_main, _BB_DIR_BIN) -#endif -#ifdef BB_KILLALL - APPLET(killall, kill_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_KLOGD - APPLET(klogd, klogd_main, _BB_DIR_SBIN) -#endif -#ifdef BB_LASH - APPLET(lash, lash_main, _BB_DIR_BIN) -#endif -#ifdef BB_LENGTH - APPLET(length, length_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_FEATURE_LINUXRC - APPLET_NOUSAGE("linuxrc", init_main, _BB_DIR_ROOT) -#endif -#ifdef BB_LN - APPLET(ln, ln_main, _BB_DIR_BIN) -#endif -#ifdef BB_LOADACM - APPLET(loadacm, loadacm_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_LOADFONT - APPLET(loadfont, loadfont_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_LOADKMAP - APPLET(loadkmap, loadkmap_main, _BB_DIR_SBIN) -#endif -#ifdef BB_LOGGER - APPLET(logger, logger_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_LOGNAME - APPLET(logname, logname_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_LOGREAD - APPLET(logread, logread_main, _BB_DIR_SBIN) -#endif -#ifdef BB_LS - APPLET(ls, ls_main, _BB_DIR_BIN) -#endif -#ifdef BB_LSMOD - APPLET(lsmod, lsmod_main, _BB_DIR_SBIN) -#endif -#ifdef BB_MAKEDEVS - APPLET(makedevs, makedevs_main, _BB_DIR_SBIN) -#endif -#ifdef BB_MD5SUM - APPLET(md5sum, md5sum_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_MKDIR - APPLET(mkdir, mkdir_main, _BB_DIR_BIN) -#endif -#ifdef BB_MKFIFO - APPLET(mkfifo, mkfifo_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_MKFS_MINIX - APPLET_ODDNAME("mkfs.minix", mkfs_minix_main, _BB_DIR_SBIN, mkfs_minix) -#endif -#ifdef BB_MKNOD - APPLET(mknod, mknod_main, _BB_DIR_BIN) -#endif -#ifdef BB_MKSWAP - APPLET(mkswap, mkswap_main, _BB_DIR_SBIN) -#endif -#ifdef BB_MKTEMP - APPLET(mktemp, mktemp_main, _BB_DIR_BIN) -#endif -#ifdef BB_MODPROBE - APPLET(modprobe, modprobe_main, _BB_DIR_SBIN) -#endif -#ifdef BB_MORE - APPLET(more, more_main, _BB_DIR_BIN) -#endif -#ifdef BB_MOUNT - APPLET(mount, mount_main, _BB_DIR_BIN) -#endif -#ifdef BB_MSH - APPLET_NOUSAGE("msh", msh_main, _BB_DIR_BIN) -#endif -#ifdef BB_MT - APPLET(mt, mt_main, _BB_DIR_BIN) -#endif -#ifdef BB_MV - APPLET(mv, mv_main, _BB_DIR_BIN) -#endif -#ifdef BB_NC - APPLET(nc, nc_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_NSLOOKUP - APPLET(nslookup, nslookup_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_PIDOF - APPLET(pidof, pidof_main, _BB_DIR_BIN) -#endif -#ifdef BB_PING - APPLET(ping, ping_main, _BB_DIR_BIN) -#endif -#ifdef BB_PIVOT_ROOT - APPLET(pivot_root, pivot_root_main, _BB_DIR_SBIN) -#endif -#ifdef BB_POWEROFF - APPLET(poweroff, poweroff_main, _BB_DIR_SBIN) -#endif -#ifdef BB_PRINTF - APPLET(printf, printf_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_PS - APPLET(ps, ps_main, _BB_DIR_BIN) -#endif -#ifdef BB_PWD - APPLET(pwd, pwd_main, _BB_DIR_BIN) -#endif -#ifdef BB_RDATE - APPLET(rdate, rdate_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_READLINK - APPLET(readlink, readlink_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_REBOOT - APPLET(reboot, reboot_main, _BB_DIR_SBIN) -#endif -#ifdef BB_RENICE - APPLET(renice, renice_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_RESET - APPLET(reset, reset_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_RM - APPLET(rm, rm_main, _BB_DIR_BIN) -#endif -#ifdef BB_RMDIR - APPLET(rmdir, rmdir_main, _BB_DIR_BIN) -#endif -#ifdef BB_RMMOD - APPLET(rmmod, rmmod_main, _BB_DIR_SBIN) -#endif -#ifdef BB_ROUTE - APPLET(route, route_main, _BB_DIR_SBIN) -#endif -#ifdef BB_RPM2CPIO - APPLET(rpm2cpio, rpm2cpio_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_SED - APPLET(sed, sed_main, _BB_DIR_BIN) -#endif -#ifdef BB_SETKEYCODES - APPLET(setkeycodes, setkeycodes_main, _BB_DIR_USR_BIN) -#endif -#if defined(BB_FEATURE_SH_IS_ASH) && defined(BB_ASH) - APPLET_NOUSAGE("sh", ash_main, _BB_DIR_BIN) -#elif defined(BB_FEATURE_SH_IS_HUSH) && defined(BB_HUSH) - APPLET_NOUSAGE("sh", hush_main, _BB_DIR_BIN) -#elif defined(BB_FEATURE_SH_IS_LASH) && defined(BB_LASH) - APPLET_NOUSAGE("sh", lash_main, _BB_DIR_BIN) -#elif defined(BB_FEATURE_SH_IS_MSH) && defined(BB_MSH) - APPLET_NOUSAGE("sh", msh_main, _BB_DIR_BIN) -#endif -#ifdef BB_SLEEP - APPLET(sleep, sleep_main, _BB_DIR_BIN) -#endif -#ifdef BB_SORT - APPLET(sort, sort_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_STTY - APPLET(stty, stty_main, _BB_DIR_BIN) -#endif -#ifdef BB_SWAPONOFF - APPLET(swapoff, swap_on_off_main, _BB_DIR_SBIN) -#endif -#ifdef BB_SWAPONOFF - APPLET(swapon, swap_on_off_main, _BB_DIR_SBIN) -#endif -#ifdef BB_SYNC - APPLET(sync, sync_main, _BB_DIR_BIN) -#endif -#ifdef BB_SYSLOGD - APPLET(syslogd, syslogd_main, _BB_DIR_SBIN) -#endif -#ifdef BB_TAIL - APPLET(tail, tail_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TAR - APPLET(tar, tar_main, _BB_DIR_BIN) -#endif -#ifdef BB_TEE - APPLET(tee, tee_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TELNET - APPLET(telnet, telnet_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TEST - APPLET(test, test_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TFTP - APPLET(tftp, tftp_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TOUCH - APPLET(touch, touch_main, _BB_DIR_BIN) -#endif -#ifdef BB_TR - APPLET(tr, tr_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TRACEROUTE - APPLET(traceroute, traceroute_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TRUE_FALSE - APPLET(true, true_main, _BB_DIR_BIN) -#endif -#ifdef BB_TTY - APPLET(tty, tty_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_UMOUNT - APPLET(umount, umount_main, _BB_DIR_BIN) -#endif -#ifdef BB_UNAME - APPLET(uname, uname_main, _BB_DIR_BIN) -#endif -#ifdef BB_UNIQ - APPLET(uniq, uniq_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_UNIX2DOS - APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_UPDATE - APPLET(update, update_main, _BB_DIR_SBIN) -#endif -#ifdef BB_UPTIME - APPLET(uptime, uptime_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_USLEEP - APPLET(usleep, usleep_main, _BB_DIR_BIN) -#endif -#ifdef BB_UUDECODE - APPLET(uudecode, uudecode_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_UUENCODE - APPLET(uuencode, uuencode_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_VI - APPLET(vi, vi_main, _BB_DIR_BIN) -#endif -#ifdef BB_WATCHDOG - APPLET(watchdog, watchdog_main, _BB_DIR_SBIN) -#endif -#ifdef BB_WC - APPLET(wc, wc_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_WGET - APPLET(wget, wget_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_WHICH - APPLET(which, which_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_WHOAMI - APPLET(whoami, whoami_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_XARGS - APPLET(xargs, xargs_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_YES - APPLET(yes, yes_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_GUNZIP - APPLET(zcat, gunzip_main, _BB_DIR_BIN) -#endif - -#if !defined(PROTOTYPES) && !defined(MAKE_USAGE) - { 0,NULL,0 } -}; - -#endif diff --git a/busybox/applets/applets.c b/busybox/applets/applets.c deleted file mode 100644 index f3e56a9f3..000000000 --- a/busybox/applets/applets.c +++ /dev/null @@ -1,116 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include "busybox.h" - -#undef APPLET -#undef APPLET_NOUSAGE -#undef PROTOTYPES -#include "applets.h" - -struct BB_applet *applet_using; - -/* The -1 arises because of the {0,NULL,0,-1} entry above. */ -const size_t NUM_APPLETS = (sizeof (applets) / sizeof (struct BB_applet) - 1); - -extern void show_usage(void) -{ - const char *format_string; - const char *usage_string = usage_messages; - int i; - - for (i = applet_using - applets; i > 0; ) { - if (!*usage_string++) { - --i; - } - } - format_string = "%s\n\nUsage: %s %s\n\n"; - if(*usage_string == 0) - format_string = "%s\n\nNo help available.\n\n"; - fprintf(stderr, format_string, - full_version, applet_using->name, usage_string); - exit(EXIT_FAILURE); -} - -static int applet_name_compare(const void *x, const void *y) -{ - const char *name = x; - const struct BB_applet *applet = y; - - return strcmp(name, applet->name); -} - -extern const size_t NUM_APPLETS; - -struct BB_applet *find_applet_by_name(const char *name) -{ - return bsearch(name, applets, NUM_APPLETS, sizeof(struct BB_applet), - applet_name_compare); -} - -void run_applet_by_name(const char *name, int argc, char **argv) -{ - static int recurse_level = 0; - extern int been_there_done_that; /* From busybox.c */ - - recurse_level++; - /* Do a binary search to find the applet entry given the name. */ - if ((applet_using = find_applet_by_name(name)) != NULL) { - applet_name = applet_using->name; - if (argv[1] && strcmp(argv[1], "--help") == 0) { - if (strcmp(applet_using->name, "busybox")==0) { - if(argv[2]) - applet_using = find_applet_by_name(argv[2]); - else - applet_using = NULL; - } - if(applet_using) - show_usage(); - been_there_done_that=1; - busybox_main(0, NULL); - } - exit((*(applet_using->main)) (argc, argv)); - } - /* Just in case they have renamed busybox - Check argv[1] */ - if (recurse_level == 1) { - run_applet_by_name("busybox", argc, argv); - } - recurse_level--; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/applets/busybox.c b/busybox/applets/busybox.c deleted file mode 100644 index 33efb5d84..000000000 --- a/busybox/applets/busybox.c +++ /dev/null @@ -1,181 +0,0 @@ -/* vi: set sw=4 ts=4: */ -#include -#include -#include -#include -#include -#include "busybox.h" -#ifdef BB_LOCALE_SUPPORT -#include -#endif - -int been_there_done_that = 0; /* Also used in applets.c */ -const char *applet_name; - -#ifdef BB_FEATURE_INSTALLER -/* - * directory table - * this should be consistent w/ the enum, busybox.h::Location, - * or else... - */ -static char* install_dir[] = { - "/", - "/bin", - "/sbin", - "/usr/bin", - "/usr/sbin", -}; - -/* abstract link() */ -typedef int (*__link_f)(const char *, const char *); - -/* - * Where in the filesystem is this busybox? - * [return] - * malloc'd string w/ full pathname of busybox's location - * NULL on failure - */ -static char *busybox_fullpath() -{ - return xreadlink("/proc/self/exe"); -} - -/* create (sym)links for each applet */ -static void install_links(const char *busybox, int use_symbolic_links) -{ - __link_f Link = link; - - char *fpc; - int i; - int rc; - - if (use_symbolic_links) - Link = symlink; - - for (i = 0; applets[i].name != NULL; i++) { - fpc = concat_path_file( - install_dir[applets[i].location], applets[i].name); - rc = Link(busybox, fpc); - if (rc!=0 && errno!=EEXIST) { - perror_msg("%s", fpc); - } - free(fpc); - } -} - -#endif /* BB_FEATURE_INSTALLER */ - -int main(int argc, char **argv) -{ - const char *s; - - applet_name = argv[0]; - - if (applet_name[0] == '-') - applet_name++; - - for (s = applet_name; *s != '\0';) { - if (*s++ == '/') - applet_name = s; - } - -#ifdef BB_LOCALE_SUPPORT -#ifdef BB_INIT - if(getpid()!=1) /* Do not set locale for `init' */ -#endif - { - setlocale(LC_ALL, ""); - } -#endif - - run_applet_by_name(applet_name, argc, argv); - error_msg_and_die("applet not found"); -} - - -int busybox_main(int argc, char **argv) -{ - int col = 0, len, i; - -#ifdef BB_FEATURE_INSTALLER - /* - * This style of argument parsing doesn't scale well - * in the event that busybox starts wanting more --options. - * If someone has a cleaner approach, by all means implement it. - */ - if (argc > 1 && (strcmp(argv[1], "--install") == 0)) { - int use_symbolic_links = 0; - int rc = 0; - char *busybox; - - /* to use symlinks, or not to use symlinks... */ - if (argc > 2) { - if ((strcmp(argv[2], "-s") == 0)) { - use_symbolic_links = 1; - } - } - - /* link */ - busybox = busybox_fullpath(); - if (busybox) { - install_links(busybox, use_symbolic_links); - free(busybox); - } else { - rc = 1; - } - return rc; - } -#endif /* BB_FEATURE_INSTALLER */ - - argc--; - - /* If we've already been here once, exit now */ - if (been_there_done_that == 1 || argc < 1) { - const struct BB_applet *a = applets; - - fprintf(stderr, "%s\n\n" - "Usage: busybox [function] [arguments]...\n" - " or: [function] [arguments]...\n\n" - "\tBusyBox is a multi-call binary that combines many common Unix\n" - "\tutilities into a single executable. Most people will create a\n" - "\tlink to busybox for each function they wish to use, and BusyBox\n" - "\twill act like whatever it was invoked as.\n" - "\nCurrently defined functions:\n", full_version); - - while (a->name != 0) { - col += - fprintf(stderr, "%s%s", ((col == 0) ? "\t" : ", "), - (a++)->name); - if (col > 60 && a->name != 0) { - fprintf(stderr, ",\n"); - col = 0; - } - } - fprintf(stderr, "\n\n"); - exit(0); - } - - /* Flag that we've been here already */ - been_there_done_that = 1; - - /* Move the command line down a notch */ - len = argv[argc] + strlen(argv[argc]) - argv[1]; - memmove(argv[0], argv[1], len); - memset(argv[0] + len, 0, argv[1] - argv[0]); - - /* Fix up the argv pointers */ - len = argv[1] - argv[0]; - memmove(argv, argv + 1, sizeof(char *) * (argc + 1)); - for (i = 0; i < argc; i++) - argv[i] -= len; - - return (main(argc, argv)); -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/applets/busybox.mkll b/busybox/applets/busybox.mkll deleted file mode 100755 index 4e15e1611..000000000 --- a/busybox/applets/busybox.mkll +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# Make busybox links list file. - -# input $1: full path to Config.h -# input $2: full path to applets.h -# output (stdout): list of pathnames that should be linked to busybox - -# Maintainer: Larry Doolittle - -export LC_ALL=POSIX -export LC_CTYPE=POSIX - -CONFIG_H=${1:-Config.h} -APPLETS_H=${2:-applets.h} -gcc -E -DMAKE_LINKS -include $CONFIG_H $APPLETS_H | - awk '/^[ \t]*LINK/{ - dir=substr($2,8) - gsub("_","/",dir) - if(dir=="/ROOT") dir="" - file=$3 - gsub("\"","",file) - if (file=="busybox") next - print tolower(dir) "/" file - }' diff --git a/busybox/applets/busybox.sh b/busybox/applets/busybox.sh deleted file mode 100755 index 9ab0f4bdb..000000000 --- a/busybox/applets/busybox.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -export LC_ALL=POSIX -export LC_CTYPE=POSIX - -RAW=` \ - $CC -E -dM ${1:-Config.h} | \ - sed -n -e '/^.*BB_FEATURE.*$/d;s/^#define.*\/\1.c/gp;' \ - | tr A-Z a-z | sort -` -test "${RAW}" != "" || exit -if [ -d "$BB_SRC_DIR" ]; then cd $BB_SRC_DIR; fi -# By running $RAW through "ls", we avoid listing -# source files that don't exist. -ls $RAW 2>/dev/null | tr '\n' ' ' - diff --git a/busybox/applets/install.sh b/busybox/applets/install.sh deleted file mode 100755 index d163a2ef8..000000000 --- a/busybox/applets/install.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh - -export LC_ALL=POSIX -export LC_CTYPE=POSIX - -prefix=$1 -if [ "$prefix" = "" ]; then - echo "No installation directory, aborting." - exit 1; -fi -if [ "$2" = "--hardlinks" ]; then - linkopts="-f" -else - linkopts="-fs" -fi -h=`sort busybox.links | uniq` - - -rm -f $prefix/bin/busybox || exit 1 -mkdir -p $prefix/bin || exit 1 -install -m 755 busybox $prefix/bin/busybox || exit 1 - -for i in $h ; do - appdir=`dirname $i` - mkdir -p $prefix/$appdir || exit 1 - if [ "$2" = "--hardlinks" ]; then - bb_path="$prefix/bin/busybox" - else - case "$appdir" in - /) - bb_path="bin/busybox" - ;; - /bin) - bb_path="busybox" - ;; - /sbin) - bb_path="../bin/busybox" - ;; - /usr/bin|/usr/sbin) - bb_path="../../bin/busybox" - ;; - *) - echo "Unknown installation directory: $appdir" - exit 1 - ;; - esac - fi - echo " $prefix$i -> $bb_path" - ln $linkopts $bb_path $prefix$i || exit 1 -done - -exit 0 diff --git a/busybox/applets/usage.c b/busybox/applets/usage.c deleted file mode 100644 index dfea1f96b..000000000 --- a/busybox/applets/usage.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "busybox.h" - -const char usage_messages[] = - -#define MAKE_USAGE -#include "usage.h" - -#include "applets.h" - -; diff --git a/busybox/applets/usage.h b/busybox/applets/usage.h deleted file mode 100644 index 4d38c43bb..000000000 --- a/busybox/applets/usage.h +++ /dev/null @@ -1,1826 +0,0 @@ -#define adjtimex_trivial_usage \ - "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]" -#define adjtimex_full_usage \ - "Reads and optionally sets system timebase parameters.\n" \ - "See adjtimex(2).\n\n" \ - "Options:\n" \ - "\t-q\t\tquiet mode - do not print\n" \ - "\t-o offset\ttime offset, microseconds\n" \ - "\t-f frequency\tfrequency adjust, integer kernel units (65536 is 1ppm)\n" \ - "\t\t\t(positive values make the system clock run fast)\n" \ - "\t-t tick\t\tmicroseconds per tick, usually 10000\n" \ - "\t-p timeconstant\n" - -#define ar_trivial_usage \ - "-[ov][ptx] ARCHIVE FILES" -#define ar_full_usage \ - "Extract or list FILES from an ar archive.\n\n" \ - "Options:\n" \ - "\t-o\t\tpreserve original dates\n" \ - "\t-p\t\textract to stdout\n" \ - "\t-t\t\tlist\n" \ - "\t-x\t\textract\n" \ - "\t-v\t\tverbosely list files processed\n" - -#define basename_trivial_usage \ - "FILE [SUFFIX]" -#define basename_full_usage \ - "Strips directory path and suffixes from FILE.\n" \ - "If specified, also removes any trailing SUFFIX." -#define basename_example_usage \ - "$ basename /usr/local/bin/foo\n" \ - "foo\n" \ - "$ basename /usr/local/bin/\n" \ - "bin\n" \ - "$ basename /foo/bar.txt .txt\n" \ - "bar" - -#define cat_trivial_usage \ - "[FILE]..." -#define cat_full_usage \ - "Concatenates FILE(s) and prints them to stdout." -#define cat_example_usage \ - "$ cat /proc/uptime\n" \ - "110716.72 17.67" - -#define chgrp_trivial_usage \ - "[OPTION]... GROUP FILE..." -#define chgrp_full_usage \ - "Change the group membership of each FILE to GROUP.\n" \ - "\nOptions:\n" \ - "\t-R\tChanges files and directories recursively." -#define chgrp_example_usage \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chgrp root /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 andersen root 0 Apr 12 18:25 /tmp/foo\n" - -#define chmod_trivial_usage \ - "[-R] MODE[,MODE]... FILE..." -#define chmod_full_usage \ - "Each MODE is one or more of the letters ugoa, one of the\n" \ - "symbols +-= and one or more of the letters rwxst.\n\n" \ - "Options:\n" \ - "\t-R\tChanges files and directories recursively." -#define chmod_example_usage \ - "$ ls -l /tmp/foo\n" \ - "-rw-rw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chmod u+x /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-rwxrw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo*\n" \ - "$ chmod 444 /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" - -#define chown_trivial_usage \ - "[ -Rh ]... OWNER[<.|:>[GROUP]] FILE..." -#define chown_full_usage \ - "Change the owner and/or group of each FILE to OWNER and/or GROUP.\n" \ - "\nOptions:\n" \ - "\t-R\tChanges files and directories recursively.\n" \ - "\t-h\tDo not dereference symbolic links." -#define chown_example_usage \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chown root /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 root andersen 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chown root.root /tmp/foo\n" \ - "ls -l /tmp/foo\n" \ - "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" - -#define chroot_trivial_usage \ - "NEWROOT [COMMAND...]" -#define chroot_full_usage \ - "Run COMMAND with root directory set to NEWROOT." -#define chroot_example_usage \ - "$ ls -l /bin/ls\n" \ - "lrwxrwxrwx 1 root root 12 Apr 13 00:46 /bin/ls -> /BusyBox\n" \ - "$ mount /dev/hdc1 /mnt -t minix\n" \ - "$ chroot /mnt\n" \ - "$ ls -l /bin/ls\n" \ - "-rwxr-xr-x 1 root root 40816 Feb 5 07:45 /bin/ls*\n" - -#define chvt_trivial_usage \ - "N" -#define chvt_full_usage \ - "Changes the foreground virtual terminal to /dev/ttyN" - -#define clear_trivial_usage \ - "" -#define clear_full_usage \ - "Clear screen." - -#define cmp_trivial_usage \ - "FILE1 [FILE2]" -#define cmp_full_usage \ - "\t-s\tquiet mode - do not print\n" \ - "Compare files." - -#define cp_trivial_usage \ - "[OPTION]... SOURCE DEST" -#define cp_full_usage \ - "Copies SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n" \ - "\n" \ - "\t-a\tSame as -dpR\n" \ - "\t-d\tPreserves links\n" \ - "\t-p\tPreserves file attributes if possible\n" \ - "\t-f\tforce (implied; ignored) - always set\n" \ - "\t-R\tCopies directories recursively" - -#define cpio_trivial_usage \ - "-[dimtuv][F cpiofile]" -#define cpio_full_usage \ - "Extract or list files from a cpio archive\n" \ - "Main operation mode:\n" \ - "\td\t\tmake leading directories\n" \ - "\ti\t\textract\n" \ - "\tm\t\tpreserve mtime\n" \ - "\tt\t\tlist\n" \ - "\tu\t\tunconditional overwrite\t" \ - "\tF\t\tinput from file\t" - -#define cut_trivial_usage \ - "[OPTION]... [FILE]..." -#define cut_full_usage \ - "Prints selected fields from each input FILE to standard output.\n\n" \ - "Options:\n" \ - "\t-b LIST\t\tOutput only bytes from LIST\n" \ - "\t-c LIST\t\tOutput only characters from LIST\n" \ - "\t-d CHAR\t\tUse CHAR instead of tab as the field delimiter\n" \ - "\t-s\t\tOutput only the lines containing delimiter\n" \ - "\t-f N\t\tPrint only these fields\n" \ - "\t-n\t\tIgnored" -#define cut_example_usage \ - "$ echo "Hello world" | cut -f 1 -d ' '\n" \ - "Hello\n" \ - "$ echo "Hello world" | cut -f 2 -d ' '\n" \ - "world\n" - -#define date_trivial_usage \ - "[OPTION]... [+FORMAT]" -#define date_full_usage \ - "Displays the current time in the given FORMAT, or sets the system date.\n" \ - "\nOptions:\n" \ - "\t-R\t\tOutputs RFC-822 compliant date string\n" \ - "\t-d STRING\tdisplay time described by STRING, not `now'\n" \ - "\t-s\t\tSets time described by STRING\n" \ - "\t-u\t\tPrints or sets Coordinated Universal Time" -#define date_example_usage \ - "$ date\n" \ - "Wed Apr 12 18:52:41 MDT 2000\n" - -#define dc_trivial_usage \ - "expression ..." -#define dc_full_usage \ - "This is a Tiny RPN calculator that understands the\n" \ - "following operations: +, -, /, *, and, or, not, eor.\n" \ - "i.e., 'dc 2 2 add' -> 4, and 'dc 8 8 \\* 2 2 + /' -> 16" -#define dc_example_usage \ - "$ dc 2 2 +\n" \ - "4\n" \ - "$ dc 8 8 \* 2 2 + /\n" \ - "16\n" \ - "$ dc 0 1 and\n" \ - "0\n" \ - "$ dc 0 1 or\n" \ - "1\n" \ - "$ echo 72 9 div 8 mul | dc\n" \ - "64\n" - -#define dd_trivial_usage \ - "[if=FILE] [of=FILE] [bs=N] [count=N] [skip=N]\n" \ - "\t [seek=N] [conv=notrunc|sync]" -#define dd_full_usage \ - "Copy a file, converting and formatting according to options\n\n" \ - "\tif=FILE\t\tread from FILE instead of stdin\n" \ - "\tof=FILE\t\twrite to FILE instead of stdout\n" \ - "\tbs=N\t\tread and write N bytes at a time\n" \ - "\tcount=N\t\tcopy only N input blocks\n" \ - "\tskip=N\t\tskip N input blocks\n" \ - "\tseek=N\t\tskip N output blocks\n" \ - "\tconv=notrunc\tdon't truncate output file\n" \ - "\tconv=sync\tpad blocks with zeros\n" \ - "\n" \ - "Numbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),\n" \ - "MD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)." -#define dd_example_usage \ - "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" \ - "4+0 records in\n" \ - "4+0 records out\n" - -#define deallocvt_trivial_usage \ - "N" -#define deallocvt_full_usage \ - "Deallocate unused virtual terminal /dev/ttyN" - - -#ifdef BB_FEATURE_HUMAN_READABLE - #define USAGE_HUMAN_READABLE(a) a - #define USAGE_NOT_HUMAN_READABLE(a) -#else - #define USAGE_HUMAN_READABLE(a) - #define USAGE_NOT_HUMAN_READABLE(a) a -#endif -#define df_trivial_usage \ - "[-" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILESYSTEM ...]" -#define df_full_usage \ - "Print the filesystem space used and space available.\n\n" \ - "Options:\n" \ - USAGE_HUMAN_READABLE( \ - "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \ - "\t-m\tprint sizes in megabytes\n" \ - "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \ - "\n\t-k\tprint sizes in kilobytes(compatibility)") -#define df_example_usage \ - "$ df\n" \ - "Filesystem 1k-blocks Used Available Use% Mounted on\n" \ - "/dev/sda3 8690864 8553540 137324 98% /\n" \ - "/dev/sda1 64216 36364 27852 57% /boot\n" \ - "$ df /dev/sda3\n" \ - "Filesystem 1k-blocks Used Available Use% Mounted on\n" \ - "/dev/sda3 8690864 8553540 137324 98% /\n" - -#define dirname_trivial_usage \ - "[FILENAME ...]" -#define dirname_full_usage \ - "Strips non-directory suffix from FILENAME" -#define dirname_example_usage \ - "$ dirname /tmp/foo\n" \ - "/tmp\n" \ - "$ dirname /tmp/foo/\n" \ - "/tmp\n" - -#define dmesg_trivial_usage \ - "[-c] [-n LEVEL] [-s SIZE]" -#define dmesg_full_usage \ - "Prints or controls the kernel ring buffer\n\n" \ - "Options:\n" \ - "\t-c\t\tClears the ring buffer's contents after printing\n" \ - "\t-n LEVEL\tSets console logging level\n" \ - "\t-s SIZE\t\tUse a buffer of size SIZE" - -#define dos2unix_trivial_usage \ - "[option] [FILE]" -#define dos2unix_full_usage \ - "Converts FILE from dos format to unix format. When no option\n" \ - "is given, the input is converted to the opposite output format.\n" \ - "When no file is given, uses stdin for input and stdout for output.\n\n" \ - "Options:\n" \ - "\t-u\toutput will be in UNIX format\n" \ - "\t-d\toutput will be in DOS format" - -#define dpkg_trivial_usage \ - "-i package_file\n" - "[-CPru] package_name" -#define dpkg_full_usage \ - "\t-i\tInstall the package\n" \ - "\t-C\tConfigure an unpackaged package\n" \ - "\t-P\tPurge all files of a package\n" \ - "\t-r\tRemove all but the configuration files for a package\n" \ - "\t-u\tUnpack a package, but dont configure it\n" - -#define dpkg_deb_trivial_usage \ - "[-cefItxX] FILE [argument]" -#define dpkg_deb_full_usage \ - "Perform actions on debian packages (.debs)\n\n" \ - "Options:\n" \ - "\t-c\tList contents of filesystem tree\n" \ - "\t-e\tExtract control files to [argument] directory\n" \ - "\t-f\tDisplay control field name starting with [argument]\n" \ - "\t-I\tDisplay the control filenamed [argument]\n" \ - "\t-t\tExtract filesystem tree to stdout in tar format\n" \ - "\t-x\tExtract packages filesystem tree to directory\n" \ - "\t-X\tVerbose extract" -#define dpkg_deb_example_usage \ - "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n" - -#define du_trivial_usage \ - "[-ls" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILE]..." -#define du_full_usage \ - "Summarizes disk space used for each FILE and/or directory.\n" \ - "Disk space is printed in units of 1024 bytes.\n\n" \ - "Options:\n" \ - "\t-l\tcount sizes many times if hard linked\n" \ - "\t-s\tdisplay only a total for each argument" \ - USAGE_HUMAN_READABLE( \ - "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \ - "\t-m\tprint sizes in megabytes\n" \ - "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \ - "\n\t-k\tprint sizes in kilobytes(compatibility)") -#define du_example_usage \ - "$ du\n" \ - "16 ./CVS\n" \ - "12 ./kernel-patches/CVS\n" \ - "80 ./kernel-patches\n" \ - "12 ./tests/CVS\n" \ - "36 ./tests\n" \ - "12 ./scripts/CVS\n" \ - "16 ./scripts\n" \ - "12 ./docs/CVS\n" \ - "104 ./docs\n" \ - "2417 .\n" - -#define dumpkmap_trivial_usage \ - "> keymap" -#define dumpkmap_full_usage \ - "Prints out a binary keyboard translation table to standard output." -#define dumpkmap_example_usage \ - "$ dumpkmap > keymap\n" - -#define dutmp_trivial_usage \ - "[FILE]" -#define dutmp_full_usage \ - "Dump utmp file format (pipe delimited) from FILE\n" \ - "or stdin to stdout. (i.e., 'dutmp /var/run/utmp')" -#define dutmp_example_usage \ - "$ dutmp /var/run/utmp\n" \ - "8|7||si|||0|0|0|955637625|760097|0\n" \ - "2|0|~|~~|reboot||0|0|0|955637625|782235|0\n" \ - "1|20020|~|~~|runlevel||0|0|0|955637625|800089|0\n" \ - "8|125||l4|||0|0|0|955637629|998367|0\n" \ - "6|245|tty1|1|LOGIN||0|0|0|955637630|998974|0\n" \ - "6|246|tty2|2|LOGIN||0|0|0|955637630|999498|0\n" \ - "7|336|pts/0|vt00andersen|andersen|:0.0|0|0|0|955637763|0|0\n" - -#define echo_trivial_usage \ - "[-neE] [ARG ...]" -#define echo_full_usage \ - "Prints the specified ARGs to stdout\n\n" \ - "Options:\n" \ - "\t-n\tsuppress trailing newline\n" \ - "\t-e\tinterpret backslash-escaped characters (i.e., \\t=tab)\n" \ - "\t-E\tdisable interpretation of backslash-escaped characters" -#define echo_example_usage \ - "$ echo "Erik is cool"\n" \ - "Erik is cool\n" \ - "$ echo -e "Erik\\nis\\ncool"\n" \ - "Erik\n" \ - "is\n" \ - "cool\n" \ - "$ echo "Erik\\nis\\ncool"\n" \ - "Erik\\nis\\ncool\n" - -#define env_trivial_usage \ - "[-iu] [-] [name=value]... [command]" -#define env_full_usage \ - "Prints the current environment or runs a program after setting\n" \ - "up the specified environment.\n\n" \ - "Options:\n" \ - "\t-, -i\tstart with an empty environment\n" \ - "\t-u\tremove variable from the environment\n" - -#define expr_trivial_usage \ - "EXPRESSION" -#define expr_full_usage \ - "Prints the value of EXPRESSION to standard output.\n\n" \ - "EXPRESSION may be:\n" \ - "\tARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n" \ - "\tARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n" \ - "\tARG1 < ARG2 ARG1 is less than ARG2\n" \ - "\tARG1 <= ARG2 ARG1 is less than or equal to ARG2\n" \ - "\tARG1 = ARG2 ARG1 is equal to ARG2\n" \ - "\tARG1 != ARG2 ARG1 is unequal to ARG2\n" \ - "\tARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n" \ - "\tARG1 > ARG2 ARG1 is greater than ARG2\n" \ - "\tARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n" \ - "\tARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n" \ - "\tARG1 * ARG2 arithmetic product of ARG1 and ARG2\n" \ - "\tARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n" \ - "\tARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n" \ - "\tSTRING : REGEXP anchored pattern match of REGEXP in STRING\n" \ - "\tmatch STRING REGEXP same as STRING : REGEXP\n" \ - "\tsubstr STRING POS LENGTH substring of STRING, POS counted from 1\n" \ - "\tindex STRING CHARS index in STRING where any CHARS is found,\n" \ - "\t or 0\n" \ - "\tlength STRING length of STRING\n" \ - "\tquote TOKEN interpret TOKEN as a string, even if\n" \ - "\t it is a keyword like `match' or an\n" \ - "\t operator like `/'\n" \ - "\t( EXPRESSION ) value of EXPRESSION\n\n" \ - "Beware that many operators need to be escaped or quoted for shells.\n" \ - "Comparisons are arithmetic if both ARGs are numbers, else\n" \ - "lexicographical. Pattern matches return the string matched between \n" \ - "\\( and \\) or null; if \\( and \\) are not used, they return the number \n" \ - "of characters matched or 0." - -#define false_trivial_usage \ - "" -#define false_full_usage \ - "Return an exit code of FALSE (1)." -#define false_example_usage \ - "$ false\n" \ - "$ echo $?\n" \ - "1\n" - -#define fbset_trivial_usage \ - "[options] [mode]" -#define fbset_full_usage \ - "Show and modify frame buffer settings" -#define fbset_example_usage \ - "$ fbset\n" \ - "mode "1024x768-76"\n" \ - "\t# D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz\n" \ - "\tgeometry 1024 768 1024 768 16\n" \ - "\ttimings 12714 128 32 16 4 128 4\n" \ - "\taccel false\n" \ - "\trgba 5/11,6/5,5/0,0/0\n" \ - "endmode\n" - -#define fdflush_trivial_usage \ - "DEVICE" -#define fdflush_full_usage \ - "Forces floppy disk drive to detect disk change" - -#ifdef BB_FEATURE_FIND_TYPE - #define USAGE_FIND_TYPE(a) a -#else - #define USAGE_FIND_TYPE(a) -#endif -#ifdef BB_FEATURE_FIND_PERM - #define USAGE_FIND_PERM(a) a -#else - #define USAGE_FIND_PERM(a) -#endif -#ifdef BB_FEATURE_FIND_MTIME - #define USAGE_FIND_MTIME(a) a -#else - #define USAGE_FIND_MTIME(a) -#endif - -#define find_trivial_usage \ - "[PATH...] [EXPRESSION]" -#define find_full_usage \ - "Search for files in a directory hierarchy. The default PATH is\n" \ - "the current directory; default EXPRESSION is '-print'\n" \ - "\nEXPRESSION may consist of:\n" \ - "\t-follow\t\tDereference symbolic links.\n" \ - "\t-name PATTERN\tFile name (leading directories removed) matches PATTERN.\n" \ - "\t-print\t\tPrint (default and assumed).\n" \ - USAGE_FIND_TYPE( \ - "\n\t-type X\t\tFiletype matches X (where X is one of: f,d,l,b,c,...)" \ -) USAGE_FIND_PERM( \ - "\n\t-perm PERMS\tPermissions match any of (+NNN); all of (-NNN);\n\t\t\tor exactly (NNN)" \ -) USAGE_FIND_MTIME( \ - "\n\t-mtime TIME\tModified time is greater than (+N); less than (-N);\n\t\t\tor exactly (N) days") -#define find_example_usage \ - "$ find / -name /etc/passwd\n" \ - "/etc/passwd\n" - -#define free_trivial_usage \ - "" -#define free_full_usage \ - "Displays the amount of free and used system memory" -#define free_example_usage \ - "$ free\n" \ - " total used free shared buffers\n" \ - " Mem: 257628 248724 8904 59644 93124\n" \ - " Swap: 128516 8404 120112\n" \ - "Total: 386144 257128 129016\n" \ - -#define freeramdisk_trivial_usage \ - "DEVICE" -#define freeramdisk_full_usage \ - "Frees all memory used by the specified ramdisk." -#define freeramdisk_example_usage \ - "$ freeramdisk /dev/ram2\n" - -#define fsck_minix_trivial_usage \ - "[-larvsmf] /dev/name" -#define fsck_minix_full_usage \ - "Performs a consistency check for MINIX filesystems.\n\n" \ - "Options:\n" \ - "\t-l\tLists all filenames\n" \ - "\t-r\tPerform interactive repairs\n" \ - "\t-a\tPerform automatic repairs\n" \ - "\t-v\tverbose\n" \ - "\t-s\tOutputs super-block information\n" \ - "\t-m\tActivates MINIX-like \"mode not cleared\" warnings\n" \ - "\t-f\tForce file system check." - -#define getopt_trivial_usage \ - "[OPTIONS]..." -#define getopt_full_usage \ - "Parse command options\n" \ - "\t-a, --alternative Allow long options starting with single -\n" \ - "\t-l, --longoptions=longopts Long options to be recognized\n" \ - "\t-n, --name=progname The name under which errors are reported\n" \ - "\t-o, --options=optstring Short options to be recognized\n" \ - "\t-q, --quiet Disable error reporting by getopt(3)\n" \ - "\t-Q, --quiet-output No normal output\n" \ - "\t-s, --shell=shell Set shell quoting conventions\n" \ - "\t-T, --test Test for getopt(1) version\n" \ - "\t-u, --unqote Do not quote the output" -#define getopt_example_usage \ - "$ cat getopt.test\n" \ - "#!/bin/sh\n" \ - "GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \\\n" \ - " -n 'example.busybox' -- "$@"`\n" \ - "if [ $? != 0 ] ; then exit 1 ; fi\n" \ - "eval set -- "$GETOPT"\n" \ - "while true ; do\n" \ - " case $1 in\n" \ - " -a|--a-long) echo \"Option a\" ; shift ;;\n" \ - " -b|--b-long) echo \"Option b, argument \`$2'\" ; shift 2 ;;\n" \ - " -c|--c-long)\n" \ - " case "$2" in\n" \ - " \"\") echo \"Option c, no argument\"; shift 2 ;;\n" \ - " *) echo \"Option c, argument \`$2'\" ; shift 2 ;;\n" \ - " esac ;;\n" \ - " --) shift ; break ;;\n" \ - " *) echo \"Internal error!\" ; exit 1 ;;\n" \ - " esac\n" \ - "done\n" - -#define grep_trivial_usage \ - "[-ihHnqvs] PATTERN [FILEs...]" -#define grep_full_usage \ - "Search for PATTERN in each FILE or standard input.\n\n" \ - "Options:\n" \ - "\t-H\tprefix output lines with filename where match was found\n" \ - "\t-h\tsuppress the prefixing filename on output\n" \ - "\t-i\tignore case distinctions\n" \ - "\t-l\tlist names of files that match\n" \ - "\t-n\tprint line number with output lines\n" \ - "\t-q\tbe quiet. Returns 0 if result was found, 1 otherwise\n" \ - "\t-v\tselect non-matching lines\n" \ - "\t-s\tsuppress file open/read error messages" -#define grep_example_usage \ - "$ grep root /etc/passwd\n" \ - "root:x:0:0:root:/root:/bin/bash\n" \ - "$ grep ^[rR]oo. /etc/passwd\n" \ - "root:x:0:0:root:/root:/bin/bash\n" - -#define gunzip_trivial_usage \ - "[OPTION]... FILE" -#define gunzip_full_usage \ - "Uncompress FILE (or standard input if FILE is '-').\n\n" \ - "Options:\n" \ - "\t-c\tWrite output to standard output\n" \ - "\t-t\tTest compressed file integrity" -#define gunzip_example_usage \ - "$ ls -la /tmp/BusyBox*\n" \ - "-rw-rw-r-- 1 andersen andersen 557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n" \ - "$ gunzip /tmp/BusyBox-0.43.tar.gz\n" \ - "$ ls -la /tmp/BusyBox*\n" \ - "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n" - -#define gzip_trivial_usage \ - "[OPTION]... FILE" -#define gzip_full_usage \ - "Compress FILE with maximum compression.\n" \ - "When FILE is '-', reads standard input. Implies -c.\n\n" \ - "Options:\n" \ - "\t-c\tWrite output to standard output instead of FILE.gz\n" \ - "\t-d\tdecompress" -#define gzip_example_usage \ - "$ ls -la /tmp/busybox*\n" \ - "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/busybox.tar\n" \ - "$ gzip /tmp/busybox.tar\n" \ - "$ ls -la /tmp/busybox*\n" \ - "-rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/busybox.tar.gz\n" - -#define halt_trivial_usage \ - "" -#define halt_full_usage \ - "Halt the system." - -#define head_trivial_usage \ - "[OPTION] [FILE]..." -#define head_full_usage \ - "Print first 10 lines of each FILE to standard output.\n" \ - "With more than one FILE, precede each with a header giving the\n" \ - "file name. With no FILE, or when FILE is -, read standard input.\n\n" \ - "Options:\n" \ - "\t-n NUM\t\tPrint first NUM lines instead of first 10" -#define head_example_usage \ - "$ head -n 2 /etc/passwd\n" \ - "root:x:0:0:root:/root:/bin/bash\n" \ - "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n" - -#define hostid_trivial_usage \ - "" -#define hostid_full_usage \ - "Print out a unique 32-bit identifier for the machine." - -#define hostname_trivial_usage \ - "[OPTION] {hostname | -F FILE}" -#define hostname_full_usage \ - "Get or set the hostname or DNS domain name. If a hostname is given\n" \ - "(or FILE with the -F parameter), the host name will be set.\n\n" \ - "Options:\n" \ - "\t-s\t\tShort\n" \ - "\t-i\t\tAddresses for the hostname\n" \ - "\t-d\t\tDNS domain name\n" \ - "\t-F, --file FILE\tUse the contents of FILE to specify the hostname" -#define hostname_example_usage \ - "$ hostname\n" \ - "sage \n" - -#define id_trivial_usage \ - "[OPTIONS]... [USERNAME]" -#define id_full_usage \ - "Print information for USERNAME or the current user\n\n" \ - "Options:\n" \ - "\t-g\tprints only the group ID\n" \ - "\t-u\tprints only the user ID\n" \ - "\t-n\tprint a name instead of a number (with for -ug)\n" \ - "\t-r\tprints the real user ID instead of the effective ID (with -ug)" -#define id_example_usage \ - "$ id\n" \ - "uid=1000(andersen) gid=1000(andersen)\n" - -#ifdef BB_FEATURE_IFCONFIG_SLIP - #define USAGE_SIOCSKEEPALIVE(a) a -#else - #define USAGE_SIOCSKEEPALIVE(a) -#endif -#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ - #define USAGE_IFCONFIG_MII(a) a -#else - #define USAGE_IFCONFIG_MII(a) -#endif -#ifdef BB_FEATURE_IFCONFIG_HW - #define USAGE_IFCONFIG_HW(a) a -#else - #define USAGE_IFCONFIG_HW(a) -#endif -#ifdef BB_FEATURE_IFCONFIG_STATUS - #define USAGE_IFCONFIG_OPT_A(a) a -#else - #define USAGE_IFCONFIG_OPT_A(a) -#endif - -#define ifconfig_trivial_usage \ - USAGE_IFCONFIG_OPT_A("[-a]") " [
]" -#define ifconfig_full_usage \ - "configure a network interface\n\n" \ - "Options:\n" \ - "\t[[-]broadcast [
]] [[-]pointopoint [
]]\n" \ - "\t[netmask
] [dstaddr
]\n" \ - USAGE_SIOCSKEEPALIVE("\t[outfill ] [keepalive ]\n") \ - "\t" USAGE_IFCONFIG_HW("[hw ether
] ") \ - "[metric ] [mtu ]\n" \ - "\t[[-]trailers] [[-]arp] [[-]allmulti]\n" \ - "\t[multicast] [[-]promisc] [txqueuelen ] [[-]dynamic]\n" \ - USAGE_IFCONFIG_MII("\t[mem_start ] [io_addr ] [irq ]\n") \ - "\t[up|down] ..." - -#define init_trivial_usage \ - "" -#define init_full_usage \ - "Init is the parent of all processes." -#define init_notes_usage \ -"This version of init is designed to be run only by the kernel.\n" \ -"\n" \ -"BusyBox init doesn't support multiple runlevels. The runlevels field of\n" \ -"the /etc/inittab file is completely ignored by BusyBox init. If you want \n" \ -"runlevels, use sysvinit.\n" \ -"\n" \ -"BusyBox init works just fine without an inittab. If no inittab is found, \n" \ -"it has the following default behavior:\n" \ -"\n" \ -" ::sysinit:/etc/init.d/rcS\n" \ -" ::askfirst:/bin/sh\n" \ -" ::ctrlaltdel:/sbin/reboot\n" \ -" ::shutdown:/sbin/swapoff -a\n" \ -" ::shutdown:/bin/umount -a -r\n" \ -"\n" \ -"if it detects that /dev/console is _not_ a serial console, it will also run:\n" \ -"\n" \ -" tty2::askfirst:/bin/sh\n" \ -" tty3::askfirst:/bin/sh\n" \ -" tty4::askfirst:/bin/sh\n" \ -"\n" \ -"If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" \ -"\n" \ -" :::\n" \ -"\n" \ -" : \n" \ -"\n" \ -" WARNING: This field has a non-traditional meaning for BusyBox init!\n" \ -" The id field is used by BusyBox init to specify the controlling tty for\n" \ -" the specified process to run on. The contents of this field are\n" \ -" appended to "/dev/" and used as-is. There is no need for this field to\n" \ -" be unique, although if it isn't you may have strange results. If this\n" \ -" field is left blank, the controlling tty is set to the console. Also\n" \ -" note that if BusyBox detects that a serial console is in use, then only\n" \ -" entries whose controlling tty is either the serial console or /dev/null\n" \ -" will be run. BusyBox init does nothing with utmp. We don't need no\n" \ -" stinkin' utmp.\n" \ -"\n" \ -" : \n" \ -"\n" \ -" The runlevels field is completely ignored.\n" \ -"\n" \ -" : \n" \ -"\n" \ -" Valid actions include: sysinit, respawn, askfirst, wait, \n" \ -" once, ctrlaltdel, and shutdown.\n" \ -"\n" \ -" The available actions can be classified into two groups: actions\n" \ -" that are run only once, and actions that are re-run when the specified\n" \ -" process exits.\n" \ -"\n" \ -" Run only-once actions:\n" \ -"\n" \ -" 'sysinit' is the first item run on boot. init waits until all\n" \ -" sysinit actions are completed before continuing. Following the\n" \ -" completion of all sysinit actions, all 'wait' actions are run.\n" \ -" 'wait' actions, like 'sysinit' actions, cause init to wait until\n" \ -" the specified task completes. 'once' actions are asynchronous,\n" \ -" therefore, init does not wait for them to complete. 'ctrlaltdel'\n" \ -" actions are run when the system detects that someone on the system\n" \ -" console has pressed the CTRL-ALT-DEL key combination. Typically one\n" \ -" wants to run 'reboot' at this point to cause the system to reboot.\n" \ -" Finally the 'shutdown' action specifies the actions to taken when\n" \ -" init is told to reboot. Unmounting filesystems and disabling swap\n" \ -" is a very good here\n" \ -"\n" \ -" Run repeatedly actions:\n" \ -"\n" \ -" 'respawn' actions are run after the 'once' actions. When a process\n" \ -" started with a 'respawn' action exits, init automatically restarts\n" \ -" it. Unlike sysvinit, BusyBox init does not stop processes from\n" \ -" respawning out of control. The 'askfirst' actions acts just like\n" \ -" respawn, except that before running the specified process it\n" \ -" displays the line "Please press Enter to activate this console."\n" \ -" and then waits for the user to press enter before starting the\n" \ -" specified process. \n" \ -"\n" \ -" Unrecognized actions (like initdefault) will cause init to emit an\n" \ -" error message, and then go along with its business. All actions are\n" \ -" run in the reverse order from how they appear in /etc/inittab.\n" \ -"\n" \ -" : \n" \ -"\n" \ -" Specifies the process to be executed and it's command line.\n" \ -"\n" \ -"Example /etc/inittab file:\n" \ -"\n" \ -" # This is run first except when booting in single-user mode.\n" \ -" #\n" \ -" ::sysinit:/etc/init.d/rcS\n" \ -" \n" \ -" # /bin/sh invocations on selected ttys\n" \ -" #\n" \ -" # Start an "askfirst" shell on the console (whatever that may be)\n" \ -" ::askfirst:-/bin/sh\n" \ -" # Start an "askfirst" shell on /dev/tty2-4\n" \ -" tty2::askfirst:-/bin/sh\n" \ -" tty3::askfirst:-/bin/sh\n" \ -" tty4::askfirst:-/bin/sh\n" \ -" \n" \ -" # /sbin/getty invocations for selected ttys\n" \ -" #\n" \ -" tty4::respawn:/sbin/getty 38400 tty5\n" \ -" tty5::respawn:/sbin/getty 38400 tty6\n" \ -" \n" \ -" \n" \ -" # Example of how to put a getty on a serial line (for a terminal)\n" \ -" #\n" \ -" #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" \ -" #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" \ -" #\n" \ -" # Example how to put a getty on a modem line.\n" \ -" #::respawn:/sbin/getty 57600 ttyS2\n" \ -" \n" \ -" # Stuff to do before rebooting\n" \ -" ::ctrlaltdel:/sbin/reboot\n" \ -" ::shutdown:/bin/umount -a -r\n" \ -" ::shutdown:/sbin/swapoff -a\n" - -#define insmod_trivial_usage \ - "[OPTION]... MODULE [symbol=value]..." -#define insmod_full_usage \ - "Loads the specified kernel modules into the kernel.\n\n" \ - "Options:\n" \ - "\t-f\tForce module to load into the wrong kernel version.\n" \ - "\t-k\tMake module autoclean-able.\n" \ - "\t-v\tverbose output\n" \ - "\t-L\tLock to prevent simultaneous loads of a module\n" \ - "\t-x\tdo not export externs" - -#define kill_trivial_usage \ - "[-signal] process-id [process-id ...]" -#define kill_full_usage \ - "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\ - "Options:\n" \ - "\t-l\tList all signal names and numbers." -#define kill_example_usage \ - "$ ps | grep apache\n" \ - "252 root root S [apache]\n" \ - "263 www-data www-data S [apache]\n" \ - "264 www-data www-data S [apache]\n" \ - "265 www-data www-data S [apache]\n" \ - "266 www-data www-data S [apache]\n" \ - "267 www-data www-data S [apache]\n" \ - "$ kill 252\n" - -#define killall_trivial_usage \ - "[-signal] process-name [process-name ...]" -#define killall_full_usage \ - "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\ - "Options:\n" \ - "\t-l\tList all signal names and numbers." -#define killall_example_usage \ - "$ killall apache\n" - -#define klogd_trivial_usage \ - "-n" -#define klogd_full_usage \ - "Kernel logger.\n"\ - "Options:\n"\ - "\t-n\tRun as a foreground process." - -#define length_trivial_usage \ - "STRING" -#define length_full_usage \ - "Prints out the length of the specified STRING." -#define length_example_usage \ - "$ length Hello\n" \ - "5\n" - -#define ln_trivial_usage \ - "[OPTION] TARGET... LINK_NAME|DIRECTORY" -#define ln_full_usage \ - "Create a link named LINK_NAME or DIRECTORY to the specified TARGET\n"\ - "\nYou may use '--' to indicate that all following arguments are non-options.\n\n" \ - "Options:\n" \ - "\t-s\tmake symbolic links instead of hard links\n" \ - "\t-f\tremove existing destination files\n" \ - "\t-n\tno dereference symlinks - treat like normal file" -#define ln_example_usage \ - "$ ln -s BusyBox /tmp/ls\n" \ - "$ ls -l /tmp/ls\n" \ - "lrwxrwxrwx 1 root root 7 Apr 12 18:39 ls -> BusyBox*\n" - -#define loadacm_trivial_usage \ - "< mapfile" -#define loadacm_full_usage \ - "Loads an acm from standard input." -#define loadacm_example_usage \ - "$ loadacm < /etc/i18n/acmname\n" - -#define loadfont_trivial_usage \ - "< font" -#define loadfont_full_usage \ - "Loads a console font from standard input." -#define loadfont_example_usage \ - "$ loadfont < /etc/i18n/fontname\n" - -#define loadkmap_trivial_usage \ - "< keymap" -#define loadkmap_full_usage \ - "Loads a binary keyboard translation table from standard input." -#define loadkmap_example_usage \ - "$ loadkmap < /etc/i18n/lang-keymap\n" - -#define logger_trivial_usage \ - "[OPTION]... [MESSAGE]" -#define logger_full_usage \ - "Write MESSAGE to the system log. If MESSAGE is omitted, log stdin.\n\n" \ - "Options:\n" \ - "\t-s\tLog to stderr as well as the system log.\n" \ - "\t-t\tLog using the specified tag (defaults to user name).\n" \ - "\t-p\tEnter the message with the specified priority.\n" \ - "\t\tThis may be numerical or a ``facility.level'' pair." -#define logger_example_usage \ - "$ logger "hello"\n" - -#define logname_trivial_usage \ - "" -#define logname_full_usage \ - "Print the name of the current user." -#define logname_example_usage \ - "$ logname\n" \ - "root\n" - -#define logread_trivial_usage \ - "" - -#define logread_full_usage \ - "Shows the messages from syslogd (using circular buffer)." - -#ifdef BB_FEATURE_LS_TIMESTAMPS - #define USAGE_LS_TIMESTAMPS(a) a -#else - #define USAGE_LS_TIMESTAMPS(a) -#endif -#ifdef BB_FEATURE_LS_FILETYPES - #define USAGE_LS_FILETYPES(a) a -#else - #define USAGE_LS_FILETYPES(a) -#endif -#ifdef BB_FEATURE_LS_FOLLOWLINKS - #define USAGE_LS_FOLLOWLINKS(a) a -#else - #define USAGE_LS_FOLLOWLINKS(a) -#endif -#ifdef BB_FEATURE_LS_RECURSIVE - #define USAGE_LS_RECURSIVE(a) a -#else - #define USAGE_LS_RECURSIVE(a) -#endif -#ifdef BB_FEATURE_LS_SORTFILES - #define USAGE_LS_SORTFILES(a) a -#else - #define USAGE_LS_SORTFILES(a) -#endif -#ifdef BB_FEATURE_AUTOWIDTH - #define USAGE_AUTOWIDTH(a) a -#else - #define USAGE_AUTOWIDTH(a) -#endif -#define ls_trivial_usage \ - "[-1Aa" USAGE_LS_TIMESTAMPS("c") "Cd" USAGE_LS_TIMESTAMPS("e") USAGE_LS_FILETYPES("F") "iln" USAGE_LS_FILETYPES("p") USAGE_LS_FOLLOWLINKS("L") USAGE_LS_RECURSIVE("R") USAGE_LS_SORTFILES("rS") "s" USAGE_AUTOWIDTH("T") USAGE_LS_TIMESTAMPS("tu") USAGE_LS_SORTFILES("v") USAGE_AUTOWIDTH("w") "x" USAGE_LS_SORTFILES("X") USAGE_HUMAN_READABLE("h") USAGE_NOT_HUMAN_READABLE("") "k] [filenames...]" -#define ls_full_usage \ - "List directory contents\n\n" \ - "Options:\n" \ - "\t-1\tlist files in a single column\n" \ - "\t-A\tdo not list implied . and ..\n" \ - "\t-a\tdo not hide entries starting with .\n" \ - "\t-C\tlist entries by columns\n" \ - USAGE_LS_TIMESTAMPS("\t-c\twith -l: show ctime\n") \ - "\t-d\tlist directory entries instead of contents\n" \ - USAGE_LS_TIMESTAMPS("\t-e\tlist both full date and full time\n") \ - USAGE_LS_FILETYPES("\t-F\tappend indicator (one of */=@|) to entries\n") \ - "\t-i\tlist the i-node for each file\n" \ - "\t-l\tuse a long listing format\n" \ - "\t-n\tlist numeric UIDs and GIDs instead of names\n" \ - USAGE_LS_FILETYPES("\t-p\tappend indicator (one of /=@|) to entries\n") \ - USAGE_LS_FOLLOWLINKS("\t-L\tlist entries pointed to by symbolic links\n") \ - USAGE_LS_RECURSIVE("\t-R\tlist subdirectories recursively\n") \ - USAGE_LS_SORTFILES("\t-r\tsort the listing in reverse order\n") \ - USAGE_LS_SORTFILES("\t-S\tsort the listing by file size\n") \ - "\t-s\tlist the size of each file, in blocks\n" \ - USAGE_AUTOWIDTH("\t-T NUM\tassume Tabstop every NUM columns\n") \ - USAGE_LS_TIMESTAMPS("\t-t\twith -l: show modification time\n") \ - USAGE_LS_TIMESTAMPS("\t-u\twith -l: show access time\n") \ - USAGE_LS_SORTFILES("\t-v\tsort the listing by version\n") \ - USAGE_AUTOWIDTH("\t-w NUM\tassume the terminal is NUM columns wide\n") \ - "\t-x\tlist entries by lines instead of by columns\n" \ - USAGE_LS_SORTFILES("\t-X\tsort the listing by extension\n") \ - USAGE_HUMAN_READABLE( \ - "\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \ - "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \ - "\t-k\tprint sizes in kilobytes(compatibility)") - -#define lsmod_trivial_usage \ - "" -#define lsmod_full_usage \ - "List the currently loaded kernel modules." - -#define makedevs_trivial_usage \ - "NAME TYPE MAJOR MINOR FIRST LAST [s]" -#define makedevs_full_usage \ - "Creates a range of block or character special files\n\n" \ - "TYPEs include:\n" \ - "\tb:\tMake a block (buffered) device.\n" \ - "\tc or u:\tMake a character (un-buffered) device.\n" \ - "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes.\n\n" \ - "FIRST specifies the number appended to NAME to create the first device.\n" \ - "LAST specifies the number of the last item that should be created.\n" \ - "If 's' is the last argument, the base device is created as well.\n\n" \ - "For example:\n" \ - "\tmakedevs /dev/ttyS c 4 66 2 63 -> ttyS2-ttyS63\n" \ - "\tmakedevs /dev/hda b 3 0 0 8 s -> hda,hda1-hda8" -#define makedevs_example_usage \ - "$ makedevs /dev/ttyS c 4 66 2 63\n" \ - "[creates ttyS2-ttyS63]\n" \ - "$ makedevs /dev/hda b 3 0 0 8 s\n" \ - "[creates hda,hda1-hda8]\n" - -#define md5sum_trivial_usage \ - "[OPTION] [FILE]...\n" \ - "or: md5sum [OPTION] -c [FILE]" -#define md5sum_full_usage \ - "Print or check MD5 checksums.\n\n" \ - "Options:\n" \ - "With no FILE, or when FILE is -, read standard input.\n\n" \ - "\t-b\tread files in binary mode\n" \ - "\t-c\tcheck MD5 sums against given list\n" \ - "\t-t\tread files in text mode (default)\n" \ - "\t-g\tread a string\n" \ - "\nThe following two options are useful only when verifying checksums:\n" \ - "\t-s\tdon't output anything, status code shows success\n" \ - "\t-w\twarn about improperly formated MD5 checksum lines" -#define md5sum_example_usage \ - "$ md5sum < busybox\n" \ - "6fd11e98b98a58f64ff3398d7b324003\n" \ - "$ md5sum busybox\n" \ - "6fd11e98b98a58f64ff3398d7b324003 busybox\n" \ - "$ md5sum -c -\n" \ - "6fd11e98b98a58f64ff3398d7b324003 busybox\n" \ - "busybox: OK\n" \ - "^D\n" - -#define mkdir_trivial_usage \ - "[OPTION] DIRECTORY..." -#define mkdir_full_usage \ - "Create the DIRECTORY(ies) if they do not already exist\n\n" \ - "Options:\n" \ - "\t-m\tset permission mode (as in chmod), not rwxrwxrwx - umask\n" \ - "\t-p\tno error if existing, make parent directories as needed" -#define mkdir_example_usage \ - "$ mkdir /tmp/foo\n" \ - "$ mkdir /tmp/foo\n" \ - "/tmp/foo: File exists\n" \ - "$ mkdir /tmp/foo/bar/baz\n" \ - "/tmp/foo/bar/baz: No such file or directory\n" \ - "$ mkdir -p /tmp/foo/bar/baz\n" - -#define mkfifo_trivial_usage \ - "[OPTIONS] name" -#define mkfifo_full_usage \ - "Creates a named pipe (identical to 'mknod name p')\n\n" \ - "Options:\n" \ - "\t-m\tcreate the pipe using the specified mode (default a=rw)" - -#define mkfs_minix_trivial_usage \ - "[-c | -l filename] [-nXX] [-iXX] /dev/name [blocks]" -#define mkfs_minix_full_usage \ - "Make a MINIX filesystem.\n\n" \ - "Options:\n" \ - "\t-c\t\tCheck the device for bad blocks\n" \ - "\t-n [14|30]\tSpecify the maximum length of filenames\n" \ - "\t-i INODES\tSpecify the number of inodes for the filesystem\n" \ - "\t-l FILENAME\tRead the bad blocks list from FILENAME\n" \ - "\t-v\t\tMake a Minix version 2 filesystem" - -#define mknod_trivial_usage \ - "[OPTIONS] NAME TYPE MAJOR MINOR" -#define mknod_full_usage \ - "Create a special file (block, character, or pipe).\n\n" \ - "Options:\n" \ - "\t-m\tcreate the special file using the specified mode (default a=rw)\n\n" \ - "TYPEs include:\n" \ - "\tb:\tMake a block (buffered) device.\n" \ - "\tc or u:\tMake a character (un-buffered) device.\n" \ - "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes." -#define mknod_example_usage \ - "$ mknod /dev/fd0 b 2 0 \n" \ - "$ mknod -m 644 /tmp/pipe p\n" - -#define mkswap_trivial_usage \ - "[-c] [-v0|-v1] device [block-count]" -#define mkswap_full_usage \ - "Prepare a disk partition to be used as a swap partition.\n\n" \ - "Options:\n" \ - "\t-c\t\tCheck for read-ability.\n" \ - "\t-v0\t\tMake version 0 swap [max 128 Megs].\n" \ - "\t-v1\t\tMake version 1 swap [big!] (default for kernels >\n\t\t\t2.1.117).\n" \ - "\tblock-count\tNumber of block to use (default is entire partition)." - -#define mktemp_trivial_usage \ - "[-q] TEMPLATE" -#define mktemp_full_usage \ - "Creates a temporary file with its name based on TEMPLATE.\n" \ - "TEMPLATE is any name with six `Xs' (i.e., /tmp/temp.XXXXXX)." -#define mktemp_example_usage \ - "$ mktemp /tmp/temp.XXXXXX\n" \ - "/tmp/temp.mWiLjM\n" \ - "$ ls -la /tmp/temp.mWiLjM\n" \ - "-rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM\n" - -#define modprobe_trivial_usage \ - "[FILE ...]" -#define modprobe_full_usage \ - "Used for hight level module loading and unloading." -#define modprobe_example_usage \ - "$ modprobe cdrom\n" - -#define more_trivial_usage \ - "[FILE ...]" -#define more_full_usage \ - "More is a filter for viewing FILE one screenful at a time." -#define more_example_usage \ - "$ dmesg | more\n" - -#ifdef BB_FEATURE_MOUNT_LOOP - #define USAGE_MOUNT_LOOP(a) a -#else - #define USAGE_MOUNT_LOOP(a) -#endif -#ifdef BB_FEATURE_MTAB_SUPPORT - #define USAGE_MTAB(a) a -#else - #define USAGE_MTAB(a) -#endif -#define mount_trivial_usage \ - "[flags] DEVICE NODE [-o options,more-options]" -#define mount_full_usage \ - "Mount a filesystem\n\n" \ - "Flags:\n" \ - "\t-a:\t\tMount all filesystems in fstab.\n" \ - USAGE_MTAB( \ - "\t-f:\t\t\"Fake\" Add entry to mount table but don't mount it.\n" \ - "\t-n:\t\tDon't write a mount table entry.\n" \ - ) \ - "\t-o option:\tOne of many filesystem options, listed below.\n" \ - "\t-r:\t\tMount the filesystem read-only.\n" \ - "\t-t fs-type:\tSpecify the filesystem type.\n" \ - "\t-w:\t\tMount for reading and writing (default).\n" \ - "\n" \ - "Options for use with the \"-o\" flag:\n" \ - "\tasync/sync:\tWrites are asynchronous / synchronous.\n" \ - "\tatime/noatime:\tEnable / disable updates to inode access times.\n" \ - "\tdev/nodev:\tAllow use of special device files / disallow them.\n" \ - "\texec/noexec:\tAllow use of executable files / disallow them.\n" \ - USAGE_MOUNT_LOOP( \ - "\tloop:\t\tMounts a file via loop device.\n" \ - ) \ - "\tsuid/nosuid:\tAllow set-user-id-root programs / disallow them.\n" \ - "\tremount:\tRe-mount a mounted filesystem, changing its flags.\n" \ - "\tro/rw:\t\tMount for read-only / read-write.\n" \ - "\tbind:\t\tUse the linux 2.4.x \"bind\" feature.\n" \ - "\nThere are EVEN MORE flags that are specific to each filesystem.\n" \ - "You'll have to see the written documentation for those filesystems." -#define mount_example_usage \ - "$ mount\n" \ - "/dev/hda3 on / type minix (rw)\n" \ - "proc on /proc type proc (rw)\n" \ - "devpts on /dev/pts type devpts (rw)\n" \ - "$ mount /dev/fd0 /mnt -t msdos -o ro\n" \ - "$ mount /tmp/diskimage /opt -t ext2 -o loop\n" - -#define mt_trivial_usage \ - "[-f device] opcode value" -#define mt_full_usage \ - "Control magnetic tape drive operation\n" \ - "\nAvailable Opcodes:\n\n" \ - "bsf bsfm bsr bss datacompression drvbuffer eof eom erase\n" \ - "fsf fsfm fsr fss load lock mkpart nop offline ras1 ras2\n" \ - "ras3 reset retension rew rewoffline seek setblk setdensity\n" \ - "setpart tell unload unlock weof wset" - -#define mv_trivial_usage \ - "SOURCE DEST\n" \ - "or: mv SOURCE... DIRECTORY" -#define mv_full_usage \ - "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY." -#define mv_example_usage \ - "$ mv /tmp/foo /bin/bar\n" - -#define nc_trivial_usage \ - "[IP] [port]" -#define nc_full_usage \ - "Netcat opens a pipe to IP:port" -#define nc_example_usage \ - "$ nc foobar.somedomain.com 25\n" \ - "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" \ - "help\n" \ - "214-Commands supported:\n" \ - "214- HELO EHLO MAIL RCPT DATA AUTH\n" \ - "214 NOOP QUIT RSET HELP\n" \ - "quit\n" \ - "221 foobar closing connection\n" - -#define nslookup_trivial_usage \ - "[HOST] [SERVER]" -#define nslookup_full_usage \ - "Queries the nameserver for the IP address of the given HOST\n" \ - "optionally using a specified DNS server" -#define nslookup_example_usage \ - "$ nslookup localhost\n" \ - "Server: default\n" \ - "Address: default\n" \ - "\n" \ - "Name: debian\n" \ - "Address: 127.0.0.1\n" - -#define pidof_trivial_usage \ - "process-name [process-name ...]" -#define pidof_full_usage \ - "Lists the PIDs of all processes with names that match the names on the command line" -#define pidof_example_usage \ - "$ pidof init\n" \ - "1\n" - -#ifndef BB_FEATURE_FANCY_PING -#define ping_trivial_usage "host" -#define ping_full_usage "Send ICMP ECHO_REQUEST packets to network hosts" -#else -#define ping_trivial_usage \ - "[OPTION]... host" -#define ping_full_usage \ - "Send ICMP ECHO_REQUEST packets to network hosts.\n\n" \ - "Options:\n" \ - "\t-c COUNT\tSend only COUNT pings.\n" \ - "\t-s SIZE\t\tSend SIZE data bytes in packets (default=56).\n" \ - "\t-q\t\tQuiet mode, only displays output at start\n" \ - "\t\t\tand when finished." -#endif -#define ping_example_usage \ - "$ ping localhost\n" \ - "PING slag (127.0.0.1): 56 data bytes\n" \ - "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" \ - "\n" \ - "--- debian ping statistics ---\n" \ - "1 packets transmitted, 1 packets received, 0% packet loss\n" \ - "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" - -#define pivot_root_trivial_usage \ - "NEW_ROOT PUT_OLD" -#define pivot_root_full_usage \ - "Move the current root file system to PUT_OLD and make NEW_ROOT\n" \ - "the new root file system." - -#define poweroff_trivial_usage \ - "" -#define poweroff_full_usage \ - "Halt the system and request that the kernel shut off the power." - -#define printf_trivial_usage \ - "FORMAT [ARGUMENT...]" -#define printf_full_usage \ - "Formats and prints ARGUMENT(s) according to FORMAT,\n" \ - "Where FORMAT controls the output exactly as in C printf." -#define printf_example_usage \ - "$ printf "Val=%d\\n" 5\n" \ - "Val=5\n" - -#define ps_trivial_usage \ - "" -#define ps_full_usage \ - "Report process status\n" \ - "\nThis version of ps accepts no options." -#define ps_example_usage \ - "$ ps\n" \ - " PID Uid Gid State Command\n" \ - " 1 root root S init\n" \ - " 2 root root S [kflushd]\n" \ - " 3 root root S [kupdate]\n" \ - " 4 root root S [kpiod]\n" \ - " 5 root root S [kswapd]\n" \ - " 742 andersen andersen S [bash]\n" \ - " 743 andersen andersen S -bash\n" \ - " 745 root root S [getty]\n" \ - " 2990 andersen andersen R ps\n" - -#define pwd_trivial_usage \ - "" -#define pwd_full_usage \ - "Print the full filename of the current working directory." -#define pwd_example_usage \ - "$ pwd\n" \ - "/root\n" - -#define rdate_trivial_usage \ - "[OPTION] HOST" -#define rdate_full_usage \ - "Get and possibly set the system date and time from a remote HOST.\n\n" \ - "Options:\n" \ - "\t-s\tSet the system date and time (default).\n" \ - "\t-p\tPrint the date and time." - -#define readlink_trivial_usage \ - "" -#define readlink_full_usage \ - "Read a symbolic link." - -#define reboot_trivial_usage \ - "" -#define reboot_full_usage \ - "Reboot the system." - -#define renice_trivial_usage \ - "priority pid [pid ...]" -#define renice_full_usage \ - "Changes priority of running processes. Allowed priorities range\n" \ - "from 20 (the process runs only when nothing else is running) to 0\n" \ - "(default priority) to -20 (almost nothing else ever gets to run)." - -#define reset_trivial_usage \ - "" -#define reset_full_usage \ - "Resets the screen." - -#define rm_trivial_usage \ - "[OPTION]... FILE..." -#define rm_full_usage \ - "Remove (unlink) the FILE(s). You may use '--' to\n" \ - "indicate that all following arguments are non-options.\n\n" \ - "Options:\n" \ - "\t-i\t\talways prompt before removing each destination" \ - "\t-f\t\tremove existing destinations, never prompt\n" \ - "\t-r or -R\tremove the contents of directories recursively" -#define rm_example_usage \ - "$ rm -rf /tmp/foo\n" - -#define rmdir_trivial_usage \ - "[OPTION]... DIRECTORY..." -#define rmdir_full_usage \ - "Remove the DIRECTORY(ies), if they are empty." -#define rmdir_example_usage \ - "# rmdir /tmp/foo\n" - -#define rmmod_trivial_usage \ - "[OPTION]... [MODULE]..." -#define rmmod_full_usage \ - "Unloads the specified kernel modules from the kernel.\n\n" \ - "Options:\n" \ - "\t-a\tTry to remove all unused kernel modules." -#define rmmod_example_usage \ - "$ rmmod tulip\n" - -#define route_trivial_usage \ - "[{add|del|flush}]" -#define route_full_usage \ - "Edit the kernel's routing tables" - -#define rpm2cpio_trivial_usage \ - "package.rpm" -#define rpm2cpio_full_usage \ - "Outputs a cpio archive of the rpm file." - -#define sed_trivial_usage \ - "[-nef] pattern [files...]" -#define sed_full_usage \ - "Options:\n" \ - "\t-n\t\tsuppress automatic printing of pattern space\n" \ - "\t-e script\tadd the script to the commands to be executed\n" \ - "\t-f scriptfile\tadd the contents of script-file to the commands to be executed\n" \ - "\n" \ - "If no -e or -f is given, the first non-option argument is taken as the\n" \ - "sed script to interpret. All remaining arguments are names of input\n" \ - "files; if no input files are specified, then the standard input is read." -#define sed_example_usage \ - "$ echo "foo" | sed -e 's/f[a-zA-Z]o/bar/g'\n" \ - "bar\n" - -#define setkeycodes_trivial_usage \ - "SCANCODE KEYCODE ..." -#define setkeycodes_full_usage \ - "Set entries into the kernel's scancode-to-keycode map,\n" \ - "allowing unusual keyboards to generate usable keycodes.\n\n" \ - "SCANCODE may be either xx or e0xx (hexadecimal),\n" \ - "and KEYCODE is given in decimal" -#define setkeycodes_example_usage \ - "$ setkeycodes e030 127\n" - -#define lash_trivial_usage \ - "[FILE]...\n" \ - "or: sh -c command [args]..." -#define lash_full_usage \ - "lash: The BusyBox LAme SHell (command interpreter)" -#define lash_notes_usage \ -"This command does not yet have proper documentation.\n" \ -"\n" \ -"Use lash just as you would use any other shell. It properly handles pipes,\n" \ -"redirects, job control, can be used as the shell for scripts, and has a\n" \ -"sufficient set of builtins to do what is needed. It does not (yet) support\n" \ -"Bourne Shell syntax. If you need things like "if-then-else", "while", and such\n" \ -"use ash or bash. If you just need a very simple and extremely small shell,\n" \ -"this will do the job." - -#define sleep_trivial_usage \ - "N" -#define sleep_full_usage \ - "Pause for N seconds." -#define sleep_example_usage \ - "$ sleep 2\n" \ - "[2 second delay results]\n" - - -#ifdef BB_FEATURE_SORT_UNIQUE - #define USAGE_SORT_UNIQUE(a) a -#else - #define USAGE_SORT_UNIQUE(a) -#endif -#ifdef BB_FEATURE_SORT_REVERSE - #define USAGE_SORT_REVERSE(a) a -#else - #define USAGE_SORT_REVERSE(a) -#endif -#define sort_trivial_usage \ - "[-n" USAGE_SORT_REVERSE("r") USAGE_SORT_UNIQUE("u") "] [FILE]..." -#define sort_full_usage \ - "Sorts lines of text in the specified files\n\n"\ - "Options:\n" \ - USAGE_SORT_UNIQUE("\t-u\tsuppress duplicate lines\n") \ - USAGE_SORT_REVERSE("\t-r\tsort in reverse order\n") \ - "\t-n\tsort numerics" -#define sort_example_usage \ - "$ echo -e \"e\\nf\\nb\\nd\\nc\\na\" | sort\n" \ - "a\n" \ - "b\n" \ - "c\n" \ - "d\n" \ - "e\n" \ - "f\n" - -#define stty_trivial_usage \ - "[-a|g] [-F DEVICE] [SETTING]..." -#define stty_full_usage \ - "Without arguments, prints baud rate, line discipline," \ - "\nand deviations from stty sane." \ - "\n\nOptions:" \ - "\n\t-F DEVICE\topen device instead of stdin" \ - "\n\t-a\t\tprint all current settings in human-readable form" \ - "\n\t-g\t\tprint in stty-readable form" \ - "\n\t[SETTING]\tsee manpage" - -#define swapoff_trivial_usage \ - "[OPTION] [DEVICE]" -#define swapoff_full_usage \ - "Stop swapping virtual memory pages on DEVICE.\n\n" \ - "Options:\n" \ - "\t-a\tStop swapping on all swap devices" - -#define swapon_trivial_usage \ - "[OPTION] [DEVICE]" -#define swapon_full_usage \ - "Start swapping virtual memory pages on DEVICE.\n\n" \ - "Options:\n" \ - "\t-a\tStart swapping on all swap devices" - -#define sync_trivial_usage \ - "" -#define sync_full_usage \ - "Write all buffered filesystem blocks to disk." - - -#ifdef BB_FEATURE_REMOTE_LOG - #define USAGE_REMOTE_LOG(a) a -#else - #define USAGE_REMOTE_LOG(a) -#endif -#define syslogd_trivial_usage \ - "[OPTION]..." -#define syslogd_full_usage \ - "Linux system and kernel logging utility.\n" \ - "Note that this version of syslogd ignores /etc/syslog.conf.\n\n" \ - "Options:\n" \ - "\t-m NUM\t\tInterval between MARK lines (default=20min, 0=off)\n" \ - "\t-n\t\tRun as a foreground process\n" \ - "\t-O FILE\t\tUse an alternate log file (default=/var/log/messages)" \ - USAGE_REMOTE_LOG( \ - "\n\t-R HOST[:PORT]\tLog to IP or hostname on PORT (default PORT=514/UDP)\n" \ - "\t-L\t\tLog locally and via network logging (default is network only)") -#define syslogd_example_usage \ - "$ syslogd -R masterlog:514\n" \ - "$ syslogd -R 192.168.1.1:601\n" - - -#ifndef BB_FEATURE_FANCY_TAIL - #define USAGE_UNSIMPLE_TAIL(a) -#else - #define USAGE_UNSIMPLE_TAIL(a) a -#endif -#define tail_trivial_usage \ - "[OPTION]... [FILE]..." -#define tail_full_usage \ - "Print last 10 lines of each FILE to standard output.\n" \ - "With more than one FILE, precede each with a header giving the\n" \ - "file name. With no FILE, or when FILE is -, read standard input.\n\n" \ - "Options:\n" \ - USAGE_UNSIMPLE_TAIL("\t-c N[kbm]\toutput the last N bytes\n") \ - "\t-n N[kbm]\tprint last N lines instead of last 10\n" \ - "\t-f\t\toutput data as the file grows" \ - USAGE_UNSIMPLE_TAIL( "\n\t-q\t\tnever output headers giving file names\n" \ - "\t-s SEC\t\twait SEC seconds between reads with -f\n" \ - "\t-v\t\talways output headers giving file names\n\n" \ - "If the first character of N (bytes or lines) is a '+', output begins with \n" \ - "the Nth item from the start of each file, otherwise, print the last N items\n" \ - "in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2)." ) -#define tail_example_usage \ - "$ tail -n 1 /etc/resolv.conf\n" \ - "nameserver 10.0.0.1\n" - -#ifdef BB_FEATURE_TAR_CREATE - #define USAGE_TAR_CREATE(a) a -#else - #define USAGE_TAR_CREATE(a) -#endif -#ifdef BB_FEATURE_TAR_EXCLUDE - #define USAGE_TAR_EXCLUDE(a) a -#else - #define USAGE_TAR_EXCLUDE(a) -#endif -#define tar_trivial_usage \ - "-[" USAGE_TAR_CREATE("c") "xtvO] " \ - USAGE_TAR_EXCLUDE("[--exclude FILE] [-X FILE]") \ - "[-f TARFILE] [-C DIR] [FILE(s)] ..." -#define tar_full_usage \ - "Create, extract, or list files from a tar file.\n\n" \ - "Options:\n" \ - USAGE_TAR_CREATE("\tc\t\tcreate\n") \ - "\tx\t\textract\n" \ - "\tt\t\tlist\n" \ - "\nFile selection:\n" \ - "\tf\t\tname of TARFILE or \"-\" for stdin\n" \ - "\tO\t\textract to stdout\n" \ - USAGE_TAR_EXCLUDE( \ - "\texclude\t\tfile to exclude\n" \ - "\tX\t\tfile with names to exclude\n" \ - ) \ - "\tC\t\tchange to directory DIR before operation\n" \ - "\tv\t\tverbosely list files processed" -#define tar_example_usage \ - "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" \ - "$ tar -cf /tmp/tarball.tar /usr/local\n" - -#define tee_trivial_usage \ - "[OPTION]... [FILE]..." -#define tee_full_usage \ - "Copy standard input to each FILE, and also to standard output.\n\n" \ - "Options:\n" \ - "\t-a\tappend to the given FILEs, do not overwrite" -#define tee_example_usage \ - "$ echo "Hello" | tee /tmp/foo\n" \ - "$ cat /tmp/foo\n" \ - "Hello\n" - -#define telnet_trivial_usage \ - "HOST [PORT]" -#define telnet_full_usage \ - "Telnet is used to establish interactive communication with another\n"\ - "computer over a network using the TELNET protocol." - -#define test_trivial_usage \ - "EXPRESSION\n or [ EXPRESSION ]" -#define test_full_usage \ - "Checks file types and compares values returning an exit\n" \ - "code determined by the value of EXPRESSION." -#define test_example_usage \ - "$ test 1 -eq 2\n" \ - "$ echo $?\n" \ - "1\n" \ - "$ test 1 -eq 1\n" \ - "$ echo $? \n" \ - "0\n" \ - "$ [ -d /etc ]\n" \ - "$ echo $?\n" \ - "0\n" \ - "$ [ -d /junk ]\n" \ - "$ echo $?\n" \ - "1\n" - -#ifdef BB_FEATURE_TFTP_GET - #define USAGE_TFTP_GET(a) a -#else - #define USAGE_TFTP_GET(a) -#endif -#ifdef BB_FEATURE_TFTP_PUT - #define USAGE_TFTP_PUT(a) a -#else - #define USAGE_TFTP_PUT(a) -#endif - -#define tftp_trivial_usage \ - "[OPTION]... HOST [PORT]" -#define tftp_full_usage \ - "Transfers a file from/to a tftp server using \"octet\" mode.\n\n" \ - "Options:\n" \ - "\t-b SIZE\tTransfer blocks of SIZE octets.\n" \ - USAGE_TFTP_GET( \ - "\t-g\tGet file.\n" \ - ) \ - "\t-l FILE\tTransfer local FILE.\n" \ - USAGE_TFTP_PUT( \ - "\t-p\tPut file.\n" \ - ) \ - "\t-r FILE\tTransfer remote FILE.\n" - -#define touch_trivial_usage \ - "[-c] FILE [FILE ...]" -#define touch_full_usage \ - "Update the last-modified date on the given FILE[s].\n\n" \ - "Options:\n" \ - "\t-c\tDo not create any files" -#define touch_example_usage \ - "$ ls -l /tmp/foo\n" \ - "/bin/ls: /tmp/foo: No such file or directory\n" \ - "$ touch /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo\n" - -#define tr_trivial_usage \ - "[-cds] STRING1 [STRING2]" -#define tr_full_usage \ - "Translate, squeeze, and/or delete characters from\n" \ - "standard input, writing to standard output.\n\n" \ - "Options:\n" \ - "\t-c\ttake complement of STRING1\n" \ - "\t-d\tdelete input characters coded STRING1\n" \ - "\t-s\tsqueeze multiple output characters of STRING2 into one character" -#define tr_example_usage \ - "$ echo "gdkkn vnqkc" | tr [a-y] [b-z]\n" \ - "hello world\n" - -#define traceroute_trivial_usage \ - "[-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\ - [-s src_addr] [-t tos] [-w wait] host [data size]" -#define traceroute_full_usage \ - "trace the route ip packets follow going to \"host\"\n" \ - "Options:\n" \ - "\t-d\tset SO_DEBUG options to socket\n" \ - "\t-n\tPrint hop addresses numerically rather than symbolically\n" \ - "\t-r\tBypass the normal routing tables and send directly to a host\n" \ - "\t-v\tVerbose output\n" \ - "\t-m max_ttl\tSet the max time-to-live (max number of hops)\n" \ - "\t-p port#\tSet the base UDP port number used in probes\n" \ - "\t\t(default is 33434)\n" \ - "\t-q nqueries\tSet the number of probes per ``ttl'' to nqueries\n" \ - "\t\t(default is 3)\n" \ - "\t-s src_addr\tUse the following IP address as the source address\n" \ - "\t-t tos\tSet the type-of-service in probe packets to the following value\n" \ - "\t\t(default 0)\n" \ - "\t-w wait\tSet the time (in seconds) to wait for a response to a probe\n" \ - "\t\t(default 3 sec.)." - - -#define true_trivial_usage \ - "" -#define true_full_usage \ - "Return an exit code of TRUE (0)." -#define true_example_usage \ - "$ true\n" \ - "$ echo $?\n" \ - "0\n" - -#define tty_trivial_usage \ - "" -#define tty_full_usage \ - "Print the file name of the terminal connected to standard input.\n\n"\ - "Options:\n" \ - "\t-s\tprint nothing, only return an exit status" -#define tty_example_usage \ - "$ tty\n" \ - "/dev/tty2\n" - -#ifdef BB_FEATURE_MOUNT_FORCE - #define USAGE_MOUNT_FORCE(a) a -#else - #define USAGE_MOUNT_FORCE(a) -#endif -#define umount_trivial_usage \ - "[flags] FILESYSTEM|DIRECTORY" -#define umount_full_usage \ - "Unmount file systems\n" \ - "\nFlags:\n" "\t-a\tUnmount all file systems" \ - USAGE_MTAB(" in /etc/mtab\n\t-n\tDon't erase /etc/mtab entries") \ - "\n\t-r\tTry to remount devices as read-only if mount is busy" \ - USAGE_MOUNT_FORCE("\n\t-f\tForce umount (i.e., unreachable NFS server)") \ - USAGE_MOUNT_LOOP("\n\t-l\tDo not free loop device (if a loop device has been used)") -#define umount_example_usage \ - "$ umount /dev/hdc1 \n" - -#define uname_trivial_usage \ - "[OPTION]..." -#define uname_full_usage \ - "Print certain system information. With no OPTION, same as -s.\n\n" \ - "Options:\n" \ - "\t-a\tprint all information\n" \ - "\t-m\tthe machine (hardware) type\n" \ - "\t-n\tprint the machine's network node hostname\n" \ - "\t-r\tprint the operating system release\n" \ - "\t-s\tprint the operating system name\n" \ - "\t-p\tprint the host processor type\n" \ - "\t-v\tprint the operating system version" -#define uname_example_usage \ - "$ uname -a\n" \ - "Linux debian 2.2.15pre13 #5 Tue Mar 14 16:03:50 MST 2000 i686 unknown\n" - -#define uniq_trivial_usage \ - "[OPTION]... [INPUT [OUTPUT]]" -#define uniq_full_usage \ - "Discard all but one of successive identical lines from INPUT\n" \ - "(or standard input), writing to OUTPUT (or standard output).\n\n" \ - "Options:\n" \ - "\t-c\tprefix lines by the number of occurrences\n" \ - "\t-d\tonly print duplicate lines\n" \ - "\t-u\tonly print unique lines" -#define uniq_example_usage \ - "$ echo -e \"a\\na\\nb\\nc\\nc\\na\" | sort | uniq\n" \ - "a\n" \ - "b\n" \ - "c\n" - -#define unix2dos_trivial_usage \ - "[option] [FILE]" -#define unix2dos_full_usage \ - "Converts FILE from unix format to dos format. When no option\n" \ - "is given, the input is converted to the opposite output format.\n" \ - "When no file is given, uses stdin for input and stdout for output.\n" \ - "Options:\n" \ - "\t-u\toutput will be in UNIX format\n" \ - "\t-d\toutput will be in DOS format" - -#define update_trivial_usage \ - "[options]" -#define update_full_usage \ - "Periodically flushes filesystem buffers.\n\n" \ - "Options:\n" \ - "\t-S\tforce use of sync(2) instead of flushing\n" \ - "\t-s SECS\tcall sync this often (default 30)\n" \ - "\t-f SECS\tflush some buffers this often (default 5)" - -#define uptime_trivial_usage \ - "" -#define uptime_full_usage \ - "Display the time since the last boot." -#define uptime_example_usage \ - "$ uptime\n" \ - " 1:55pm up 2:30, load average: 0.09, 0.04, 0.00\n" - -#define usleep_trivial_usage \ - "N" -#define usleep_full_usage \ - "Pause for N microseconds." -#define usleep_example_usage \ - "$ usleep 1000000\n" \ - "[pauses for 1 second]\n" - -#define uudecode_trivial_usage \ - "[FILE]..." -#define uudecode_full_usage \ - "Uudecode a file that is uuencoded.\n\n" \ - "Options:\n" \ - "\t-o FILE\tdirect output to FILE" -#define uudecode_example_usage \ - "$ uudecode -o busybox busybox.uu\n" \ - "$ ls -l busybox\n" \ - "-rwxr-xr-x 1 ams ams 245264 Jun 7 21:35 busybox\n" - -#define uuencode_trivial_usage \ - "[OPTION] [INFILE] REMOTEFILE" -#define uuencode_full_usage \ - "Uuencode a file.\n\n" \ - "Options:\n" \ - "\t-m\tuse base64 encoding per RFC1521" -#define uuencode_example_usage \ - "$ uuencode busybox busybox\n" \ - "begin 755 busybox\n" \ - "\n" \ - "$ uudecode busybox busybox > busybox.uu\n" \ - "$\n" - -#define vi_trivial_usage \ - "[OPTION] [FILE]..." -#define vi_full_usage \ - "edit FILE.\n\n" \ - "Options:\n" \ - "\t-R\tRead-only- do not write to the file." - -#define watchdog_trivial_usage \ - "DEV" -#define watchdog_full_usage \ - "Periodically write to watchdog device DEV" - -#define wc_trivial_usage \ - "[OPTION]... [FILE]..." -#define wc_full_usage \ - "Print line, word, and byte counts for each FILE, and a total line if\n" \ - "more than one FILE is specified. With no FILE, read standard input.\n\n" \ - "Options:\n" \ - "\t-c\tprint the byte counts\n" \ - "\t-l\tprint the newline counts\n" \ - "\t-L\tprint the length of the longest line\n" \ - "\t-w\tprint the word counts" -#define wc_example_usage \ - "$ wc /etc/passwd\n" \ - " 31 46 1365 /etc/passwd\n" - -#define wget_trivial_usage \ - "[-c|--continue] [-q|--quiet] [-O|--output-document file]\n\t[--header 'header: value'] [-P DIR] url" -#define wget_full_usage \ - "wget retrieves files via HTTP or FTP\n\n" \ - "Options:\n" \ - "\t-c\tcontinue retrieval of aborted transfers\n" \ - "\t-q\tquiet mode - do not print\n" \ - "\t-P\tSet directory prefix to DIR\n" \ - "\t-O\tsave to filename ('-' for stdout)" - -#define which_trivial_usage \ - "[COMMAND ...]" -#define which_full_usage \ - "Locates a COMMAND." -#define which_example_usage \ - "$ which login\n" \ - "/bin/login\n" - -#define whoami_trivial_usage \ - "" -#define whoami_full_usage \ - "Prints the user name associated with the current effective user id." - -#define xargs_trivial_usage \ - "[COMMAND] [ARGS...]" -#define xargs_full_usage \ - "Executes COMMAND on every item given by standard input." -#define xargs_example_usage \ - "$ ls | xargs gzip\n" \ - "$ find . -name '*.c' -print | xargs rm\n" - -#define yes_trivial_usage \ - "[OPTION]... [STRING]..." -#define yes_full_usage \ - "Repeatedly outputs a line with all specified STRING(s), or 'y'." - -#define zcat_trivial_usage \ - "FILE" -#define zcat_full_usage \ - "Uncompress to stdout." diff --git a/busybox/ar.c b/busybox/ar.c deleted file mode 100644 index 7f3396c8c..000000000 --- a/busybox/ar.c +++ /dev/null @@ -1,89 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini ar implementation for busybox - * - * Copyright (C) 2000 by Glenn McGrath - * Written by Glenn McGrath 1 June 2000 - * - * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar. - * - * 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 "busybox.h" - -extern int ar_main(int argc, char **argv) -{ - FILE *src_stream = NULL; - char **extract_names = NULL; - char ar_magic[8]; - int extract_function = extract_unconditional; - int opt; - int num_of_entries = 0; - extern off_t archive_offset; - - while ((opt = getopt(argc, argv, "ovtpx")) != -1) { - switch (opt) { - case 'o': - extract_function |= extract_preserve_date; - break; - case 'v': - extract_function |= extract_verbose_list; - break; - case 't': - extract_function |= extract_list; - break; - case 'p': - extract_function |= extract_to_stdout; - break; - case 'x': - extract_function |= extract_all_to_fs; - break; - default: - show_usage(); - } - } - - /* check the src filename was specified */ - if (optind == argc) { - show_usage(); - } - - src_stream = xfopen(argv[optind++], "r"); - - /* check ar magic */ - fread(ar_magic, 1, 8, src_stream); - archive_offset = 8; - if (strncmp(ar_magic,"!",7) != 0) { - error_msg_and_die("invalid magic"); - } - - /* Create a list of files to extract */ - while (optind < argc) { - extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2)); - extract_names[num_of_entries] = xstrdup(argv[optind]); - num_of_entries++; - extract_names[num_of_entries] = NULL; - optind++; - } - - unarchive(src_stream, stdout, &get_header_ar, extract_function, "./", extract_names); - return EXIT_SUCCESS; -} diff --git a/busybox/archival/ar.c b/busybox/archival/ar.c deleted file mode 100644 index 7f3396c8c..000000000 --- a/busybox/archival/ar.c +++ /dev/null @@ -1,89 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini ar implementation for busybox - * - * Copyright (C) 2000 by Glenn McGrath - * Written by Glenn McGrath 1 June 2000 - * - * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar. - * - * 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 "busybox.h" - -extern int ar_main(int argc, char **argv) -{ - FILE *src_stream = NULL; - char **extract_names = NULL; - char ar_magic[8]; - int extract_function = extract_unconditional; - int opt; - int num_of_entries = 0; - extern off_t archive_offset; - - while ((opt = getopt(argc, argv, "ovtpx")) != -1) { - switch (opt) { - case 'o': - extract_function |= extract_preserve_date; - break; - case 'v': - extract_function |= extract_verbose_list; - break; - case 't': - extract_function |= extract_list; - break; - case 'p': - extract_function |= extract_to_stdout; - break; - case 'x': - extract_function |= extract_all_to_fs; - break; - default: - show_usage(); - } - } - - /* check the src filename was specified */ - if (optind == argc) { - show_usage(); - } - - src_stream = xfopen(argv[optind++], "r"); - - /* check ar magic */ - fread(ar_magic, 1, 8, src_stream); - archive_offset = 8; - if (strncmp(ar_magic,"!",7) != 0) { - error_msg_and_die("invalid magic"); - } - - /* Create a list of files to extract */ - while (optind < argc) { - extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2)); - extract_names[num_of_entries] = xstrdup(argv[optind]); - num_of_entries++; - extract_names[num_of_entries] = NULL; - optind++; - } - - unarchive(src_stream, stdout, &get_header_ar, extract_function, "./", extract_names); - return EXIT_SUCCESS; -} diff --git a/busybox/archival/cpio.c b/busybox/archival/cpio.c deleted file mode 100644 index 7f68715eb..000000000 --- a/busybox/archival/cpio.c +++ /dev/null @@ -1,95 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini cpio implementation for busybox - * - * Copyright (C) 2001 by 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 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 - * - * Limitations: - * Doesn't check CRC's - * Only supports new ASCII and CRC formats - * - */ -#include -#include -#include -#include -#include -#include "busybox.h" - -extern int cpio_main(int argc, char **argv) -{ - FILE *src_stream = stdin; - char **extract_names = NULL; - int extract_function = 0; - int num_of_entries = 0; - int opt = 0; - mode_t oldmask = 0; - - while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) { - switch (opt) { - case 'i': // extract - extract_function |= extract_all_to_fs; - break; - case 'd': // create _leading_ directories - extract_function |= extract_create_leading_dirs; - oldmask = umask(077); /* Make make_directory act like GNU cpio */ - break; - case 'm': // preserve modification time - extract_function |= extract_preserve_date; - break; - case 'v': // verbosly list files - extract_function |= extract_verbose_list; - break; - case 'u': // unconditional - extract_function |= extract_unconditional; - break; - case 't': // list files - extract_function |= extract_list; - break; - case 'F': - src_stream = xfopen(optarg, "r"); - break; - default: - show_usage(); - } - } - - if ((extract_function & extract_all_to_fs) && (extract_function & extract_list)) { - extract_function ^= extract_all_to_fs; /* If specify t, don't extract*/ - } - - if ((extract_function & extract_all_to_fs) && (extract_function & extract_verbose_list)) { - /* The meaning of v changes on extract */ - extract_function ^= extract_verbose_list; - extract_function |= extract_list; - } - - while (optind < argc) { - extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2)); - extract_names[num_of_entries] = xstrdup(argv[optind]); - num_of_entries++; - extract_names[num_of_entries] = NULL; - optind++; - } - - unarchive(src_stream, stdout, &get_header_cpio, extract_function, "./", extract_names); - if (oldmask) { - umask(oldmask); /* Restore umask if we changed it */ - } - return EXIT_SUCCESS; -} - diff --git a/busybox/archival/dpkg.c b/busybox/archival/dpkg.c deleted file mode 100644 index 48c392894..000000000 --- a/busybox/archival/dpkg.c +++ /dev/null @@ -1,1445 +0,0 @@ -/* - * Mini dpkg implementation for busybox. - * This is not meant as a replacemnt for dpkg - * - * Copyright (C) 2001 by Glenn McGrath - * - * Started life as a busybox implementation of udpkg - * - * 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. - */ - -/* - * Known difference between busybox dpkg and the official dpkg that i dont - * consider important, its worth keeping a note of differences anyway, just to - * make it easier to maintain. - * - The first value for the Confflile: field isnt placed on a new line. - * - The .control file is extracted and kept in the info dir. - * - When installing a package the Status: field is placed at the end of the - * section, rather than just after the Package: field. - * - Packages with previously unknown status are inserted at the begining of - * the status file - * - * Bugs that need to be fixed - * - (unknown, please let me know when you find any) - * - */ - -#include -#include -#include -#include -#include "busybox.h" - -/* NOTE: If you vary HASH_PRIME sizes be aware, - * 1) Tweaking these will have a big effect on how much memory this program uses. - * 2) For computational efficiency these hash tables should be at least 20% - * larger than the maximum number of elements stored in it. - * 3) All _HASH_PRIME's must be a prime number or chaos is assured, if your looking - * for a prime, try http://www.utm.edu/research/primes/lists/small/10000.txt - * 4) If you go bigger than 15 bits you may get into trouble (untested) as its - * sometimes cast to an unsigned int, if you go to 16 bit you will overlap - * int's and chaos is assured, 16381 is the max prime for 14 bit field - */ - -/* NAME_HASH_PRIME, Stores package names and versions, - * I estimate it should be at least 50% bigger than PACKAGE_HASH_PRIME, - * as there a lot of duplicate version numbers */ -#define NAME_HASH_PRIME 16381 -char *name_hashtable[NAME_HASH_PRIME + 1]; - -/* PACKAGE_HASH_PRIME, Maximum number of unique packages, - * It must not be smaller than STATUS_HASH_PRIME, - * Currently only packages from status_hashtable are stored in here, but in - * future this may be used to store packages not only from a status file, - * but an available_hashtable, and even multiple packages files. - * Package can be stored more than once if they have different versions. - * e.g. The same package may have different versions in the status file - * and available file */ -#define PACKAGE_HASH_PRIME 10007 -typedef struct edge_s { - unsigned int operator:3; - unsigned int type:4; - unsigned int name:14; - unsigned int version:14; -} edge_t; - -typedef struct common_node_s { - unsigned int name:14; - unsigned int version:14; - unsigned int num_of_edges:14; - edge_t **edge; -} common_node_t; -common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1]; - -/* Currently it doesnt store packages that have state-status of not-installed - * So it only really has to be the size of the maximum number of packages - * likely to be installed at any one time, so there is a bit of leaway here */ -#define STATUS_HASH_PRIME 8191 -typedef struct status_node_s { - unsigned int package:14; /* has to fit PACKAGE_HASH_PRIME */ - unsigned int status:14; /* has to fit STATUS_HASH_PRIME */ -} status_node_t; -status_node_t *status_hashtable[STATUS_HASH_PRIME + 1]; - -/* Even numbers are for 'extras', like ored dependecies or null */ -enum edge_type_e { - EDGE_NULL = 0, - EDGE_PRE_DEPENDS = 1, - EDGE_OR_PRE_DEPENDS = 2, - EDGE_DEPENDS = 3, - EDGE_OR_DEPENDS = 4, - EDGE_REPLACES = 5, - EDGE_PROVIDES = 7, - EDGE_CONFLICTS = 9, - EDGE_SUGGESTS = 11, - EDGE_RECOMMENDS = 13, - EDGE_ENHANCES = 15 -}; -enum operator_e { - VER_NULL = 0, - VER_EQUAL = 1, - VER_LESS = 2, - VER_LESS_EQUAL = 3, - VER_MORE = 4, - VER_MORE_EQUAL = 5, - VER_ANY = 6 -}; - -enum dpkg_opt_e { - dpkg_opt_purge = 1, - dpkg_opt_remove = 2, - dpkg_opt_unpack = 4, - dpkg_opt_configure = 8, - dpkg_opt_install = 16, - dpkg_opt_package_name = 32, - dpkg_opt_filename = 64, - dpkg_opt_list_installed = 128, - dpkg_opt_force_ignore_depends = 256 -}; - -typedef struct deb_file_s { - char *control_file; - char *filename; - unsigned int package:14; -} deb_file_t; - - -void make_hash(const char *key, unsigned int *start, unsigned int *decrement, const int hash_prime) -{ - unsigned long int hash_num = key[0]; - int len = strlen(key); - int i; - - /* Maybe i should have uses a "proper" hashing algorithm here instead - * of making one up myself, seems to be working ok though. */ - for(i = 1; i < len; i++) { - /* shifts the ascii based value and adds it to previous value - * shift amount is mod 24 because long int is 32 bit and data - * to be shifted is 8, dont want to shift data to where it has - * no effect*/ - hash_num += ((key[i] + key[i-1]) << ((key[i] * i) % 24)); - } - *start = (unsigned int) hash_num % hash_prime; - *decrement = (unsigned int) 1 + (hash_num % (hash_prime - 1)); -} - -/* this adds the key to the hash table */ -int search_name_hashtable(const char *key) -{ - unsigned int probe_address = 0; - unsigned int probe_decrement = 0; -// char *temp; - - make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME); - while(name_hashtable[probe_address] != NULL) { - if (strcmp(name_hashtable[probe_address], key) == 0) { - return(probe_address); - } else { - probe_address -= probe_decrement; - if ((int)probe_address < 0) { - probe_address += NAME_HASH_PRIME; - } - } - } - name_hashtable[probe_address] = xstrdup(key); - return(probe_address); -} - -/* this DOESNT add the key to the hashtable - * TODO make it consistent with search_name_hashtable - */ -unsigned int search_status_hashtable(const char *key) -{ - unsigned int probe_address = 0; - unsigned int probe_decrement = 0; - - make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME); - while(status_hashtable[probe_address] != NULL) { - if (strcmp(key, name_hashtable[package_hashtable[status_hashtable[probe_address]->package]->name]) == 0) { - break; - } else { - probe_address -= probe_decrement; - if ((int)probe_address < 0) { - probe_address += STATUS_HASH_PRIME; - } - } - } - return(probe_address); -} - -/* Need to rethink version comparison, maybe the official dpkg has something i can use ? */ -int version_compare_part(const char *version1, const char *version2) -{ - int upstream_len1 = 0; - int upstream_len2 = 0; - char *name1_char; - char *name2_char; - int len1 = 0; - int len2 = 0; - int tmp_int; - int ver_num1; - int ver_num2; - int ret; - - if (version1 == NULL) { - version1 = xstrdup(""); - } - if (version2 != NULL) { - version2 = xstrdup(""); - } - upstream_len1 = strlen(version1); - upstream_len2 = strlen(version2); - - while ((len1 < upstream_len1) || (len2 < upstream_len2)) { - /* Compare non-digit section */ - tmp_int = strcspn(&version1[len1], "0123456789"); - name1_char = xstrndup(&version1[len1], tmp_int); - len1 += tmp_int; - tmp_int = strcspn(&version2[len2], "0123456789"); - name2_char = xstrndup(&version2[len2], tmp_int); - len2 += tmp_int; - tmp_int = strcmp(name1_char, name2_char); - free(name1_char); - free(name2_char); - if (tmp_int != 0) { - ret = tmp_int; - goto cleanup_version_compare_part; - } - - /* Compare digits */ - tmp_int = strspn(&version1[len1], "0123456789"); - name1_char = xstrndup(&version1[len1], tmp_int); - len1 += tmp_int; - tmp_int = strspn(&version2[len2], "0123456789"); - name2_char = xstrndup(&version2[len2], tmp_int); - len2 += tmp_int; - ver_num1 = atoi(name1_char); - ver_num2 = atoi(name2_char); - free(name1_char); - free(name2_char); - if (ver_num1 < ver_num2) { - ret = -1; - goto cleanup_version_compare_part; - } - else if (ver_num1 > ver_num2) { - ret = 1; - goto cleanup_version_compare_part; - } - } - ret = 0; -cleanup_version_compare_part: - return(ret); -} - -/* if ver1 < ver2 return -1, - * if ver1 = ver2 return 0, - * if ver1 > ver2 return 1, - */ -int version_compare(const unsigned int ver1, const unsigned int ver2) -{ - char *ch_ver1 = name_hashtable[ver1]; - char *ch_ver2 = name_hashtable[ver2]; - - char epoch1, epoch2; - char *deb_ver1, *deb_ver2; - char *ver1_ptr, *ver2_ptr; - char *upstream_ver1; - char *upstream_ver2; - int result; - - /* Compare epoch */ - if (ch_ver1[1] == ':') { - epoch1 = ch_ver1[0]; - ver1_ptr = strchr(ch_ver1, ':') + 1; - } else { - epoch1 = '0'; - ver1_ptr = ch_ver1; - } - if (ch_ver2[1] == ':') { - epoch2 = ch_ver2[0]; - ver2_ptr = strchr(ch_ver2, ':') + 1; - } else { - epoch2 = '0'; - ver2_ptr = ch_ver2; - } - if (epoch1 < epoch2) { - return(-1); - } - else if (epoch1 > epoch2) { - return(1); - } - - /* Compare upstream version */ - upstream_ver1 = xstrdup(ver1_ptr); - upstream_ver2 = xstrdup(ver2_ptr); - - /* Chop off debian version, and store for later use */ - deb_ver1 = strrchr(upstream_ver1, '-'); - deb_ver2 = strrchr(upstream_ver2, '-'); - if (deb_ver1) { - deb_ver1[0] = '\0'; - deb_ver1++; - } - if (deb_ver2) { - deb_ver2[0] = '\0'; - deb_ver2++; - } - result = version_compare_part(upstream_ver1, upstream_ver2); - - free(upstream_ver1); - free(upstream_ver2); - - if (result != 0) { - return(result); - } - - /* Compare debian versions */ - return(version_compare_part(deb_ver1, deb_ver2)); -} - -int test_version(const unsigned int version1, const unsigned int version2, const unsigned int operator) -{ - const int version_result = version_compare(version1, version2); - switch(operator) { - case (VER_ANY): - return(TRUE); - case (VER_EQUAL): - if (version_result == 0) { - return(TRUE); - } - break; - case (VER_LESS): - if (version_result < 0) { - return(TRUE); - } - break; - case (VER_LESS_EQUAL): - if (version_result <= 0) { - return(TRUE); - } - break; - case (VER_MORE): - if (version_result > 0) { - return(TRUE); - } - break; - case (VER_MORE_EQUAL): - if (version_result >= 0) { - return(TRUE); - } - break; - } - return(FALSE); -} - - -int search_package_hashtable(const unsigned int name, const unsigned int version, const unsigned int operator) -{ - unsigned int probe_address = 0; - unsigned int probe_decrement = 0; - - make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME); - while(package_hashtable[probe_address] != NULL) { - if (package_hashtable[probe_address]->name == name) { - if (operator == VER_ANY) { - return(probe_address); - } - if (test_version(package_hashtable[probe_address]->version, version, operator)) { - return(probe_address); - } - } - probe_address -= probe_decrement; - if ((int)probe_address < 0) { - probe_address += PACKAGE_HASH_PRIME; - } - } - return(probe_address); -} - -/* - * Create one new node and one new edge for every dependency. - */ -void add_split_dependencies(common_node_t *parent_node, const char *whole_line, unsigned int edge_type) -{ - char *line = xstrdup(whole_line); - char *line2; - char *line_ptr1 = NULL; - char *line_ptr2 = NULL; - char *field; - char *field2; - char *version; - edge_t *edge; - int offset_ch; - int type; - - field = strtok_r(line, ",", &line_ptr1); - do { - line2 = xstrdup(field); - field2 = strtok_r(line2, "|", &line_ptr2); - if ((edge_type == EDGE_DEPENDS) && (strcmp(field, field2) != 0)) { - type = EDGE_OR_DEPENDS; - } - else if ((edge_type == EDGE_PRE_DEPENDS) && (strcmp(field, field2) != 0)) { - type = EDGE_OR_PRE_DEPENDS; - } else { - type = edge_type; - } - - do { - edge = (edge_t *) xmalloc(sizeof(edge_t)); - edge->type = type; - - /* Skip any extra leading spaces */ - field2 += strspn(field2, " "); - - /* Get dependency version info */ - version = strchr(field2, '('); - if (version == NULL) { - edge->operator = VER_ANY; - /* Get the versions hash number, adding it if the number isnt already in there */ - edge->version = search_name_hashtable("ANY"); - } else { - /* Skip leading ' ' or '(' */ - version += strspn(field2, " "); - version += strspn(version, "("); - /* Calculate length of any operator charactors */ - offset_ch = strspn(version, "<=>"); - /* Determine operator */ - if (offset_ch > 0) { - if (strncmp(version, "=", offset_ch) == 0) { - edge->operator = VER_EQUAL; - } - else if (strncmp(version, "<<", offset_ch) == 0) { - edge->operator = VER_LESS; - } - else if (strncmp(version, "<=", offset_ch) == 0) { - edge->operator = VER_LESS_EQUAL; - } - else if (strncmp(version, ">>", offset_ch) == 0) { - edge->operator = VER_MORE; - } - else if (strncmp(version, ">=", offset_ch) == 0) { - edge->operator = VER_MORE_EQUAL; - } else { - error_msg_and_die("Illegal operator\n"); - } - } - /* skip to start of version numbers */ - version += offset_ch; - version += strspn(version, " "); - - /* Truncate version at trailing ' ' or ')' */ - version[strcspn(version, " )")] = '\0'; - /* Get the versions hash number, adding it if the number isnt already in there */ - edge->version = search_name_hashtable(version); - } - - /* Get the dependency name */ - field2[strcspn(field2, " (")] = '\0'; - edge->name = search_name_hashtable(field2); - - /* link the new edge to the current node */ - parent_node->num_of_edges++; - parent_node->edge = xrealloc(parent_node->edge, sizeof(edge_t) * (parent_node->num_of_edges + 1)); - parent_node->edge[parent_node->num_of_edges - 1] = edge; - } while ((field2 = strtok_r(NULL, "|", &line_ptr2)) != NULL); - free(line2); - } while ((field = strtok_r(NULL, ",", &line_ptr1)) != NULL); - free(line); - - return; -} - -void free_package(common_node_t *node) -{ - int i; - if (node != NULL) { - for (i = 0; i < node->num_of_edges; i++) { - if (node->edge[i] != NULL) { - free(node->edge[i]); - } - } - if (node->edge != NULL) { - free(node->edge); - } - if (node != NULL) { - free(node); - } - } -} - -unsigned int fill_package_struct(char *control_buffer) -{ - common_node_t *new_node = (common_node_t *) xcalloc(1, sizeof(common_node_t)); - - char **field_name = xmalloc(sizeof(char *)); - char **field_value = xmalloc(sizeof(char *)); - int field_start = 0; - int num = -1; - int buffer_length = strlen(control_buffer); - - new_node->version = search_name_hashtable("unknown"); - while (field_start < buffer_length) { - field_start += read_package_field(&control_buffer[field_start], field_name, field_value); - - if (*field_name == NULL) { - goto fill_package_struct_cleanup; // Oh no, the dreaded goto statement !! - } - - if (strcmp(*field_name, "Package") == 0) { - new_node->name = search_name_hashtable(*field_value); - } - else if (strcmp(*field_name, "Version") == 0) { - new_node->version = search_name_hashtable(*field_value); - } - else if (strcmp(*field_name, "Pre-Depends") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_PRE_DEPENDS); - } - else if (strcmp(*field_name, "Depends") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_DEPENDS); - } - else if (strcmp(*field_name, "Replaces") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_REPLACES); - } - else if (strcmp(*field_name, "Provides") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_PROVIDES); - } - else if (strcmp(*field_name, "Conflicts") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_CONFLICTS); - } - else if (strcmp(*field_name, "Suggests") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_SUGGESTS); - } - else if (strcmp(*field_name, "Recommends") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_RECOMMENDS); - } - else if (strcmp(*field_name, "Enhances") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_ENHANCES); - } -fill_package_struct_cleanup: - if (*field_name) { - free(*field_name); - } - if (*field_value) { - free(*field_value); - } - } - free(field_name); - free(field_value); - - if (new_node->version == search_name_hashtable("unknown")) { - free_package(new_node); - return(-1); - } - num = search_package_hashtable(new_node->name, new_node->version, VER_EQUAL); - if (package_hashtable[num] == NULL) { - package_hashtable[num] = new_node; - } else { - free_package(new_node); - } - return(num); -} - -/* if num = 1, it returns the want status, 2 returns flag, 3 returns status */ -unsigned int get_status(const unsigned int status_node, const int num) -{ - char *status_string = name_hashtable[status_hashtable[status_node]->status]; - char *state_sub_string; - unsigned int state_sub_num; - int len; - int i; - - /* set tmp_string to point to the start of the word number */ - for (i = 1; i < num; i++) { - /* skip past a word */ - status_string += strcspn(status_string, " "); - /* skip past the seperating spaces */ - status_string += strspn(status_string, " "); - } - len = strcspn(status_string, " \n\0"); - state_sub_string = xstrndup(status_string, len); - state_sub_num = search_name_hashtable(state_sub_string); - free(state_sub_string); - return(state_sub_num); -} - -void set_status(const unsigned int status_node_num, const char *new_value, const int position) -{ - const unsigned int new_value_len = strlen(new_value); - const unsigned int new_value_num = search_name_hashtable(new_value); - unsigned int want = get_status(status_node_num, 1); - unsigned int flag = get_status(status_node_num, 2); - unsigned int status = get_status(status_node_num, 3); - int want_len = strlen(name_hashtable[want]); - int flag_len = strlen(name_hashtable[flag]); - int status_len = strlen(name_hashtable[status]); - char *new_status; - - switch (position) { - case (1): - want = new_value_num; - want_len = new_value_len; - break; - case (2): - flag = new_value_num; - flag_len = new_value_len; - break; - case (3): - status = new_value_num; - status_len = new_value_len; - break; - default: - error_msg_and_die("DEBUG ONLY: this shouldnt happen"); - } - - new_status = (char *) xmalloc(want_len + flag_len + status_len + 3); - sprintf(new_status, "%s %s %s", name_hashtable[want], name_hashtable[flag], name_hashtable[status]); - status_hashtable[status_node_num]->status = search_name_hashtable(new_status); - free(new_status); - return; -} - -void index_status_file(const char *filename) -{ - FILE *status_file; - char *control_buffer; - char *status_line; - status_node_t *status_node = NULL; - unsigned int status_num; - - status_file = xfopen(filename, "r"); - while ((control_buffer = fgets_str(status_file, "\n\n")) != NULL) { - const unsigned int package_num = fill_package_struct(control_buffer); - if (package_num != -1) { - status_node = xmalloc(sizeof(status_node_t)); - /* fill_package_struct doesnt handle the status field */ - status_line = strstr(control_buffer, "Status:"); - if (status_line != NULL) { - status_line += 7; - status_line += strspn(status_line, " \n\t"); - status_line = xstrndup(status_line, strcspn(status_line, "\n\0")); - status_node->status = search_name_hashtable(status_line); - free(status_line); - } - status_node->package = package_num; - status_num = search_status_hashtable(name_hashtable[package_hashtable[status_node->package]->name]); - status_hashtable[status_num] = status_node; - } - free(control_buffer); - } - fclose(status_file); - return; -} - - -char *get_depends_field(common_node_t *package, const int depends_type) -{ - char *depends = NULL; - char *old_sep = (char *)xcalloc(1, 3); - char *new_sep = (char *)xcalloc(1, 3); - int line_size = 0; - int depends_size; - - int i; - - for (i = 0; i < package->num_of_edges; i++) { - if ((package->edge[i]->type == EDGE_OR_PRE_DEPENDS) || - (package->edge[i]->type == EDGE_OR_DEPENDS)) { - } - - if ((package->edge[i]->type == depends_type) || - (package->edge[i]->type == depends_type + 1)) { - /* Check if its the first time through */ - - depends_size = 8 + strlen(name_hashtable[package->edge[i]->name]) - + strlen(name_hashtable[package->edge[i]->version]); - line_size += depends_size; - depends = (char *) xrealloc(depends, line_size + 1); - - /* Check to see if this dependency is the type we are looking for - * +1 to check for 'extra' types, e.g. ored dependecies */ - strcpy(old_sep, new_sep); - if (package->edge[i]->type == depends_type) { - strcpy(new_sep, ", "); - } - else if (package->edge[i]->type == depends_type + 1) { - strcpy(new_sep, "| "); - } - - if (depends_size == line_size) { - strcpy(depends, ""); - } else { - if ((strcmp(old_sep, "| ") == 0) && (strcmp(new_sep, "| ") == 0)) { - strcat(depends, " | "); - } else { - strcat(depends, ", "); - } - } - - strcat(depends, name_hashtable[package->edge[i]->name]); - if (strcmp(name_hashtable[package->edge[i]->version], "NULL") != 0) { - if (package->edge[i]->operator == VER_EQUAL) { - strcat(depends, " (= "); - } - else if (package->edge[i]->operator == VER_LESS) { - strcat(depends, " (<< "); - } - else if (package->edge[i]->operator == VER_LESS_EQUAL) { - strcat(depends, " (<= "); - } - else if (package->edge[i]->operator == VER_MORE) { - strcat(depends, " (>> "); - } - else if (package->edge[i]->operator == VER_MORE_EQUAL) { - strcat(depends, " (>= "); - } else { - strcat(depends, " ("); - } - strcat(depends, name_hashtable[package->edge[i]->version]); - strcat(depends, ")"); - } - } - } - return(depends); -} - -void write_buffer_no_status(FILE *new_status_file, const char *control_buffer) -{ - char *name; - char *value; - int start = 0; - while (1) { - start += read_package_field(&control_buffer[start], &name, &value); - if (name == NULL) { - break; - } - if (strcmp(name, "Status") != 0) { - fprintf(new_status_file, "%s: %s\n", name, value); - } - } - return; -} - -/* This could do with a cleanup */ -void write_status_file(deb_file_t **deb_file) -{ - FILE *old_status_file = xfopen("/var/lib/dpkg/status", "r"); - FILE *new_status_file = xfopen("/var/lib/dpkg/status.udeb", "w"); - char *package_name; - char *status_from_file; - char *control_buffer = NULL; - char *tmp_string; - int status_num; - int field_start = 0; - int write_flag; - int i = 0; - - /* Update previously known packages */ - while ((control_buffer = fgets_str(old_status_file, "\n\n")) != NULL) { - tmp_string = strstr(control_buffer, "Package:") + 8; - tmp_string += strspn(tmp_string, " \n\t"); - package_name = xstrndup(tmp_string, strcspn(tmp_string, "\n\0")); - write_flag = FALSE; - tmp_string = strstr(control_buffer, "Status:"); - if (tmp_string != NULL) { - /* Seperate the status value from the control buffer */ - tmp_string += 7; - tmp_string += strspn(tmp_string, " \n\t"); - status_from_file = xstrndup(tmp_string, strcspn(tmp_string, "\n")); - } else { - status_from_file = NULL; - } - - /* Find this package in the status hashtable */ - status_num = search_status_hashtable(package_name); - if (status_hashtable[status_num] != NULL) { - const char *status_from_hashtable = name_hashtable[status_hashtable[status_num]->status]; - if (strcmp(status_from_file, status_from_hashtable) != 0) { - /* New status isnt exactly the same as old status */ - const int state_status = get_status(status_num, 3); - if ((strcmp("installed", name_hashtable[state_status]) == 0) || - (strcmp("unpacked", name_hashtable[state_status]) == 0)) { - /* We need to add the control file from the package */ - i = 0; - while(deb_file[i] != NULL) { - if (strcmp(package_name, name_hashtable[package_hashtable[deb_file[i]->package]->name]) == 0) { - /* Write a status file entry with a modified status */ - /* remove trailing \n's */ - write_buffer_no_status(new_status_file, deb_file[i]->control_file); - set_status(status_num, "ok", 2); - fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]); - write_flag = TRUE; - break; - } - i++; - } - /* This is temperary, debugging only */ - if (deb_file[i] == NULL) { - error_msg_and_die("ALERT: Couldnt find a control file, your status file may be broken, status may be incorrect for %s", package_name); - } - } - else if (strcmp("not-installed", name_hashtable[state_status]) == 0) { - /* Only write the Package, Status, Priority and Section lines */ - fprintf(new_status_file, "Package: %s\n", package_name); - fprintf(new_status_file, "Status: %s\n", status_from_hashtable); - - while (1) { - char *field_name; - char *field_value; - field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value); - if (field_name == NULL) { - break; - } - if ((strcmp(field_name, "Priority") == 0) || - (strcmp(field_name, "Section") == 0)) { - fprintf(new_status_file, "%s: %s\n", field_name, field_value); - } - } - write_flag = TRUE; - fputs("\n", new_status_file); - } - else if (strcmp("config-files", name_hashtable[state_status]) == 0) { - /* only change the status line */ - while (1) { - char *field_name; - char *field_value; - field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value); - if (field_name == NULL) { - break; - } - /* Setup start point for next field */ - if (strcmp(field_name, "Status") == 0) { - fprintf(new_status_file, "Status: %s\n", status_from_hashtable); - } else { - fprintf(new_status_file, "%s: %s\n", field_name, field_value); - } - } - write_flag = TRUE; - fputs("\n", new_status_file); - } - } - } - /* If the package from the status file wasnt handle above, do it now*/ - if (write_flag == FALSE) { - fprintf(new_status_file, "%s\n\n", control_buffer); - } - - if (status_from_file != NULL) { - free(status_from_file); - } - free(package_name); - free(control_buffer); - } - - /* Write any new packages */ - for(i = 0; deb_file[i] != NULL; i++) { - status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[i]->package]->name]); - if (strcmp("reinstreq", name_hashtable[get_status(status_num, 2)]) == 0) { - write_buffer_no_status(new_status_file, deb_file[i]->control_file); - set_status(status_num, "ok", 2); - fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]); - } - } - fclose(old_status_file); - fclose(new_status_file); - - - /* Create a seperate backfile to dpkg */ - if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) { - struct stat stat_buf; - if (stat("/var/lib/dpkg/status", &stat_buf) == 0) { - error_msg_and_die("Couldnt create backup status file"); - } - /* Its ok if renaming the status file fails becasue status - * file doesnt exist, maybe we are starting from scratch */ - error_msg("No status file found, creating new one"); - } - - if (rename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status") == -1) { - error_msg_and_die("DANGER: Couldnt create status file, you need to manually repair your status file"); - } -} - -int check_deps(deb_file_t **deb_file, int deb_start, int dep_max_count) -{ - int *conflicts = NULL; - int conflicts_num = 0; - int state_status; - int state_flag; - int state_want; - unsigned int status_package_num; - int i = deb_start; - int j, k; - - /* Check for conflicts - * TODO: TEST if conflicts with other packages to be installed - * - * Add install packages and the packages they provide - * to the list of files to check conflicts for - */ - - /* Create array of package numbers to check against - * installed package for conflicts*/ - while (deb_file[i] != NULL) { - const unsigned int package_num = deb_file[i]->package; - conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1)); - conflicts[conflicts_num] = package_num; - conflicts_num++; - /* add provides to conflicts list */ - for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) { - if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) { - const int conflicts_package_num = search_package_hashtable( - package_hashtable[package_num]->edge[j]->name, - package_hashtable[package_num]->edge[j]->version, - package_hashtable[package_num]->edge[j]->operator); - if (package_hashtable[conflicts_package_num] == NULL) { - /* create a new package */ - common_node_t *new_node = (common_node_t *) xmalloc(sizeof(common_node_t)); - new_node->name = package_hashtable[package_num]->edge[j]->name; - new_node->version = package_hashtable[package_num]->edge[j]->version; - new_node->num_of_edges = 0; - new_node->edge = NULL; - package_hashtable[conflicts_package_num] = new_node; - } - conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1)); - conflicts[conflicts_num] = conflicts_package_num; - conflicts_num++; - } - } - i++; - } - - /* Check conflicts */ - for (i = 0; i < conflicts_num; i++) { - /* Check for conflicts */ - for (j = 0; j < STATUS_HASH_PRIME; j++) { - if (status_hashtable[j] == NULL) { - continue; - } - state_flag = get_status(j, 2); - state_status = get_status(j, 3); - if ((state_status != search_name_hashtable("installed")) - && (state_flag != search_name_hashtable("want-install"))) { - continue; - } - status_package_num = status_hashtable[j]->package; - for (k = 0; k < package_hashtable[status_package_num]->num_of_edges; k++) { - const edge_t *package_edge = package_hashtable[status_package_num]->edge[k]; - if (package_edge->type != EDGE_CONFLICTS) { - continue; - } - if (package_edge->name != package_hashtable[conflicts[i]]->name) { - continue; - } - /* There is a conflict against the package name - * check if version conflict as well */ - if (test_version(package_hashtable[deb_file[i]->package]->version, - package_edge->version, package_edge->operator)) { - error_msg_and_die("Package %s conflict with %s", - name_hashtable[package_hashtable[deb_file[i]->package]->name], - name_hashtable[package_hashtable[status_package_num]->name]); - } - } - } - } - - /* Check dependendcies */ - i = 0; - while (deb_file[i] != NULL) { - const common_node_t *package_node = package_hashtable[deb_file[i]->package]; - int status_num = 0; - - for (j = 0; j < package_hashtable[deb_file[i]->package]->num_of_edges; j++) { - const edge_t *package_edge = package_node->edge[j]; - const unsigned int package_num = search_package_hashtable(package_edge->name, - package_edge->version, package_edge->operator); - - status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]); - state_status = get_status(status_num, 3); - state_want = get_status(status_num, 1); - switch (package_edge->type) { - case(EDGE_PRE_DEPENDS): - case(EDGE_OR_PRE_DEPENDS): - /* It must be already installed */ - /* NOTE: This is untested, nothing apropriate in my status file */ - if ((package_hashtable[package_num] == NULL) || (state_status != search_name_hashtable("installed"))) { - error_msg_and_die("Package %s pre-depends on %s, but it is not installed", - name_hashtable[package_node->name], - name_hashtable[package_edge->name]); - } - break; - case(EDGE_DEPENDS): - case(EDGE_OR_DEPENDS): - /* It must be already installed, or to be installed */ - if ((package_hashtable[package_num] == NULL) || - ((state_status != search_name_hashtable("installed")) && - (state_want != search_name_hashtable("want_install")))) { - error_msg_and_die("Package %s depends on %s, but it is not installed, or flaged to be installed", - name_hashtable[package_node->name], - name_hashtable[package_edge->name]); - } - break; - } - } - i++; - } - free(conflicts); - return(TRUE); -} - -char **create_list(const char *filename) -{ - FILE *list_stream; - char **file_list = xmalloc(sizeof(char *)); - char *line = NULL; - char *last_char; - int length = 0; - int count = 0; - - /* dont use [xw]fopen here, handle error ourself */ - list_stream = fopen(filename, "r"); - if (list_stream == NULL) { - *file_list = NULL; - return(file_list); - } - while (getline(&line, &length, list_stream) != -1) { - file_list = xrealloc(file_list, sizeof(char *) * (length + 1)); - last_char = last_char_is(line, '\n'); - if (last_char) { - *last_char = '\0'; - } - file_list[count] = xstrdup(line); - free(line); - count++; - length = 0; - } - fclose(list_stream); - - if (count == 0) { - return(NULL); - } else { - file_list[count] = NULL; - return(file_list); - } -} - -/* maybe i should try and hook this into remove_file.c somehow */ -int remove_file_array(char **remove_names, char **exclude_names) -{ - struct stat path_stat; - int match_flag; - int remove_flag = FALSE; - int i,j; - - if (remove_names == NULL) { - return(FALSE); - } - for (i = 0; remove_names[i] != NULL; i++) { - match_flag = FALSE; - if (exclude_names != NULL) { - for (j = 0; exclude_names[j] != 0; j++) { - if (strcmp(remove_names[i], exclude_names[j]) == 0) { - match_flag = TRUE; - break; - } - } - } - if (!match_flag) { - if (lstat(remove_names[i], &path_stat) < 0) { - continue; - } - if (S_ISDIR(path_stat.st_mode)) { - if (rmdir(remove_names[i]) != -1) { - remove_flag = TRUE; - } - } else { - if (unlink(remove_names[i]) != -1) { - remove_flag = TRUE; - } - } - } - } - return(remove_flag); -} - -int run_package_script(const char *package_name, const char *script_type) -{ - struct stat path_stat; - char *script_path; - - script_path = xmalloc(strlen(package_name) + strlen(script_type) + 21); - sprintf(script_path, "/var/lib/dpkg/info/%s.%s", package_name, script_type); - - /* If the file doesnt exist is isnt a fatal */ - if (lstat(script_path, &path_stat) < 0) { - free(script_path); - return(EXIT_SUCCESS); - } else { - free(script_path); - return(system(script_path)); - } -} - -void all_control_list(char **remove_files, const char *package_name) -{ - const char *all_extensions[11] = {"preinst", "postinst", "prerm", "postrm", - "list", "md5sums", "shlibs", "conffiles", "config", "templates", NULL }; - int i; - - /* Create a list of all /var/lib/dpkg/info/ files */ - for(i = 0; i < 10; i++) { - remove_files[i] = xmalloc(strlen(package_name) + strlen(all_extensions[i]) + 21); - sprintf(remove_files[i], "/var/lib/dpkg/info/%s.%s", package_name, all_extensions[i]); - } - remove_files[10] = NULL; -} - -void remove_package(const unsigned int package_num) -{ - const char *package_name = name_hashtable[package_hashtable[package_num]->name]; - const unsigned int status_num = search_status_hashtable(package_name); - const int package_name_length = strlen(package_name); - char **remove_files; - char **exclude_files; - char list_name[package_name_length + 25]; - char conffile_name[package_name_length + 30]; - int return_value; - - printf("Removing %s ...\n", package_name); - - /* run prerm script */ - return_value = run_package_script(package_name, "prem"); - if (return_value == -1) { - error_msg_and_die("script failed, prerm failure"); - } - - /* Create a list of files to remove, and a seperate list of those to keep */ - sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name); - remove_files = create_list(list_name); - - sprintf(conffile_name, "/var/lib/dpkg/info/%s.conffiles", package_name); - exclude_files = create_list(conffile_name); - - /* Some directories cant be removed straight away, so do multiple passes */ - while (remove_file_array(remove_files, exclude_files) == TRUE); - - /* Create a list of all /var/lib/dpkg/info/ files */ - remove_files = xmalloc(11); - all_control_list(remove_files, package_name); - - /* Create a list of files in /var/lib/dpkg/info/.* to keep */ - exclude_files = xmalloc(sizeof(char*) * 3); - exclude_files[0] = xstrdup(conffile_name); - exclude_files[1] = xmalloc(package_name_length + 27); - sprintf(exclude_files[1], "/var/lib/dpkg/info/%s.postrm", package_name); - exclude_files[2] = NULL; - - remove_file_array(remove_files, exclude_files); - - /* rename .conffile to .list */ - rename(conffile_name, list_name); - - /* Change package status */ - set_status(status_num, "deinstall", 1); - set_status(status_num, "config-files", 3); -} - -void purge_package(const unsigned int package_num) -{ - const char *package_name = name_hashtable[package_hashtable[package_num]->name]; - const unsigned int status_num = search_status_hashtable(package_name); - char **remove_files; - char **exclude_files; - char list_name[strlen(package_name) + 25]; - - /* run prerm script */ - if (run_package_script(package_name, "prerm") == -1) { - error_msg_and_die("script failed, prerm failure"); - } - - /* Create a list of files to remove */ - sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name); - remove_files = create_list(list_name); - - exclude_files = xmalloc(1); - exclude_files[0] = NULL; - - /* Some directories cant be removed straight away, so do multiple passes */ - while (remove_file_array(remove_files, exclude_files) == TRUE); - - /* Create a list of all /var/lib/dpkg/info/ files */ - remove_files = xmalloc(11); - all_control_list(remove_files, package_name); - remove_file_array(remove_files, exclude_files); - - /* run postrm script */ - if (run_package_script(package_name, "postrm") == -1) { - error_msg_and_die("postrm fialure.. set status to what?"); - } - - /* Change package status */ - set_status(status_num, "purge", 1); - set_status(status_num, "not-installed", 3); -} - -void unpack_package(deb_file_t *deb_file) -{ - const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name]; - const unsigned int status_num = search_status_hashtable(package_name); - const unsigned int status_package_num = status_hashtable[status_num]->status; - - FILE *out_stream; - char *info_prefix; - - /* If existing version, remove it first */ - if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) { - /* Package is already installed, remove old version first */ - printf("Preparing to replace %s %s (using %s) ...\n", package_name, - name_hashtable[package_hashtable[status_package_num]->version], - deb_file->filename); - remove_package(status_package_num); - } else { - printf("Unpacking %s (from %s) ...\n", package_name, deb_file->filename); - } - - /* Extract control.tar.gz to /var/lib/dpkg/info/.filename */ - info_prefix = (char *) xmalloc(sizeof(package_name) + 20 + 4 + 1); - sprintf(info_prefix, "/var/lib/dpkg/info/%s.", package_name); - deb_extract(deb_file->filename, stdout, (extract_quiet | extract_control_tar_gz | extract_all_to_fs), info_prefix, NULL); - - /* Extract data.tar.gz to the root directory */ - deb_extract(deb_file->filename, stdout, (extract_quiet | extract_data_tar_gz | extract_all_to_fs), "/", NULL); - - /* Create the list file */ - strcat(info_prefix, "list"); - out_stream = xfopen(info_prefix, "w"); - deb_extract(deb_file->filename, out_stream, (extract_quiet | extract_data_tar_gz | extract_list), NULL, NULL); - fclose(out_stream); - - /* change status */ - set_status(status_num, "install", 1); - set_status(status_num, "unpacked", 3); - - free(info_prefix); -} - -void configure_package(deb_file_t *deb_file) -{ - const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name]; - const char *package_version = name_hashtable[package_hashtable[deb_file->package]->version]; - const int status_num = search_status_hashtable(package_name); - int return_value; - - printf("Setting up %s (%s)\n", package_name, package_version); - - /* Run the preinst prior to extracting */ - return_value = run_package_script(package_name, "postinst"); - if (return_value == -1) { - /* TODO: handle failure gracefully */ - error_msg_and_die("postrm failure.. set status to what?"); - } - /* Change status to reflect success */ - set_status(status_num, "install", 1); - set_status(status_num, "installed", 3); -} - -extern int dpkg_main(int argc, char **argv) -{ - deb_file_t **deb_file = NULL; - status_node_t *status_node; - char opt = 0; - int package_num; - int dpkg_opt = 0; - int deb_count = 0; - int state_status; - int status_num; - int i; - - while ((opt = getopt(argc, argv, "CF:ilPru")) != -1) { - switch (opt) { - case 'C': // equivalent to --configure in official dpkg - dpkg_opt |= dpkg_opt_configure; - dpkg_opt |= dpkg_opt_package_name; - break; - case 'F': // equivalent to --force in official dpkg - if (strcmp(optarg, "depends") == 0) { - dpkg_opt |= dpkg_opt_force_ignore_depends; - } - case 'i': - dpkg_opt |= dpkg_opt_install; - dpkg_opt |= dpkg_opt_filename; - break; - case 'l': - dpkg_opt |= dpkg_opt_list_installed; - case 'P': - dpkg_opt |= dpkg_opt_purge; - dpkg_opt |= dpkg_opt_package_name; - break; - case 'r': - dpkg_opt |= dpkg_opt_remove; - dpkg_opt |= dpkg_opt_package_name; - break; - case 'u': /* Equivalent to --unpack in official dpkg */ - dpkg_opt |= dpkg_opt_unpack; - dpkg_opt |= dpkg_opt_filename; - break; - default: - show_usage(); - } - } - - if ((argc == optind) || (dpkg_opt == 0)) { - show_usage(); - } - - puts("(Reading database ... xxxxx files and directories installed.)"); - index_status_file("/var/lib/dpkg/status"); - - /* Read arguments and store relevant info in structs */ - deb_file = xmalloc(sizeof(deb_file_t)); - while (optind < argc) { - deb_file[deb_count] = (deb_file_t *) xmalloc(sizeof(deb_file_t)); - if (dpkg_opt & dpkg_opt_filename) { - deb_file[deb_count]->filename = xstrdup(argv[optind]); - deb_file[deb_count]->control_file = deb_extract(argv[optind], stdout, (extract_control_tar_gz | extract_one_to_buffer), NULL, "./control"); - if (deb_file[deb_count]->control_file == NULL) { - error_msg_and_die("Couldnt extract control file"); - } - package_num = fill_package_struct(deb_file[deb_count]->control_file); - - if (package_num == -1) { - error_msg("Invalid control file in %s", argv[optind]); - continue; - } - deb_file[deb_count]->package = (unsigned int) package_num; - /* Add the package to the status hashtable */ - if ((dpkg_opt & dpkg_opt_unpack) || (dpkg_opt & dpkg_opt_install)) { - status_node = (status_node_t *) xmalloc(sizeof(status_node_t)); - status_node->package = deb_file[deb_count]->package; - /* use reinstreq isnt changed to "ok" until the package control info - * is written to the status file*/ - status_node->status = search_name_hashtable("install reinstreq not-installed"); - - status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); - status_hashtable[status_num] = status_node; - } - } - else if (dpkg_opt & dpkg_opt_package_name) { - deb_file[deb_count]->filename = NULL; - deb_file[deb_count]->control_file = NULL; - deb_file[deb_count]->package = search_package_hashtable( - search_name_hashtable(argv[optind]), - search_name_hashtable("ANY"), VER_ANY); - if (package_hashtable[deb_file[deb_count]->package] == NULL) { - error_msg_and_die("Package %s is uninstalled or unknown\n", argv[optind]); - } - state_status = get_status(search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]), 3); - - /* check package status is "installed" */ - if (dpkg_opt & dpkg_opt_remove) { - if ((strcmp(name_hashtable[state_status], "not-installed") == 0) || - (strcmp(name_hashtable[state_status], "config-files") == 0)) { - error_msg_and_die("%s is already removed.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); - } - } - else if (dpkg_opt & dpkg_opt_purge) { - /* if package status is "conf-files" then its ok */ - if (strcmp(name_hashtable[state_status], "not-installed") == 0) { - error_msg_and_die("%s is already purged.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); - } - } - } - deb_count++; - optind++; - } - deb_file[deb_count] = NULL; - - /* Check that the deb file arguments are installable */ - /* TODO: check dependencies before removing */ - if ((dpkg_opt & dpkg_opt_force_ignore_depends) != dpkg_opt_force_ignore_depends) { - if (!check_deps(deb_file, 0, deb_count)) { - error_msg_and_die("Dependency check failed"); - } - } - - for (i = 0; i < deb_count; i++) { - /* Remove or purge packages */ - if (dpkg_opt & dpkg_opt_remove) { - remove_package(deb_file[i]->package); - } - else if (dpkg_opt & dpkg_opt_purge) { - purge_package(deb_file[i]->package); - } - else if (dpkg_opt & dpkg_opt_unpack) { - unpack_package(deb_file[i]); - } - else if (dpkg_opt & dpkg_opt_install) { - unpack_package(deb_file[i]); - configure_package(deb_file[i]); - } - else if (dpkg_opt & dpkg_opt_configure) { - configure_package(deb_file[i]); - } - } - - write_status_file(deb_file); - - for (i = 0; i < deb_count; i++) { - free(deb_file[i]->control_file); - free(deb_file[i]->filename); - free(deb_file[i]); - } - free(deb_file); - - for (i = 0; i < NAME_HASH_PRIME; i++) { - if (name_hashtable[i] != NULL) { - free(name_hashtable[i]); - } - } - - for (i = 0; i < PACKAGE_HASH_PRIME; i++) { - free_package(package_hashtable[i]); - } - - for (i = 0; i < STATUS_HASH_PRIME; i++) { - if (status_hashtable[i] != NULL) { - free(status_hashtable[i]); - } - } - - return(EXIT_FAILURE); -} - diff --git a/busybox/archival/dpkg_deb.c b/busybox/archival/dpkg_deb.c deleted file mode 100644 index a933c6948..000000000 --- a/busybox/archival/dpkg_deb.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include "busybox.h" - -extern int dpkg_deb_main(int argc, char **argv) -{ - char *prefix = NULL; - char *filename = NULL; - char *output_buffer = NULL; - int opt = 0; - int arg_type = 0; - int deb_extract_funct = extract_create_leading_dirs | extract_unconditional; - - const int arg_type_prefix = 1; - const int arg_type_field = 2; - const int arg_type_filename = 4; -// const int arg_type_un_ar_gz = 8; - - while ((opt = getopt(argc, argv, "ceftXxI")) != -1) { - switch (opt) { - case 'c': - deb_extract_funct |= extract_data_tar_gz; - deb_extract_funct |= extract_verbose_list; - break; - case 'e': - arg_type = arg_type_prefix; - deb_extract_funct |= extract_control_tar_gz; - deb_extract_funct |= extract_all_to_fs; - break; - case 'f': - arg_type = arg_type_field; - deb_extract_funct |= extract_control_tar_gz; - deb_extract_funct |= extract_one_to_buffer; - filename = xstrdup("./control"); - break; - case 't': /* --fsys-tarfile, i just made up this short name */ - /* Integrate the functionality needed with some code from ar.c */ - error_msg_and_die("Option disabled"); -// arg_type = arg_type_un_ar_gz; - break; - case 'X': - arg_type = arg_type_prefix; - deb_extract_funct |= extract_data_tar_gz; - deb_extract_funct |= extract_all_to_fs; - deb_extract_funct |= extract_list; - case 'x': - arg_type = arg_type_prefix; - deb_extract_funct |= extract_data_tar_gz; - deb_extract_funct |= extract_all_to_fs; - break; - case 'I': - arg_type = arg_type_filename; - deb_extract_funct |= extract_control_tar_gz; - deb_extract_funct |= extract_one_to_buffer; - break; - default: - show_usage(); - } - } - - if (optind == argc) { - show_usage(); - } - - /* Workout where to extract the files */ - if (arg_type == arg_type_prefix) { - /* argument is a dir name */ - if ((optind + 1) == argc ) { - prefix = xstrdup("./DEBIAN/"); - } else { - prefix = (char *) xmalloc(strlen(argv[optind + 1]) + 2); - strcpy(prefix, argv[optind + 1]); - /* Make sure the directory has a trailing '/' */ - if (last_char_is(prefix, '/') == NULL) { - strcat(prefix, "/"); - } - } - mkdir(prefix, 0777); - } - - if (arg_type == arg_type_filename) { - if ((optind + 1) != argc) { - filename = xstrdup(argv[optind + 1]); - } else { - error_msg_and_die("-I currently requires a filename to be specified"); - } - } - - output_buffer = deb_extract(argv[optind], stdout, deb_extract_funct, prefix, filename); - - if ((arg_type == arg_type_filename) && (output_buffer != NULL)) { - puts(output_buffer); - } - else if (arg_type == arg_type_field) { - char *field = NULL; - char *name; - char *value; - int field_start = 0; - - while (1) { - field_start += read_package_field(&output_buffer[field_start], &name, &value); - if (name == NULL) { - break; - } - if (strcmp(name, argv[optind + 1]) == 0) { - puts(value); - } - free(field); - } - } - - return(EXIT_SUCCESS); -} diff --git a/busybox/archival/gunzip.c b/busybox/archival/gunzip.c deleted file mode 100644 index 430bc630e..000000000 --- a/busybox/archival/gunzip.c +++ /dev/null @@ -1,183 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Gzip implementation for busybox - * - * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly. - * - * Originally adjusted for busybox by Sven Rudolph - * based on gzip sources - * - * Adjusted further by Erik Andersen , - * to support files as well as stdin/stdout, and to generally behave itself wrt - * command line handling. - * - * General cleanup to better adhere to the style guide and make use of standard - * busybox functions by 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 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 - * - * - * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface - * Copyright (C) 1992-1993 Jean-loup Gailly - * The unzip code was written and put in the public domain by Mark Adler. - * Portions of the lzw code are derived from the public domain 'compress' - * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, - * Ken Turkowski, Dave Mack and Peter Jannesen. - * - * See the license_msg below and the file COPYING for the software license. - * See the file algorithm.doc for the compression algorithms and file formats. - */ - -#if 0 -static char *license_msg[] = { - " Copyright (C) 1992-1993 Jean-loup Gailly", - " 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., 675 Mass Ave, Cambridge, MA 02139, USA.", - 0 -}; -#endif - -#include -#include -#include -#include -#include "busybox.h" - -extern int gunzip_main(int argc, char **argv) -{ - FILE *in_file = stdin; - FILE *out_file = NULL; - struct stat stat_buf; - - char *if_name = NULL; - char *of_name = NULL; - char *delete_file_name = NULL; - - const int gunzip_to_stdout = 1; - const int gunzip_force = 2; - const int gunzip_test = 4; - - int flags = 0; - int opt = 0; - int delete_old_file = FALSE; - - /* if called as zcat */ - if (strcmp(applet_name, "zcat") == 0) - flags |= gunzip_to_stdout; - - while ((opt = getopt(argc, argv, "ctfhdq")) != -1) { - switch (opt) { - case 'c': - flags |= gunzip_to_stdout; - break; - case 'f': - flags |= gunzip_force; - break; - case 't': - flags |= gunzip_test; - break; - case 'd': /* Used to convert gzip to gunzip. */ - break; - case 'q': - error_msg("-q option not supported, ignored"); - break; - case 'h': - default: - show_usage(); /* exit's inside usage */ - } - } - - /* Set input filename and number */ - if (argv[optind] == NULL || strcmp(argv[optind], "-") == 0) { - flags |= gunzip_to_stdout; - } else { - if_name = strdup(argv[optind]); - /* Open input file */ - in_file = xfopen(if_name, "r"); - - /* set the buffer size */ - setvbuf(in_file, NULL, _IOFBF, 0x8000); - - /* Get the time stamp on the input file. */ - if (stat(if_name, &stat_buf) < 0) { - error_msg_and_die("Couldn't stat file %s", if_name); - } - } - - /* Check that the input is sane. */ - if (isatty(fileno(in_file)) && (flags & gunzip_force) == 0) - error_msg_and_die("compressed data not read from terminal. Use -f to force it."); - - /* Set output filename and number */ - if (flags & gunzip_test) { - out_file = xfopen("/dev/null", "w"); /* why does test use filenum 2 ? */ - } else if (flags & gunzip_to_stdout) { - out_file = stdout; - } else { - char *extension; - int length = strlen(if_name); - - delete_old_file = TRUE; - extension = strrchr(if_name, '.'); - if (extension && strcmp(extension, ".gz") == 0) { - length -= 3; - } else if (extension && strcmp(extension, ".tgz") == 0) { - length -= 4; - } else { - error_msg_and_die("Invalid extension"); - } - of_name = (char *) xcalloc(sizeof(char), length + 1); - strncpy(of_name, if_name, length); - - /* Open output file */ - out_file = xfopen(of_name, "w"); - - /* Set permissions on the file */ - chmod(of_name, stat_buf.st_mode); - } - - /* do the decompression, and cleanup */ - if (unzip(in_file, out_file) == 0) { - /* Success, remove .gz file */ - delete_file_name = if_name; - } else { - /* remove failed attempt */ - delete_file_name = of_name; - } - - fclose(out_file); - fclose(in_file); - - if (delete_old_file == TRUE) { - if (unlink(delete_file_name) < 0) { - error_msg_and_die("Couldnt remove %s", delete_file_name); - } - } - - free(of_name); - - return(EXIT_SUCCESS); -} diff --git a/busybox/archival/gzip.c b/busybox/archival/gzip.c deleted file mode 100644 index 54bb72745..000000000 --- a/busybox/archival/gzip.c +++ /dev/null @@ -1,2550 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Gzip implementation for busybox - * - * Based on GNU gzip Copyright (C) 1992-1993 Jean-loup Gailly. - * - * Originally adjusted for busybox by Charles P. Wright - * "this is a stripped down version of gzip I put into busybox, it does - * only standard in to standard out with -9 compression. It also requires - * the zcat module for some important functions." - * - * Adjusted further by Erik Andersen , - * to support files as well as stdin/stdout, and to generally behave itself wrt - * command line handling. - * - * 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 - * - */ - -/* These defines are very important for BusyBox. Without these, - * huge chunks of ram are pre-allocated making the BusyBox bss - * size Freaking Huge(tm), which is a bad thing.*/ -#define SMALL_MEM -#define DYN_ALLOC - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#define memzero(s, n) memset ((void *)(s), 0, (n)) - -#ifndef RETSIGTYPE -# define RETSIGTYPE void -#endif - -typedef unsigned char uch; -typedef unsigned short ush; -typedef unsigned long ulg; - -/* Return codes from gzip */ -#define OK 0 -#define ERROR 1 -#define WARNING 2 - -/* Compression methods (see algorithm.doc) */ -/* Only STORED and DEFLATED are supported by this BusyBox module */ -#define STORED 0 -/* methods 4 to 7 reserved */ -#define DEFLATED 8 -static int method; /* compression method */ - -/* To save memory for 16 bit systems, some arrays are overlaid between - * the various modules: - * deflate: prev+head window d_buf l_buf outbuf - * unlzw: tab_prefix tab_suffix stack inbuf outbuf - * For compression, input is done in window[]. For decompression, output - * is done in window except for unlzw. - */ - -#ifndef INBUFSIZ -# ifdef SMALL_MEM -# define INBUFSIZ 0x2000 /* input buffer size */ -# else -# define INBUFSIZ 0x8000 /* input buffer size */ -# endif -#endif -#define INBUF_EXTRA 64 /* required by unlzw() */ - -#ifndef OUTBUFSIZ -# ifdef SMALL_MEM -# define OUTBUFSIZ 8192 /* output buffer size */ -# else -# define OUTBUFSIZ 16384 /* output buffer size */ -# endif -#endif -#define OUTBUF_EXTRA 2048 /* required by unlzw() */ - -#ifndef DIST_BUFSIZE -# ifdef SMALL_MEM -# define DIST_BUFSIZE 0x2000 /* buffer for distances, see trees.c */ -# else -# define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */ -# endif -#endif - -#ifdef DYN_ALLOC -# define DECLARE(type, array, size) static type * array -# define ALLOC(type, array, size) { \ - array = (type*)calloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \ - if (array == NULL) error_msg(memory_exhausted); \ - } -# define FREE(array) {if (array != NULL) free(array), array=NULL;} -#else -# define DECLARE(type, array, size) static type array[size] -# define ALLOC(type, array, size) -# define FREE(array) -#endif - -#define tab_suffix window -#define tab_prefix prev /* hash link (see deflate.c) */ -#define head (prev+WSIZE) /* hash head (see deflate.c) */ - -static long bytes_in; /* number of input bytes */ - -#define isize bytes_in -/* for compatibility with old zip sources (to be cleaned) */ - -typedef int file_t; /* Do not use stdio */ - -#define NO_FILE (-1) /* in memory compression */ - - -#define PACK_MAGIC "\037\036" /* Magic header for packed files */ -#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */ -#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */ -#define LZH_MAGIC "\037\240" /* Magic header for SCO LZH Compress files */ -#define PKZIP_MAGIC "\120\113\003\004" /* Magic header for pkzip files */ - -/* gzip flag byte */ -#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ -#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ -#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define RESERVED 0xC0 /* bit 6,7: reserved */ - -/* internal file attribute */ -#define UNKNOWN 0xffff -#define BINARY 0 -#define ASCII 1 - -#ifndef WSIZE -# define WSIZE 0x8000 /* window size--must be a power of two, and */ -#endif /* at least 32K for zip's deflate method */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST (WSIZE-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - -/* put_byte is used for the compressed output */ -#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\ - flush_outbuf();} - -/* Output a 16 bit value, lsb first */ -#define put_short(w) \ -{ if (outcnt < OUTBUFSIZ-2) { \ - outbuf[outcnt++] = (uch) ((w) & 0xff); \ - outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \ - } else { \ - put_byte((uch)((w) & 0xff)); \ - put_byte((uch)((ush)(w) >> 8)); \ - } \ -} - -/* Output a 32 bit value to the bit stream, lsb first */ -#define put_long(n) { \ - put_short((n) & 0xffff); \ - put_short(((ulg)(n)) >> 16); \ -} - -#define seekable() 0 /* force sequential output */ -#define translate_eol 0 /* no option -a yet */ - -/* Diagnostic functions */ -#ifdef DEBUG -# define Assert(cond,msg) {if(!(cond)) error_msg(msg);} -# define Trace(x) fprintf x -# define Tracev(x) {if (verbose) fprintf x ;} -# define Tracevv(x) {if (verbose>1) fprintf x ;} -# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} -# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - -#define WARN(msg) {if (!quiet) fprintf msg ; \ - if (exit_code == OK) exit_code = WARNING;} - -#ifndef MAX_PATH_LEN -# define MAX_PATH_LEN 1024 /* max pathname length */ -#endif - - - - /* from zip.c: */ -static int zip (int in, int out); -static int file_read (char *buf, unsigned size); - - /* from gzip.c */ -static RETSIGTYPE abort_gzip (void); - - /* from deflate.c */ -static void lm_init (ush * flags); -static ulg deflate (void); - - /* from trees.c */ -static void ct_init (ush * attr, int *methodp); -static int ct_tally (int dist, int lc); -static ulg flush_block (char *buf, ulg stored_len, int eof); - - /* from bits.c */ -static void bi_init (file_t zipfile); -static void send_bits (int value, int length); -static unsigned bi_reverse (unsigned value, int length); -static void bi_windup (void); -static void copy_block (char *buf, unsigned len, int header); -static int (*read_buf) (char *buf, unsigned size); - - /* from util.c: */ -static void flush_outbuf (void); - -/* lzw.h -- define the lzw functions. - * Copyright (C) 1992-1993 Jean-loup Gailly. - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License, see the file COPYING. - */ - -#if !defined(OF) && defined(lint) -# include "gzip.h" -#endif - -#ifndef BITS -# define BITS 16 -#endif -#define INIT_BITS 9 /* Initial number of bits per code */ - -#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */ -/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free. - * It's a pity that old uncompress does not check bit 0x20. That makes - * extension of the format actually undesirable because old compress - * would just crash on the new format instead of giving a meaningful - * error message. It does check the number of bits, but it's more - * helpful to say "unsupported format, get a new version" than - * "can only handle 16 bits". - */ - -/* tailor.h -- target dependent definitions - * Copyright (C) 1992-1993 Jean-loup Gailly. - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License, see the file COPYING. - */ - -/* The target dependent definitions should be defined here only. - * The target dependent functions should be defined in tailor.c. - */ - - - /* Common defaults */ - -#ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ -#endif - -#ifndef PATH_SEP -# define PATH_SEP '/' -#endif - -#ifndef OPTIONS_VAR -# define OPTIONS_VAR "GZIP" -#endif - -#ifndef Z_SUFFIX -# define Z_SUFFIX ".gz" -#endif - -#ifdef MAX_EXT_CHARS -# define MAX_SUFFIX MAX_EXT_CHARS -#else -# define MAX_SUFFIX 30 -#endif - - /* global buffers */ - -DECLARE(uch, inbuf, INBUFSIZ + INBUF_EXTRA); -DECLARE(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA); -DECLARE(ush, d_buf, DIST_BUFSIZE); -DECLARE(uch, window, 2L * WSIZE); -DECLARE(ush, tab_prefix, 1L << BITS); - -static int crc_table_empty = 1; - -static int foreground; /* set if program run in foreground */ -static int method = DEFLATED; /* compression method */ -static int exit_code = OK; /* program exit code */ -static int part_nb; /* number of parts in .gz file */ -static long time_stamp; /* original time stamp (modification time) */ -static long ifile_size; /* input file size, -1 for devices (debug only) */ -static char z_suffix[MAX_SUFFIX + 1]; /* default suffix (can be set with --suffix) */ -static int z_len; /* strlen(z_suffix) */ - -static char ifname[MAX_PATH_LEN]; /* input file name */ -static char ofname[MAX_PATH_LEN]; /* output file name */ -static int ifd; /* input file descriptor */ -static int ofd; /* output file descriptor */ -static unsigned insize; /* valid bytes in inbuf */ -static unsigned outcnt; /* bytes in output buffer */ - -/* ======================================================================== - * Signal and error handler. - */ -static void abort_gzip() -{ - exit(ERROR); -} - -/* =========================================================================== - * Clear input and output buffers - */ -static void clear_bufs(void) -{ - outcnt = 0; - insize = 0; - bytes_in = 0L; -} - -static void write_error_msg() -{ - fprintf(stderr, "\n"); - perror(""); - abort_gzip(); -} - -/* =========================================================================== - * Does the same as write(), but also handles partial pipe writes and checks - * for error return. - */ -static void write_buf(int fd, void *buf, unsigned cnt) -{ - unsigned n; - - while ((n = write(fd, buf, cnt)) != cnt) { - if (n == (unsigned) (-1)) { - write_error_msg(); - } - cnt -= n; - buf = (void *) ((char *) buf + n); - } -} - -/* =========================================================================== - * Run a set of bytes through the crc shift register. If s is a NULL - * pointer, then initialize the crc shift register contents instead. - * Return the current crc in either case. - */ -static ulg updcrc(uch *s, unsigned n) -{ - static ulg crc = (ulg) 0xffffffffL; /* shift register contents */ - register ulg c; /* temporary variable */ - static unsigned long crc_32_tab[256]; - if (crc_table_empty) { - unsigned long csr; /* crc shift register */ - unsigned long e=0; /* polynomial exclusive-or pattern */ - int i; /* counter for all possible eight bit values */ - int k; /* byte being shifted into crc apparatus */ - - /* terms of polynomial defining this crc (except x^32): */ - static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* Make exclusive-or pattern from polynomial (0xedb88320) */ - for (i = 0; i < sizeof(p)/sizeof(int); i++) - e |= 1L << (31 - p[i]); - - /* Compute and print table of CRC's, five per line */ - crc_32_tab[0] = 0x00000000L; - for (i = 1; i < 256; i++) { - csr = i; - /* The idea to initialize the register with the byte instead of - * zero was stolen from Haruhiko Okumura's ar002 - */ - for (k = 8; k; k--) - csr = csr & 1 ? (csr >> 1) ^ e : csr >> 1; - crc_32_tab[i]=csr; - } - } - - if (s == NULL) { - c = 0xffffffffL; - } else { - c = crc; - if (n) - do { - c = crc_32_tab[((int) c ^ (*s++)) & 0xff] ^ (c >> 8); - } while (--n); - } - crc = c; - return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */ -} - -/* bits.c -- output variable-length bit strings - * Copyright (C) 1992-1993 Jean-loup Gailly - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License, see the file COPYING. - */ - - -/* - * PURPOSE - * - * Output variable-length bit strings. Compression can be done - * to a file or to memory. (The latter is not supported in this version.) - * - * DISCUSSION - * - * The PKZIP "deflate" file format interprets compressed file data - * as a sequence of bits. Multi-bit strings in the file may cross - * byte boundaries without restriction. - * - * The first bit of each byte is the low-order bit. - * - * The routines in this file allow a variable-length bit value to - * be output right-to-left (useful for literal values). For - * left-to-right output (useful for code strings from the tree routines), - * the bits must have been reversed first with bi_reverse(). - * - * For in-memory compression, the compressed bit stream goes directly - * into the requested output buffer. The input data is read in blocks - * by the mem_read() function. The buffer is limited to 64K on 16 bit - * machines. - * - * INTERFACE - * - * void bi_init (FILE *zipfile) - * Initialize the bit string routines. - * - * void send_bits (int value, int length) - * Write out a bit string, taking the source bits right to - * left. - * - * int bi_reverse (int value, int length) - * Reverse the bits of a bit string, taking the source bits left to - * right and emitting them right to left. - * - * void bi_windup (void) - * Write out any remaining bits in an incomplete byte. - * - * void copy_block(char *buf, unsigned len, int header) - * Copy a stored block to the zip file, storing first the length and - * its one's complement if requested. - * - */ - -/* =========================================================================== - * Local data used by the "bit string" routines. - */ - -static file_t zfile; /* output gzip file */ - -static unsigned short bi_buf; - -/* Output buffer. bits are inserted starting at the bottom (least significant - * bits). - */ - -#define Buf_size (8 * 2*sizeof(char)) -/* Number of bits used within bi_buf. (bi_buf might be implemented on - * more than 16 bits on some systems.) - */ - -static int bi_valid; - -/* Current input function. Set to mem_read for in-memory compression */ - -#ifdef DEBUG -ulg bits_sent; /* bit length of the compressed data */ -#endif - -/* =========================================================================== - * Initialize the bit string routines. - */ -static void bi_init(file_t zipfile) -{ - zfile = zipfile; - bi_buf = 0; - bi_valid = 0; -#ifdef DEBUG - bits_sent = 0L; -#endif - - /* Set the defaults for file compression. They are set by memcompress - * for in-memory compression. - */ - if (zfile != NO_FILE) { - read_buf = file_read; - } -} - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -static void send_bits(int value, int length) -{ -#ifdef DEBUG - Tracev((stderr, " l %2d v %4x ", length, value)); - Assert(length > 0 && length <= 15, "invalid length"); - bits_sent += (ulg) length; -#endif - /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) - * unused bits in value. - */ - if (bi_valid > (int) Buf_size - length) { - bi_buf |= (value << bi_valid); - put_short(bi_buf); - bi_buf = (ush) value >> (Buf_size - bi_valid); - bi_valid += length - Buf_size; - } else { - bi_buf |= value << bi_valid; - bi_valid += length; - } -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -static unsigned bi_reverse(unsigned code, int len) -{ - register unsigned res = 0; - - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Write out any remaining bits in an incomplete byte. - */ -static void bi_windup() -{ - if (bi_valid > 8) { - put_short(bi_buf); - } else if (bi_valid > 0) { - put_byte(bi_buf); - } - bi_buf = 0; - bi_valid = 0; -#ifdef DEBUG - bits_sent = (bits_sent + 7) & ~7; -#endif -} - -/* =========================================================================== - * Copy a stored block to the zip file, storing first the length and its - * one's complement if requested. - */ -static void copy_block(char *buf, unsigned len, int header) -{ - bi_windup(); /* align on byte boundary */ - - if (header) { - put_short((ush) len); - put_short((ush) ~ len); -#ifdef DEBUG - bits_sent += 2 * 16; -#endif - } -#ifdef DEBUG - bits_sent += (ulg) len << 3; -#endif - while (len--) { - put_byte(*buf++); - } -} - -/* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1992-1993 Jean-loup Gailly - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License, see the file COPYING. - */ - -/* - * PURPOSE - * - * Identify new text as repetitions of old text within a fixed- - * length sliding window trailing behind the new text. - * - * DISCUSSION - * - * The "deflation" process depends on being able to identify portions - * of the input text which are identical to earlier input (within a - * sliding window trailing behind the input currently being processed). - * - * The most straightforward technique turns out to be the fastest for - * most input files: try all possible matches and select the longest. - * The key feature of this algorithm is that insertions into the string - * dictionary are very simple and thus fast, and deletions are avoided - * completely. Insertions are performed at each input character, whereas - * string matches are performed only when the previous match ends. So it - * is preferable to spend more time in matches to allow very fast string - * insertions and avoid deletions. The matching algorithm for small - * strings is inspired from that of Rabin & Karp. A brute force approach - * is used to find longer strings when a small match has been found. - * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze - * (by Leonid Broukhis). - * A previous version of this file used a more sophisticated algorithm - * (by Fiala and Greene) which is guaranteed to run in linear amortized - * time, but has a larger average cost, uses more memory and is patented. - * However the F&G algorithm may be faster for some highly redundant - * files if the parameter max_chain_length (described below) is too large. - * - * ACKNOWLEDGEMENTS - * - * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and - * I found it in 'freeze' written by Leonid Broukhis. - * Thanks to many info-zippers for bug reports and testing. - * - * REFERENCES - * - * APPNOTE.TXT documentation file in PKZIP 1.93a distribution. - * - * A description of the Rabin and Karp algorithm is given in the book - * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. - * - * Fiala,E.R., and Greene,D.H. - * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 - * - * INTERFACE - * - * void lm_init (int pack_level, ush *flags) - * Initialize the "longest match" routines for a new file - * - * ulg deflate (void) - * Processes a new input file and return its compressed length. Sets - * the compressed length, crc, deflate flags and internal file - * attributes. - */ - - -/* =========================================================================== - * Configuration parameters - */ - -/* Compile with MEDIUM_MEM to reduce the memory requirements or - * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the - * entire input file can be held in memory (not possible on 16 bit systems). - * Warning: defining these symbols affects HASH_BITS (see below) and thus - * affects the compression ratio. The compressed output - * is still correct, and might even be smaller in some cases. - */ - -#ifdef SMALL_MEM -# define HASH_BITS 13 /* Number of bits used to hash strings */ -#endif -#ifdef MEDIUM_MEM -# define HASH_BITS 14 -#endif -#ifndef HASH_BITS -# define HASH_BITS 15 - /* For portability to 16 bit machines, do not use values above 15. */ -#endif - -/* To save space (see unlzw.c), we overlay prev+head with tab_prefix and - * window with tab_suffix. Check that we can do this: - */ -#if (WSIZE<<1) > (1< BITS-1 -# error cannot overlay head with tab_prefix1 -#endif -#define HASH_SIZE (unsigned)(1<= HASH_BITS - */ - -static unsigned int prev_length; - -/* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - -static unsigned strstart; /* start of string to insert */ -static unsigned match_start; /* start of matching string */ -static int eofile; /* flag set at end of input file */ -static unsigned lookahead; /* number of valid bytes ahead in window */ - -static const unsigned max_chain_length=4096; - -/* To speed up deflation, hash chains are never searched beyond this length. - * A higher limit improves compression ratio but degrades the speed. - */ - -static const unsigned int max_lazy_match=258; - -/* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ -#define max_insert_length max_lazy_match -/* Insert new strings in the hash table only if the match length - * is not greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - -static const unsigned good_match=32; - -/* Use a faster search when the previous match is longer than this */ - - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ - -static const int nice_match=258; /* Stop searching when current match exceeds this */ - -/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 - * For deflate_fast() (levels <= 3) good is ignored and lazy has a different - * meaning. - */ - -#define EQUAL 0 -/* result of memcmp for equal strings */ - -/* =========================================================================== - * Prototypes for local functions. - */ -static void fill_window (void); - -static int longest_match (IPos cur_match); - -#ifdef DEBUG -static void check_match (IPos start, IPos match, int length); -#endif - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. - */ -#define UPDATE_HASH(h,c) (h = (((h)<= 1 - */ - -/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or - * match.s. The code is functionally equivalent, so you can use the C version - * if desired. - */ -static int longest_match(IPos cur_match) -{ - unsigned chain_length = max_chain_length; /* max hash chain length */ - register uch *scan = window + strstart; /* current string */ - register uch *match; /* matched string */ - register int len; /* length of current match */ - int best_len = prev_length; /* best match length so far */ - IPos limit = - - strstart > (IPos) MAX_DIST ? strstart - (IPos) MAX_DIST : NIL; - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - -/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ -#if HASH_BITS < 8 || MAX_MATCH != 258 -# error Code too clever -#endif - register uch *strend = window + strstart + MAX_MATCH; - register uch scan_end1 = scan[best_len - 1]; - register uch scan_end = scan[best_len]; - - /* Do not waste too much time if we already have a good match: */ - if (prev_length >= good_match) { - chain_length >>= 2; - } - Assert(strstart <= window_size - MIN_LOOKAHEAD, - "insufficient lookahead"); - - do { - Assert(cur_match < strstart, "no future"); - match = window + cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2: - */ - if (match[best_len] != scan_end || - match[best_len - 1] != scan_end1 || - *match != *scan || *++match != scan[1]) - continue; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match++; - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - len = MAX_MATCH - (int) (strend - scan); - scan = strend - MAX_MATCH; - - if (len > best_len) { - match_start = cur_match; - best_len = len; - if (len >= nice_match) - break; - scan_end1 = scan[best_len - 1]; - scan_end = scan[best_len]; - } - } while ((cur_match = prev[cur_match & WMASK]) > limit - && --chain_length != 0); - - return best_len; -} - -#ifdef DEBUG -/* =========================================================================== - * Check that the match at match_start is indeed a match. - */ -static void check_match(IPos start, IPos match, int length) -{ - /* check that the match is indeed a match */ - if (memcmp((char *) window + match, - (char *) window + start, length) != EQUAL) { - fprintf(stderr, - " start %d, match %d, length %d\n", start, match, length); - error_msg("invalid match"); - } - if (verbose > 1) { - fprintf(stderr, "\\[%d,%d]", start - match, length); - do { - putc(window[start++], stderr); - } while (--length != 0); - } -} -#else -# define check_match(start, match, length) -#endif - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead, and sets eofile if end of input file. - * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0 - * OUT assertions: at least one byte has been read, or eofile is set; - * file reads are performed for at least two bytes (required for the - * translate_eol option). - */ -static void fill_window() -{ - register unsigned n, m; - unsigned more = - - (unsigned) (window_size - (ulg) lookahead - (ulg) strstart); - /* Amount of free space at the end of the window. */ - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (more == (unsigned) EOF) { - /* Very unlikely, but possible on 16 bit machine if strstart == 0 - * and lookahead == 1 (input done one byte at time) - */ - more--; - } else if (strstart >= WSIZE + MAX_DIST) { - /* By the IN assertion, the window is not empty so we can't confuse - * more == 0 with more == 64K on a 16 bit machine. - */ - Assert(window_size == (ulg) 2 * WSIZE, "no sliding with BIG_MEM"); - - memcpy((char *) window, (char *) window + WSIZE, (unsigned) WSIZE); - match_start -= WSIZE; - strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */ - - block_start -= (long) WSIZE; - - for (n = 0; n < HASH_SIZE; n++) { - m = head[n]; - head[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL); - } - for (n = 0; n < WSIZE; n++) { - m = prev[n]; - prev[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } - more += WSIZE; - } - /* At this point, more >= 2 */ - if (!eofile) { - n = read_buf((char *) window + strstart + lookahead, more); - if (n == 0 || n == (unsigned) EOF) { - eofile = 1; - } else { - lookahead += n; - } - } -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK(eof) \ - flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \ - (char*)NULL, (long)strstart - block_start, (eof)) - -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -static ulg deflate() -{ - IPos hash_head; /* head of hash chain */ - IPos prev_match; /* previous match */ - int flush; /* set if current block must be flushed */ - int match_available = 0; /* set if previous match exists */ - register unsigned match_length = MIN_MATCH - 1; /* length of best match */ - - /* Process the input block. */ - while (lookahead != 0) { - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - INSERT_STRING(strstart, hash_head); - - /* Find the longest match, discarding those <= prev_length. - */ - prev_length = match_length, prev_match = match_start; - match_length = MIN_MATCH - 1; - - if (hash_head != NIL && prev_length < max_lazy_match && - strstart - hash_head <= MAX_DIST) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - match_length = longest_match(hash_head); - /* longest_match() sets match_start */ - if (match_length > lookahead) - match_length = lookahead; - - /* Ignore a length 3 match if it is too distant: */ - if (match_length == MIN_MATCH - && strstart - match_start > TOO_FAR) { - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - match_length--; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (prev_length >= MIN_MATCH && match_length <= prev_length) { - - check_match(strstart - 1, prev_match, prev_length); - - flush = - ct_tally(strstart - 1 - prev_match, - prev_length - MIN_MATCH); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. - */ - lookahead -= prev_length - 1; - prev_length -= 2; - do { - strstart++; - INSERT_STRING(strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH - * these bytes are garbage, but it does not matter since the - * next lookahead bytes will always be emitted as literals. - */ - } while (--prev_length != 0); - match_available = 0; - match_length = MIN_MATCH - 1; - strstart++; - if (flush) - FLUSH_BLOCK(0), block_start = strstart; - - } else if (match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - Tracevv((stderr, "%c", window[strstart - 1])); - if (ct_tally(0, window[strstart - 1])) { - FLUSH_BLOCK(0), block_start = strstart; - } - strstart++; - lookahead--; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - match_available = 1; - strstart++; - lookahead--; - } - Assert(strstart <= isize && lookahead <= isize, "a bit too far"); - - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - while (lookahead < MIN_LOOKAHEAD && !eofile) - fill_window(); - } - if (match_available) - ct_tally(0, window[strstart - 1]); - - return FLUSH_BLOCK(1); /* eof */ -} - -/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface - * Copyright (C) 1992-1993 Jean-loup Gailly - * The unzip code was written and put in the public domain by Mark Adler. - * Portions of the lzw code are derived from the public domain 'compress' - * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, - * Ken Turkowski, Dave Mack and Peter Jannesen. - * - * See the license_msg below and the file COPYING for the software license. - * See the file algorithm.doc for the compression algorithms and file formats. - */ - -/* Compress files with zip algorithm and 'compress' interface. - * See usage() and help() functions below for all options. - * Outputs: - * file.gz: compressed file with same mode, owner, and utimes - * or stdout with -c option or if stdin used as input. - * If the output file name had to be truncated, the original name is kept - * in the compressed file. - */ - - /* configuration */ - -typedef struct dirent dir_type; - -typedef RETSIGTYPE(*sig_type) (int); - - -/* ======================================================================== */ -// int main (argc, argv) -// int argc; -// char **argv; -int gzip_main(int argc, char **argv) -{ - int result; - int inFileNum; - int outFileNum; - struct stat statBuf; - char *delFileName; - int tostdout = 0; - int fromstdin = 0; - int force = 0; - int opt; - - while ((opt = getopt(argc, argv, "cf123456789dq")) != -1) { - switch (opt) { - case 'c': - tostdout = 1; - break; - case 'f': - force = 1; - break; - /* Ignore 1-9 (compression level) options */ - case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - break; - case 'q': - break; -#ifdef BB_GUNZIP - case 'd': - optind = 1; - return gunzip_main(argc, argv); -#endif - default: - show_usage(); - } - } - if ((optind == argc) || (strcmp(argv[optind], "-") == 0)) { - fromstdin = 1; - tostdout = 1; - } - - if (isatty(fileno(stdout)) && tostdout==1 && force==0) - error_msg_and_die( "compressed data not written to terminal. Use -f to force it."); - - foreground = signal(SIGINT, SIG_IGN) != SIG_IGN; - if (foreground) { - (void) signal(SIGINT, (sig_type) abort_gzip); - } -#ifdef SIGTERM - if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { - (void) signal(SIGTERM, (sig_type) abort_gzip); - } -#endif -#ifdef SIGHUP - if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { - (void) signal(SIGHUP, (sig_type) abort_gzip); - } -#endif - - strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix) - 1); - z_len = strlen(z_suffix); - - /* Allocate all global buffers (for DYN_ALLOC option) */ - ALLOC(uch, inbuf, INBUFSIZ + INBUF_EXTRA); - ALLOC(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA); - ALLOC(ush, d_buf, DIST_BUFSIZE); - ALLOC(uch, window, 2L * WSIZE); - ALLOC(ush, tab_prefix, 1L << BITS); - - if (fromstdin == 1) { - strcpy(ofname, "stdin"); - - inFileNum = fileno(stdin); - time_stamp = 0; /* time unknown by default */ - ifile_size = -1L; /* convention for unknown size */ - } else { - /* Open up the input file */ - strncpy(ifname, argv[optind], MAX_PATH_LEN); - - /* Open input file */ - inFileNum = open(ifname, O_RDONLY); - if (inFileNum < 0) - perror_msg_and_die("%s", ifname); - /* Get the time stamp on the input file. */ - if (stat(ifname, &statBuf) < 0) - perror_msg_and_die("%s", ifname); - time_stamp = statBuf.st_ctime; - ifile_size = statBuf.st_size; - } - - - if (tostdout == 1) { - /* And get to work */ - strcpy(ofname, "stdout"); - outFileNum = fileno(stdout); - - clear_bufs(); /* clear input and output buffers */ - part_nb = 0; - - /* Actually do the compression/decompression. */ - zip(inFileNum, outFileNum); - - } else { - - /* And get to work */ - strncpy(ofname, ifname, MAX_PATH_LEN - 4); - strcat(ofname, ".gz"); - - - /* Open output fille */ -#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) - outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW); -#else - outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL); -#endif - if (outFileNum < 0) - perror_msg_and_die("%s", ofname); - /* Set permissions on the file */ - fchmod(outFileNum, statBuf.st_mode); - - clear_bufs(); /* clear input and output buffers */ - part_nb = 0; - - /* Actually do the compression/decompression. */ - result = zip(inFileNum, outFileNum); - close(outFileNum); - close(inFileNum); - /* Delete the original file */ - if (result == OK) - delFileName = ifname; - else - delFileName = ofname; - - if (unlink(delFileName) < 0) - perror_msg_and_die("%s", delFileName); - } - - return(exit_code); -} - -/* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1992-1993 Jean-loup Gailly - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License, see the file COPYING. - */ - -/* - * PURPOSE - * - * Encode various sets of source values using variable-length - * binary code trees. - * - * DISCUSSION - * - * The PKZIP "deflation" process uses several Huffman trees. The more - * common source values are represented by shorter bit sequences. - * - * Each code tree is stored in the ZIP file in a compressed form - * which is itself a Huffman encoding of the lengths of - * all the code strings (in ascending order by source values). - * The actual code strings are reconstructed from the lengths in - * the UNZIP process, as described in the "application note" - * (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program. - * - * REFERENCES - * - * Lynch, Thomas J. - * Data Compression: Techniques and Applications, pp. 53-55. - * Lifetime Learning Publications, 1985. ISBN 0-534-03418-7. - * - * Storer, James A. - * Data Compression: Methods and Theory, pp. 49-50. - * Computer Science Press, 1988. ISBN 0-7167-8156-5. - * - * Sedgewick, R. - * Algorithms, p290. - * Addison-Wesley, 1983. ISBN 0-201-06672-6. - * - * INTERFACE - * - * void ct_init (ush *attr, int *methodp) - * Allocate the match buffer, initialize the various tables and save - * the location of the internal file attribute (ascii/binary) and - * method (DEFLATE/STORE) - * - * void ct_tally (int dist, int lc); - * Save the match info and tally the frequency counts. - * - * long flush_block (char *buf, ulg stored_len, int eof) - * Determine the best encoding for the current block: dynamic trees, - * static trees or store, and output the encoded block to the zip - * file. Returns the total compressed length for the file so far. - * - */ - -/* =========================================================================== - * Constants - */ - -#define MAX_BITS 15 -/* All codes must not exceed MAX_BITS bits */ - -#define MAX_BL_BITS 7 -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -#define LENGTH_CODES 29 -/* number of length codes, not counting the special END_BLOCK code */ - -#define LITERALS 256 -/* number of literal bytes 0..255 */ - -#define END_BLOCK 256 -/* end of block literal code */ - -#define L_CODES (LITERALS+1+LENGTH_CODES) -/* number of Literal or Length codes, including the END_BLOCK code */ - -#define D_CODES 30 -/* number of distance codes */ - -#define BL_CODES 19 -/* number of codes used to transfer the bit lengths */ - - -static const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ - = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, - 4, 4, 5, 5, 5, 5, 0 }; - -static const int extra_dbits[D_CODES] /* extra bits for each distance code */ - = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, - 10, 10, 11, 11, 12, 12, 13, 13 }; - -static const int extra_blbits[BL_CODES] /* extra bits for each bit length code */ -= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 }; - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#ifndef LIT_BUFSIZE -# ifdef SMALL_MEM -# define LIT_BUFSIZE 0x2000 -# else -# ifdef MEDIUM_MEM -# define LIT_BUFSIZE 0x4000 -# else -# define LIT_BUFSIZE 0x8000 -# endif -# endif -#endif -#ifndef DIST_BUFSIZE -# define DIST_BUFSIZE LIT_BUFSIZE -#endif -/* Sizes of match buffers for literals/lengths and distances. There are - * 4 reasons for limiting LIT_BUFSIZE to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input data is - * still in the window so we can still emit a stored block even when input - * comes from standard input. (This can also be done for all blocks if - * LIT_BUFSIZE is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting trees - * more frequently. - * - I can't count above 4 - * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save - * memory at the expense of compression). Some optimizations would be possible - * if we rely on DIST_BUFSIZE == LIT_BUFSIZE. - */ -#if LIT_BUFSIZE > INBUFSIZ -error cannot overlay l_buf and inbuf -#endif -#define REP_3_6 16 -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ -#define REPZ_3_10 17 -/* repeat a zero length 3-10 times (3 bits of repeat count) */ -#define REPZ_11_138 18 -/* repeat a zero length 11-138 times (7 bits of repeat count) *//* =========================================================================== - * Local data - *//* Data structure describing a single value and its code string. */ typedef struct ct_data { - union { - ush freq; /* frequency count */ - ush code; /* bit string */ - } fc; - union { - ush dad; /* father node in Huffman tree */ - ush len; /* length of bit string */ - } dl; -} ct_data; - -#define Freq fc.freq -#define Code fc.code -#define Dad dl.dad -#define Len dl.len - -#define HEAP_SIZE (2*L_CODES+1) -/* maximum heap size */ - -static ct_data dyn_ltree[HEAP_SIZE]; /* literal and length tree */ -static ct_data dyn_dtree[2 * D_CODES + 1]; /* distance tree */ - -static ct_data static_ltree[L_CODES + 2]; - -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see ct_init - * below). - */ - -static ct_data static_dtree[D_CODES]; - -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -static ct_data bl_tree[2 * BL_CODES + 1]; - -/* Huffman tree for the bit lengths */ - -typedef struct tree_desc { - ct_data *dyn_tree; /* the dynamic tree */ - ct_data *static_tree; /* corresponding static tree or NULL */ - const int *extra_bits; /* extra bits for each code or NULL */ - int extra_base; /* base index for extra_bits */ - int elems; /* max number of elements in the tree */ - int max_length; /* max bit length for the codes */ - int max_code; /* largest code with non zero frequency */ -} tree_desc; - -static tree_desc l_desc = - { dyn_ltree, static_ltree, extra_lbits, LITERALS + 1, L_CODES, - MAX_BITS, 0 }; - -static tree_desc d_desc = - { dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0 }; - -static tree_desc bl_desc = - { bl_tree, (ct_data *) 0, extra_blbits, 0, BL_CODES, MAX_BL_BITS, - 0 }; - - -static ush bl_count[MAX_BITS + 1]; - -/* number of codes at each bit length for an optimal tree */ - -static const uch bl_order[BL_CODES] -= { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -static int heap[2 * L_CODES + 1]; /* heap used to build the Huffman trees */ -static int heap_len; /* number of elements in the heap */ -static int heap_max; /* element of largest frequency */ - -/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - -static uch depth[2 * L_CODES + 1]; - -/* Depth of each subtree used as tie breaker for trees of equal frequency */ - -static uch length_code[MAX_MATCH - MIN_MATCH + 1]; - -/* length code for each normalized match length (0 == MIN_MATCH) */ - -static uch dist_code[512]; - -/* distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -static int base_length[LENGTH_CODES]; - -/* First normalized length for each code (0 = MIN_MATCH) */ - -static int base_dist[D_CODES]; - -/* First normalized distance for each code (0 = distance of 1) */ - -#define l_buf inbuf -/* DECLARE(uch, l_buf, LIT_BUFSIZE); buffer for literals or lengths */ - -/* DECLARE(ush, d_buf, DIST_BUFSIZE); buffer for distances */ - -static uch flag_buf[(LIT_BUFSIZE / 8)]; - -/* flag_buf is a bit array distinguishing literals from lengths in - * l_buf, thus indicating the presence or absence of a distance. - */ - -static unsigned last_lit; /* running index in l_buf */ -static unsigned last_dist; /* running index in d_buf */ -static unsigned last_flags; /* running index in flag_buf */ -static uch flags; /* current flags not yet saved in flag_buf */ -static uch flag_bit; /* current bit used in flags */ - -/* bits are filled in flags starting at bit 0 (least significant). - * Note: these flags are overkill in the current code since we don't - * take advantage of DIST_BUFSIZE == LIT_BUFSIZE. - */ - -static ulg opt_len; /* bit length of current block with optimal trees */ -static ulg static_len; /* bit length of current block with static trees */ - -static ulg compressed_len; /* total bit length of compressed file */ - - -static ush *file_type; /* pointer to UNKNOWN, BINARY or ASCII */ -static int *file_method; /* pointer to DEFLATE or STORE */ - -/* =========================================================================== - * Local (static) routines in this file. - */ - -static void init_block (void); -static void pqdownheap (ct_data * tree, int k); -static void gen_bitlen (tree_desc * desc); -static void gen_codes (ct_data * tree, int max_code); -static void build_tree (tree_desc * desc); -static void scan_tree (ct_data * tree, int max_code); -static void send_tree (ct_data * tree, int max_code); -static int build_bl_tree (void); -static void send_all_trees (int lcodes, int dcodes, int blcodes); -static void compress_block (ct_data * ltree, ct_data * dtree); -static void set_file_type (void); - - -#ifndef DEBUG -# define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len) - /* Send a code of the given tree. c and tree must not have side effects */ - -#else /* DEBUG */ -# define send_code(c, tree) \ - { if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \ - send_bits(tree[c].Code, tree[c].Len); } -#endif - -#define d_code(dist) \ - ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. dist_code[256] and dist_code[257] are never - * used. - */ - -/* the arguments must not have side effects */ - -/* =========================================================================== - * Allocate the match buffer, initialize the various tables and save the - * location of the internal file attribute (ascii/binary) and method - * (DEFLATE/STORE). - */ -static void ct_init(ush *attr, int *methodp) -{ - int n; /* iterates over tree elements */ - int bits; /* bit counter */ - int length; /* length value */ - int code; /* code value */ - int dist; /* distance index */ - - file_type = attr; - file_method = methodp; - compressed_len = 0L; - - if (static_dtree[0].Len != 0) - return; /* ct_init already called */ - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES - 1; code++) { - base_length[code] = length; - for (n = 0; n < (1 << extra_lbits[code]); n++) { - length_code[length++] = (uch) code; - } - } - Assert(length == 256, "ct_init: length != 256"); - /* Note that the length 255 (match length 258) can be represented - * in two different ways: code 284 + 5 bits or code 285, so we - * overwrite length_code[255] to use the best encoding: - */ - length_code[length - 1] = (uch) code; - - /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ - dist = 0; - for (code = 0; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1 << extra_dbits[code]); n++) { - dist_code[dist++] = (uch) code; - } - } - Assert(dist == 256, "ct_init: dist != 256"); - dist >>= 7; /* from now on, all distances are divided by 128 */ - for (; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { - dist_code[256 + dist++] = (uch) code; - } - } - Assert(dist == 256, "ct_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) - bl_count[bits] = 0; - n = 0; - while (n <= 143) - static_ltree[n++].Len = 8, bl_count[8]++; - while (n <= 255) - static_ltree[n++].Len = 9, bl_count[9]++; - while (n <= 279) - static_ltree[n++].Len = 7, bl_count[7]++; - while (n <= 287) - static_ltree[n++].Len = 8, bl_count[8]++; - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes((ct_data *) static_ltree, L_CODES + 1); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n].Len = 5; - static_dtree[n].Code = bi_reverse(n, 5); - } - - /* Initialize the first block of the first file: */ - init_block(); -} - -/* =========================================================================== - * Initialize a new block. - */ -static void init_block() -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) - dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) - dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) - bl_tree[n].Freq = 0; - - dyn_ltree[END_BLOCK].Freq = 1; - opt_len = static_len = 0L; - last_lit = last_dist = last_flags = 0; - flags = 0; - flag_bit = 1; -} - -#define SMALLEST 1 -/* Index within the heap array of least frequent node in the Huffman tree */ - - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. - */ -#define pqremove(tree, top) \ -{\ - top = heap[SMALLEST]; \ - heap[SMALLEST] = heap[heap_len--]; \ - pqdownheap(tree, SMALLEST); \ -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -#define smaller(tree, n, m) \ - (tree[n].Freq < tree[m].Freq || \ - (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -static void pqdownheap(ct_data *tree, int k) -{ - int v = heap[k]; - int j = k << 1; /* left son of k */ - - while (j <= heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < heap_len && smaller(tree, heap[j + 1], heap[j])) - j++; - - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, heap[j])) - break; - - /* Exchange v with the smallest son */ - heap[k] = heap[j]; - k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - heap[k] = v; -} - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -static void gen_bitlen(tree_desc *desc) -{ - ct_data *tree = desc->dyn_tree; - const int *extra = desc->extra_bits; - int base = desc->extra_base; - int max_code = desc->max_code; - int max_length = desc->max_length; - ct_data *stree = desc->static_tree; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) - bl_count[bits] = 0; - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[heap[heap_max]].Len = 0; /* root of the heap */ - - for (h = heap_max + 1; h < HEAP_SIZE; h++) { - n = heap[h]; - bits = tree[tree[n].Dad].Len + 1; - if (bits > max_length) - bits = max_length, overflow++; - tree[n].Len = (ush) bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) - continue; /* not a leaf node */ - - bl_count[bits]++; - xbits = 0; - if (n >= base) - xbits = extra[n - base]; - f = tree[n].Freq; - opt_len += (ulg) f *(bits + xbits); - - if (stree) - static_len += (ulg) f *(stree[n].Len + xbits); - } - if (overflow == 0) - return; - - Trace((stderr, "\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length - 1; - while (bl_count[bits] == 0) - bits--; - bl_count[bits]--; /* move one leaf down the tree */ - bl_count[bits + 1] += 2; /* move one overflow item as its brother */ - bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits != 0; bits--) { - n = bl_count[bits]; - while (n != 0) { - m = heap[--h]; - if (m > max_code) - continue; - if (tree[m].Len != (unsigned) bits) { - Trace( - (stderr, "code %d bits %d->%d\n", m, tree[m].Len, - bits)); - opt_len += - ((long) bits - - (long) tree[m].Len) * (long) tree[m].Freq; - tree[m].Len = (ush) bits; - } - n--; - } - } -} - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -static void gen_codes(ct_data *tree, int max_code) -{ - ush next_code[MAX_BITS + 1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits - 1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert(code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, - "inconsistent bit counts"); - Tracev((stderr, "\ngen_codes: max_code %d ", max_code)); - - for (n = 0; n <= max_code; n++) { - int len = tree[n].Len; - - if (len == 0) - continue; - /* Now reverse the bits */ - tree[n].Code = bi_reverse(next_code[len]++, len); - - Tracec(tree != static_ltree, - (stderr, "\nn %3d %c l %2d c %4x (%x) ", n, - (isgraph(n) ? n : ' '), len, tree[n].Code, - next_code[len] - 1)); - } -} - -/* =========================================================================== - * Construct one Huffman tree and assigns the code bit strings and lengths. - * Update the total bit length for the current block. - * IN assertion: the field freq is set for all tree elements. - * OUT assertions: the fields len and code are set to the optimal bit length - * and corresponding code. The length opt_len is updated; static_len is - * also updated if stree is not null. The field max_code is set. - */ -static void build_tree(tree_desc *desc) -{ - ct_data *tree = desc->dyn_tree; - ct_data *stree = desc->static_tree; - int elems = desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node = elems; /* next internal node of the tree */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - heap_len = 0, heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].Freq != 0) { - heap[++heap_len] = max_code = n; - depth[n] = 0; - } else { - tree[n].Len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (heap_len < 2) { - int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0); - - tree[new].Freq = 1; - depth[new] = 0; - opt_len--; - if (stree) - static_len -= stree[new].Len; - /* new is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = heap_len / 2; n >= 1; n--) - pqdownheap(tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - do { - pqremove(tree, n); /* n = node of least frequency */ - m = heap[SMALLEST]; /* m = node of next least frequency */ - - heap[--heap_max] = n; /* keep the nodes sorted by frequency */ - heap[--heap_max] = m; - - /* Create a new node father of n and m */ - tree[node].Freq = tree[n].Freq + tree[m].Freq; - depth[node] = (uch) (MAX(depth[n], depth[m]) + 1); - tree[n].Dad = tree[m].Dad = (ush) node; -#ifdef DUMP_BL_TREE - if (tree == bl_tree) { - fprintf(stderr, "\nnode %d(%d), sons %d(%d) %d(%d)", - node, tree[node].Freq, n, tree[n].Freq, m, - tree[m].Freq); - } -#endif - /* and insert the new node in the heap */ - heap[SMALLEST] = node++; - pqdownheap(tree, SMALLEST); - - } while (heap_len >= 2); - - heap[--heap_max] = heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen((tree_desc *) desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes((ct_data *) tree, max_code); -} - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. Updates opt_len to take into account the repeat - * counts. (The contribution of the bit length codes will be added later - * during the construction of bl_tree.) - */ -static void scan_tree(ct_data *tree, int max_code) -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - if (nextlen == 0) - max_count = 138, min_count = 3; - tree[max_code + 1].Len = (ush) 0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[n + 1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - bl_tree[curlen].Freq += count; - } else if (curlen != 0) { - if (curlen != prevlen) - bl_tree[curlen].Freq++; - bl_tree[REP_3_6].Freq++; - } else if (count <= 10) { - bl_tree[REPZ_3_10].Freq++; - } else { - bl_tree[REPZ_11_138].Freq++; - } - count = 0; - prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -static void send_tree(ct_data *tree, int max_code) -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - -/* tree[max_code+1].Len = -1; *//* guard already set */ - if (nextlen == 0) - max_count = 138, min_count = 3; - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[n + 1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - do { - send_code(curlen, bl_tree); - } while (--count != 0); - - } else if (curlen != 0) { - if (curlen != prevlen) { - send_code(curlen, bl_tree); - count--; - } - Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(REP_3_6, bl_tree); - send_bits(count - 3, 2); - - } else if (count <= 10) { - send_code(REPZ_3_10, bl_tree); - send_bits(count - 3, 3); - - } else { - send_code(REPZ_11_138, bl_tree); - send_bits(count - 11, 7); - } - count = 0; - prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -static const int build_bl_tree() -{ - int max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree((ct_data *) dyn_ltree, l_desc.max_code); - scan_tree((ct_data *) dyn_dtree, d_desc.max_code); - - /* Build the bit length tree: */ - build_tree((tree_desc *) (&bl_desc)); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) { - if (bl_tree[bl_order[max_blindex]].Len != 0) - break; - } - /* Update opt_len to include the bit length tree and counts */ - opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; - Tracev( - (stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len, - static_len)); - - return max_blindex; -} - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -static void send_all_trees(int lcodes, int dcodes, int blcodes) -{ - int rank; /* index in bl_order */ - - Assert(lcodes >= 257 && dcodes >= 1 - && blcodes >= 4, "not enough codes"); - Assert(lcodes <= L_CODES && dcodes <= D_CODES - && blcodes <= BL_CODES, "too many codes"); - Tracev((stderr, "\nbl counts: ")); - send_bits(lcodes - 257, 5); /* not +255 as stated in appnote.txt */ - send_bits(dcodes - 1, 5); - send_bits(blcodes - 4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(bl_tree[bl_order[rank]].Len, 3); - } - Tracev((stderr, "\nbl tree: sent %ld", bits_sent)); - - send_tree((ct_data *) dyn_ltree, lcodes - 1); /* send the literal tree */ - Tracev((stderr, "\nlit tree: sent %ld", bits_sent)); - - send_tree((ct_data *) dyn_dtree, dcodes - 1); /* send the distance tree */ - Tracev((stderr, "\ndist tree: sent %ld", bits_sent)); -} - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. This function - * returns the total compressed length for the file so far. - */ -static ulg flush_block(char *buf, ulg stored_len, int eof) -{ - ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - int max_blindex; /* index of last bit length code of non zero freq */ - - flag_buf[last_flags] = flags; /* Save the flags for the last 8 items */ - - /* Check if the file is ascii or binary */ - if (*file_type == (ush) UNKNOWN) - set_file_type(); - - /* Construct the literal and distance trees */ - build_tree((tree_desc *) (&l_desc)); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len)); - - build_tree((tree_desc *) (&d_desc)); - Tracev( - (stderr, "\ndist data: dyn %ld, stat %ld", opt_len, - static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(); - - /* Determine the best encoding. Compute first the block length in bytes */ - opt_lenb = (opt_len + 3 + 7) >> 3; - static_lenb = (static_len + 3 + 7) >> 3; - - Trace( - (stderr, - "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ", - opt_lenb, opt_len, static_lenb, static_len, stored_len, - last_lit, last_dist)); - - if (static_lenb <= opt_lenb) - opt_lenb = static_lenb; - - /* If compression failed and this is the first and last block, - * and if the zip file can be seeked (to rewrite the local header), - * the whole file is transformed into a stored file: - */ - if (stored_len <= opt_lenb && eof && compressed_len == 0L - && seekable()) { - /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */ - if (buf == (char *) 0) - error_msg("block vanished"); - - copy_block(buf, (unsigned) stored_len, 0); /* without header */ - compressed_len = stored_len << 3; - *file_method = STORED; - - } else if (stored_len + 4 <= opt_lenb && buf != (char *) 0) { - /* 4: two words for the lengths */ - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - send_bits((STORED_BLOCK << 1) + eof, 3); /* send block type */ - compressed_len = (compressed_len + 3 + 7) & ~7L; - compressed_len += (stored_len + 4) << 3; - - copy_block(buf, (unsigned) stored_len, 1); /* with header */ - - } else if (static_lenb == opt_lenb) { - send_bits((STATIC_TREES << 1) + eof, 3); - compress_block((ct_data *) static_ltree, - (ct_data *) static_dtree); - compressed_len += 3 + static_len; - } else { - send_bits((DYN_TREES << 1) + eof, 3); - send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1, - max_blindex + 1); - compress_block((ct_data *) dyn_ltree, - (ct_data *) dyn_dtree); - compressed_len += 3 + opt_len; - } - Assert(compressed_len == bits_sent, "bad compressed size"); - init_block(); - - if (eof) { - bi_windup(); - compressed_len += 7; /* align on byte boundary */ - } - Tracev((stderr, "\ncomprlen %lu(%lu) ", compressed_len >> 3, - compressed_len - 7 * eof)); - - return compressed_len >> 3; -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -static int ct_tally(int dist, int lc) -{ - l_buf[last_lit++] = (uch) lc; - if (dist == 0) { - /* lc is the unmatched char */ - dyn_ltree[lc].Freq++; - } else { - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - Assert((ush) dist < (ush) MAX_DIST && - (ush) lc <= (ush) (MAX_MATCH - MIN_MATCH) && - (ush) d_code(dist) < (ush) D_CODES, "ct_tally: bad match"); - - dyn_ltree[length_code[lc] + LITERALS + 1].Freq++; - dyn_dtree[d_code(dist)].Freq++; - - d_buf[last_dist++] = (ush) dist; - flags |= flag_bit; - } - flag_bit <<= 1; - - /* Output the flags if they fill a byte: */ - if ((last_lit & 7) == 0) { - flag_buf[last_flags++] = flags; - flags = 0, flag_bit = 1; - } - /* Try to guess if it is profitable to stop the current block here */ - if ((last_lit & 0xfff) == 0) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg) last_lit * 8L; - ulg in_length = (ulg) strstart - block_start; - int dcode; - - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += - (ulg) dyn_dtree[dcode].Freq * (5L + extra_dbits[dcode]); - } - out_length >>= 3; - Trace( - (stderr, - "\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ", - last_lit, last_dist, in_length, out_length, - 100L - out_length * 100L / in_length)); - if (last_dist < last_lit / 2 && out_length < in_length / 2) - return 1; - } - return (last_lit == LIT_BUFSIZE - 1 || last_dist == DIST_BUFSIZE); - /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -static void compress_block(ct_data *ltree, ct_data *dtree) -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned dx = 0; /* running index in d_buf */ - unsigned fx = 0; /* running index in flag_buf */ - uch flag = 0; /* current flags */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (last_lit != 0) - do { - if ((lx & 7) == 0) - flag = flag_buf[fx++]; - lc = l_buf[lx++]; - if ((flag & 1) == 0) { - send_code(lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr, " '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = length_code[lc]; - send_code(code + LITERALS + 1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(lc, extra); /* send the extra length bits */ - } - dist = d_buf[dx++]; - /* Here, dist is the match distance - 1 */ - code = d_code(dist); - Assert(code < D_CODES, "bad d_code"); - - send_code(code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= base_dist[code]; - send_bits(dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - flag >>= 1; - } while (lx < last_lit); - - send_code(END_BLOCK, ltree); -} - -/* =========================================================================== - * Set the file type to ASCII or BINARY, using a crude approximation: - * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - * IN assertion: the fields freq of dyn_ltree are set and the total of all - * frequencies does not exceed 64K (to fit in an int on 16 bit machines). - */ -static void set_file_type() -{ - int n = 0; - unsigned ascii_freq = 0; - unsigned bin_freq = 0; - - while (n < 7) - bin_freq += dyn_ltree[n++].Freq; - while (n < 128) - ascii_freq += dyn_ltree[n++].Freq; - while (n < LITERALS) - bin_freq += dyn_ltree[n++].Freq; - *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII; - if (*file_type == BINARY && translate_eol) { - error_msg("-l used on binary file"); - } -} - -/* zip.c -- compress files to the gzip or pkzip format - * Copyright (C) 1992-1993 Jean-loup Gailly - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License, see the file COPYING. - */ - - -static ulg crc; /* crc on uncompressed file data */ -static long header_bytes; /* number of bytes in gzip header */ - -/* =========================================================================== - * Deflate in to out. - * IN assertions: the input and output buffers are cleared. - * The variables time_stamp and save_orig_name are initialized. - */ -static int zip(int in, int out) -{ - uch my_flags = 0; /* general purpose bit flags */ - ush attr = 0; /* ascii/binary flag */ - ush deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */ - - ifd = in; - ofd = out; - outcnt = 0; - - /* Write the header to the gzip file. See algorithm.doc for the format */ - - - method = DEFLATED; - put_byte(GZIP_MAGIC[0]); /* magic header */ - put_byte(GZIP_MAGIC[1]); - put_byte(DEFLATED); /* compression method */ - - put_byte(my_flags); /* general flags */ - put_long(time_stamp); - - /* Write deflated file to zip file */ - crc = updcrc(0, 0); - - bi_init(out); - ct_init(&attr, &method); - lm_init(&deflate_flags); - - put_byte((uch) deflate_flags); /* extra flags */ - put_byte(OS_CODE); /* OS identifier */ - - header_bytes = (long) outcnt; - - (void) deflate(); - - /* Write the crc and uncompressed size */ - put_long(crc); - put_long(isize); - header_bytes += 2 * sizeof(long); - - flush_outbuf(); - return OK; -} - - -/* =========================================================================== - * Read a new buffer from the current input file, perform end-of-line - * translation, and update the crc and input file size. - * IN assertion: size >= 2 (for end-of-line translation) - */ -static int file_read(char *buf, unsigned size) -{ - unsigned len; - - Assert(insize == 0, "inbuf not empty"); - - len = read(ifd, buf, size); - if (len == (unsigned) (-1) || len == 0) - return (int) len; - - crc = updcrc((uch *) buf, len); - isize += (ulg) len; - return (int) len; -} - -/* =========================================================================== - * Write the output buffer outbuf[0..outcnt-1] and update bytes_out. - * (used for the compressed data only) - */ -static void flush_outbuf() -{ - if (outcnt == 0) - return; - - write_buf(ofd, (char *) outbuf, outcnt); - outcnt = 0; -} diff --git a/busybox/archival/libunarchive/decompress_unzip.c b/busybox/archival/libunarchive/decompress_unzip.c deleted file mode 100644 index ee746216d..000000000 --- a/busybox/archival/libunarchive/decompress_unzip.c +++ /dev/null @@ -1,1026 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * gunzip implementation for busybox - * - * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly. - * - * Originally adjusted for busybox by Sven Rudolph - * based on gzip sources - * - * Adjusted further by Erik Andersen , - * to support files as well as stdin/stdout, and to generally behave itself wrt - * command line handling. - * - * General cleanup to better adhere to the style guide and make use of standard - * busybox functions by 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 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 - * - * - * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface - * Copyright (C) 1992-1993 Jean-loup Gailly - * The unzip code was written and put in the public domain by Mark Adler. - * Portions of the lzw code are derived from the public domain 'compress' - * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, - * Ken Turkowski, Dave Mack and Peter Jannesen. - * - * See the license_msg below and the file COPYING for the software license. - * See the file algorithm.doc for the compression algorithms and file formats. - */ - -#if 0 -static char *license_msg[] = { - " Copyright (C) 1992-1993 Jean-loup Gailly", - " 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., 675 Mass Ave, Cambridge, MA 02139, USA.", - 0 -}; -#endif - -#include -#include -#include -#include -#include -#include "libbb.h" - -static FILE *in_file, *out_file; - -/* these are freed by gz_close */ -static unsigned char *window; -static unsigned long *crc_table; - -static unsigned long crc = 0xffffffffL; /* shift register contents */ - -/* Return codes from gzip */ -static const int ERROR = 1; - -/* - * window size--must be a power of two, and - * at least 32K for zip's deflate method - */ -static const int WSIZE = 0x8000; - -/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ -static const int BMAX = 16; /* maximum bit length of any code (16 for explode) */ -static const int N_MAX = 288; /* maximum number of codes in any set */ - -static long bytes_out; /* number of output bytes */ -static unsigned long outcnt; /* bytes in output buffer */ - -static unsigned hufts; /* track memory usage */ -static unsigned long bb; /* bit buffer */ -static unsigned bk; /* bits in bit buffer */ - -typedef struct huft_s { - unsigned char e; /* number of extra bits or operation */ - unsigned char b; /* number of bits in this code or subcode */ - union { - unsigned short n; /* literal, length base, or distance base */ - struct huft_s *t; /* pointer to next level of table */ - } v; -} huft_t; - -static const unsigned short mask_bits[] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - -//static int error_number = 0; -/* ======================================================================== - * Signal and error handler. - */ - -static void abort_gzip() -{ - error_msg("gzip aborted\n"); - exit(ERROR); -} - -static void make_crc_table() -{ - unsigned long table_entry; /* crc shift register */ - unsigned long poly = 0; /* polynomial exclusive-or pattern */ - int i; /* counter for all possible eight bit values */ - int k; /* byte being shifted into crc apparatus */ - - /* terms of polynomial defining this crc (except x^32): */ - static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - crc_table = (unsigned long *) malloc(256 * sizeof(unsigned long)); - - /* Make exclusive-or pattern from polynomial (0xedb88320) */ - for (i = 0; i < sizeof(p)/sizeof(int); i++) - poly |= 1L << (31 - p[i]); - - /* Compute and print table of CRC's, five per line */ - for (i = 0; i < 256; i++) { - table_entry = i; - /* The idea to initialize the register with the byte instead of - * zero was stolen from Haruhiko Okumura's ar002 - */ - for (k = 8; k; k--) { - table_entry = table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> 1; - } - crc_table[i]=table_entry; - } -} - -/* =========================================================================== - * Write the output window window[0..outcnt-1] and update crc and bytes_out. - * (Used for the decompressed data only.) - */ -static void flush_window(void) -{ - int n; - - if (outcnt == 0) - return; - - for (n = 0; n < outcnt; n++) { - crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8); - } - - if (fwrite(window, 1, outcnt, out_file) != outcnt) { - error_msg_and_die("Couldnt write"); - } - bytes_out += (unsigned long) outcnt; - outcnt = 0; -} - -/* - * Free the malloc'ed tables built by huft_build(), which makes a linked - * list of the tables it made, with the links in a dummy first entry of - * each table. - * t: table to free - */ -static int huft_free(huft_t *t) -{ - huft_t *p, *q; - - /* Go through linked list, freeing from the malloced (t[-1]) address. */ - p = t; - while (p != (huft_t *) NULL) { - q = (--p)->v.t; - free((char *) p); - p = q; - } - return 0; -} - -/* Given a list of code lengths and a maximum table size, make a set of - * tables to decode that set of codes. Return zero on success, one if - * the given code set is incomplete (the tables are still built in this - * case), two if the input is invalid (all zero length codes or an - * oversubscribed set of lengths), and three if not enough memory. - * - * b: code lengths in bits (all assumed <= BMAX) - * n: number of codes (assumed <= N_MAX) - * s: number of simple-valued codes (0..s-1) - * d: list of base values for non-simple codes - * e: list of extra bits for non-simple codes - * t: result: starting table - * m: maximum lookup bits, returns actual - */ -static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s, - const unsigned short *d, const unsigned short *e, huft_t **t, int *m) -{ - unsigned a; /* counter for codes of length k */ - unsigned c[BMAX + 1]; /* bit length count table */ - unsigned f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int h; /* table level */ - register unsigned i; /* counter, current code */ - register unsigned j; /* counter */ - register int k; /* number of bits in current code */ - int l; /* bits per table (returned in m) */ - register unsigned *p; /* pointer into c[], b[], or v[] */ - register huft_t *q; /* points to current table */ - huft_t r; /* table entry for structure assignment */ - huft_t *u[BMAX]; /* table stack */ - unsigned v[N_MAX]; /* values in order of bit length */ - register int w; /* bits before this table == (l * h) */ - unsigned x[BMAX + 1]; /* bit offsets, then code stack */ - unsigned *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - unsigned z; /* number of entries in current table */ - - /* Generate counts for each bit length */ - memset ((void *)(c), 0, sizeof(c)); - p = b; - i = n; - do { - c[*p]++; /* assume all entries <= BMAX */ - p++; /* Can't combine with above line (Solaris bug) */ - } while (--i); - if (c[0] == n) { /* null input--all zero length codes */ - *t = (huft_t *) NULL; - *m = 0; - return 0; - } - - /* Find minimum and maximum length, bound *m by those */ - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; /* minimum code length */ - if ((unsigned) l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; /* maximum code length */ - if ((unsigned) l > i) - l = i; - *m = l; - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return 2; /* bad input: more codes than bits */ - if ((y -= c[i]) < 0) - return 2; - c[i] += y; - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; - xp = x + 2; - while (--i) { /* note that i == g from above */ - *xp++ = (j += *p++); - } - - /* Make a table of values in order of bit lengths */ - p = b; - i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = -l; /* bits decoded == (l * h) */ - u[0] = (huft_t *) NULL; /* just to keep compilers happy */ - q = (huft_t *) NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) { - a = c[k]; - while (a--) { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l) { - h++; - w += l; /* previous table always l bits */ - - /* compute minimum size table less than or equal to l bits */ - z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */ - if ((f = 1 << (j = k - w)) > a + 1) { /* try a k-w bit table *//* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - while (++j < z) { /* try smaller tables up to z bits */ - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } - } - z = 1 << j; /* table entries for j-bit table */ - - /* allocate and link in new table */ - if ((q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t))) == NULL) { - if (h) { - huft_free(u[0]); - } - return 3; /* not enough memory */ - } - hufts += z + 1; /* track memory usage */ - *t = q + 1; /* link to list for huft_free() */ - *(t = &(q->v.t)) = NULL; - u[h] = ++q; /* table starts after link */ - - /* connect to last table, if there is one */ - if (h) { - x[h] = i; /* save pattern for backing up */ - r.b = (unsigned char) l; /* bits to dump before this table */ - r.e = (unsigned char) (16 + j); /* bits in this table */ - r.v.t = q; /* pointer to this table */ - j = i >> (w - l); /* (get around Turbo C bug) */ - u[h - 1][j] = r; /* connect to last table */ - } - } - - /* set up table entry in r */ - r.b = (unsigned char) (k - w); - if (p >= v + n) - r.e = 99; /* out of values--invalid code */ - else if (*p < s) { - r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ - r.v.n = (unsigned short) (*p); /* simple code is just the value */ - p++; /* one compiler does not like *p++ */ - } else { - r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ - r.v.n = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - while ((i & ((1 << w) - 1)) != x[h]) { - h--; /* don't need to update q */ - w -= l; - } - } - } - /* Return true (1) if we were given an incomplete table */ - return y != 0 && g != 1; -} - -/* - * inflate (decompress) the codes in a deflated (compressed) block. - * Return an error code or zero if it all goes ok. - * - * tl, td: literal/length and distance decoder tables - * bl, bd: number of bits decoded by tl[] and td[] - */ -static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd) -{ - register unsigned long e; /* table entry flag/number of extra bits */ - unsigned long n, d; /* length and index for copy */ - unsigned long w; /* current window position */ - huft_t *t; /* pointer to table entry */ - unsigned ml, md; /* masks for bl and bd bits */ - register unsigned long b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ - - /* make local copies of globals */ - b = bb; /* initialize bit buffer */ - k = bk; - w = outcnt; /* initialize window position */ - - /* inflate the coded data */ - ml = mask_bits[bl]; /* precompute masks for speed */ - md = mask_bits[bd]; - for (;;) { /* do until end of block */ - while (k < (unsigned) bl) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) - do { - if (e == 99) { - return 1; - } - b >>= t->b; - k -= t->b; - e -= 16; - while (k < e) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); - b >>= t->b; - k -= t->b; - if (e == 16) { /* then it's a literal */ - window[w++] = (unsigned char) t->v.n; - if (w == WSIZE) { - outcnt=(w), - flush_window(); - w = 0; - } - } else { /* it's an EOB or a length */ - - /* exit if end of block */ - if (e == 15) { - break; - } - - /* get length of block to copy */ - while (k < e) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - n = t->v.n + ((unsigned) b & mask_bits[e]); - b >>= e; - k -= e; - - /* decode distance of block to copy */ - while (k < (unsigned) bd) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - - if ((e = (t = td + ((unsigned) b & md))->e) > 16) - do { - if (e == 99) - return 1; - b >>= t->b; - k -= t->b; - e -= 16; - while (k < e) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); - b >>= t->b; - k -= t->b; - while (k < e) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - d = w - t->v.n - ((unsigned) b & mask_bits[e]); - b >>= e; - k -= e; - - /* do the copy */ - do { - n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e); -#if !defined(NOMEMCPY) && !defined(DEBUG) - if (w - d >= e) { /* (this test assumes unsigned comparison) */ - memcpy(window + w, window + d, e); - w += e; - d += e; - } else /* do it slow to avoid memcpy() overlap */ -#endif /* !NOMEMCPY */ - do { - window[w++] = window[d++]; - } while (--e); - if (w == WSIZE) { - outcnt=(w), - flush_window(); - w = 0; - } - } while (n); - } - } - - /* restore the globals from the locals */ - outcnt = w; /* restore global window pointer */ - bb = b; /* restore global bit buffer */ - bk = k; - - /* done */ - return 0; -} - -/* - * decompress an inflated block - * e: last block flag - * - * GLOBAL VARIABLES: bb, kk, - */ -static int inflate_block(int *e) -{ - unsigned t; /* block type */ - register unsigned long b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ - static unsigned short cplens[] = { /* Copy lengths for literal codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 - }; - /* note: see note #13 above about the 258 in this list. */ - static unsigned short cplext[] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 - }; /* 99==invalid */ - static unsigned short cpdist[] = { /* Copy offsets for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577 - }; - static unsigned short cpdext[] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13 - }; - - /* make local bit buffer */ - b = bb; - k = bk; - - /* read in last block bit */ - while (k < 1) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - *e = (int) b & 1; - b >>= 1; - k -= 1; - - /* read in block type */ - while (k < 2) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - t = (unsigned) b & 3; - b >>= 2; - k -= 2; - - /* restore the global bit buffer */ - bb = b; - bk = k; - - /* inflate that block type */ - switch (t) { - case 0: /* Inflate stored */ - { - unsigned long n; /* number of bytes in block */ - unsigned long w; /* current window position */ - register unsigned long b_stored; /* bit buffer */ - register unsigned long k_stored; /* number of bits in bit buffer */ - - /* make local copies of globals */ - b_stored = bb; /* initialize bit buffer */ - k_stored = bk; - w = outcnt; /* initialize window position */ - - /* go to byte boundary */ - n = k_stored & 7; - b_stored >>= n; - k_stored -= n; - - /* get the length and its complement */ - while (k_stored < 16) { - b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; - k_stored += 8; - } - n = ((unsigned) b_stored & 0xffff); - b_stored >>= 16; - k_stored -= 16; - while (k_stored < 16) { - b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; - k_stored += 8; - } - if (n != (unsigned) ((~b_stored) & 0xffff)) { - return 1; /* error in compressed data */ - } - b_stored >>= 16; - k_stored -= 16; - - /* read and output the compressed data */ - while (n--) { - while (k_stored < 8) { - b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; - k_stored += 8; - } - window[w++] = (unsigned char) b_stored; - if (w == (unsigned long)WSIZE) { - outcnt=(w), - flush_window(); - w = 0; - } - b_stored >>= 8; - k_stored -= 8; - } - - /* restore the globals from the locals */ - outcnt = w; /* restore global window pointer */ - bb = b_stored; /* restore global bit buffer */ - bk = k_stored; - return 0; - } - case 1: /* Inflate fixed - * decompress an inflated type 1 (fixed Huffman codes) block. We should - * either replace this with a custom decoder, or at least precompute the - * Huffman tables. - */ - { - int i; /* temporary variable */ - huft_t *tl; /* literal/length code table */ - huft_t *td; /* distance code table */ - int bl; /* lookup bits for tl */ - int bd; /* lookup bits for td */ - unsigned int l[288]; /* length list for huft_build */ - - /* set up literal table */ - for (i = 0; i < 144; i++) { - l[i] = 8; - } - for (; i < 256; i++) { - l[i] = 9; - } - for (; i < 280; i++) { - l[i] = 7; - } - for (; i < 288; i++) { /* make a complete, but wrong code set */ - l[i] = 8; - } - bl = 7; - if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) { - return i; - } - - /* set up distance table */ - for (i = 0; i < 30; i++) { /* make an incomplete code set */ - l[i] = 5; - } - bd = 5; - if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) { - huft_free(tl); - return i; - } - - /* decompress until an end-of-block code */ - if (inflate_codes(tl, td, bl, bd)) - return 1; - - /* free the decoding tables, return */ - huft_free(tl); - huft_free(td); - return 0; - } - case 2: /* Inflate dynamic */ - { - /* Tables for deflate from PKZIP's appnote.txt. */ - static unsigned border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 - }; - int dbits = 6; /* bits in base distance lookup table */ - int lbits = 9; /* bits in base literal/length lookup table */ - - int i; /* temporary variables */ - unsigned j; - unsigned l; /* last length */ - unsigned m; /* mask for bit lengths table */ - unsigned n; /* number of lengths to get */ - huft_t *tl; /* literal/length code table */ - huft_t *td; /* distance code table */ - int bl; /* lookup bits for tl */ - int bd; /* lookup bits for td */ - unsigned nb; /* number of bit length codes */ - unsigned nl; /* number of literal/length codes */ - unsigned nd; /* number of distance codes */ - - unsigned ll[286 + 30]; /* literal/length and distance code lengths */ - register unsigned long b_dynamic; /* bit buffer */ - register unsigned k_dynamic; /* number of bits in bit buffer */ - - /* make local bit buffer */ - b_dynamic = bb; - k_dynamic = bk; - - /* read in table lengths */ - while (k_dynamic < 5) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ - b_dynamic >>= 5; - k_dynamic -= 5; - while (k_dynamic < 5) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ - b_dynamic >>= 5; - k_dynamic -= 5; - while (k_dynamic < 4) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ - b_dynamic >>= 4; - k_dynamic -= 4; - if (nl > 286 || nd > 30) { - return 1; /* bad lengths */ - } - - /* read in bit-length-code lengths */ - for (j = 0; j < nb; j++) { - while (k_dynamic < 3) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - ll[border[j]] = (unsigned) b_dynamic & 7; - b_dynamic >>= 3; - k_dynamic -= 3; - } - for (; j < 19; j++) { - ll[border[j]] = 0; - } - - /* build decoding table for trees--single level, 7 bit lookup */ - bl = 7; - if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) { - if (i == 1) { - huft_free(tl); - } - return i; /* incomplete code set */ - } - - /* read in literal and distance code lengths */ - n = nl + nd; - m = mask_bits[bl]; - i = l = 0; - while ((unsigned) i < n) { - while (k_dynamic < (unsigned) bl) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - j = (td = tl + ((unsigned) b_dynamic & m))->b; - b_dynamic >>= j; - k_dynamic -= j; - j = td->v.n; - if (j < 16) { /* length of code in bits (0..15) */ - ll[i++] = l = j; /* save last length in l */ - } - else if (j == 16) { /* repeat last length 3 to 6 times */ - while (k_dynamic < 2) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - j = 3 + ((unsigned) b_dynamic & 3); - b_dynamic >>= 2; - k_dynamic -= 2; - if ((unsigned) i + j > n) { - return 1; - } - while (j--) { - ll[i++] = l; - } - } else if (j == 17) { /* 3 to 10 zero length codes */ - while (k_dynamic < 3) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - j = 3 + ((unsigned) b_dynamic & 7); - b_dynamic >>= 3; - k_dynamic -= 3; - if ((unsigned) i + j > n) { - return 1; - } - while (j--) { - ll[i++] = 0; - } - l = 0; - } else { /* j == 18: 11 to 138 zero length codes */ - while (k_dynamic < 7) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - j = 11 + ((unsigned) b_dynamic & 0x7f); - b_dynamic >>= 7; - k_dynamic -= 7; - if ((unsigned) i + j > n) { - return 1; - } - while (j--) { - ll[i++] = 0; - } - l = 0; - } - } - - /* free decoding table for trees */ - huft_free(tl); - - /* restore the global bit buffer */ - bb = b_dynamic; - bk = k_dynamic; - - /* build the decoding tables for literal/length and distance codes */ - bl = lbits; - if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) { - if (i == 1) { - error_msg("Incomplete literal tree"); - huft_free(tl); - } - return i; /* incomplete code set */ - } - bd = dbits; - if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { - if (i == 1) { - error_msg("incomplete distance tree"); - huft_free(td); - } - huft_free(tl); - return i; /* incomplete code set */ - } - - /* decompress until an end-of-block code */ - if (inflate_codes(tl, td, bl, bd)) - return 1; - - /* free the decoding tables, return */ - huft_free(tl); - huft_free(td); - return 0; - } - default: - /* bad block type */ - return 2; - } -} - -/* - * decompress an inflated entry - * - * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr - */ -static int inflate() -{ - int e; /* last block flag */ - int r; /* result code */ - unsigned h = 0; /* maximum struct huft's malloc'ed */ - - /* initialize window, bit buffer */ - outcnt = 0; - bk = 0; - bb = 0; - - /* decompress until the last block */ - do { - hufts = 0; - if ((r = inflate_block(&e)) != 0) { - return r; - } - if (hufts > h) { - h = hufts; - } - } while (!e); - - /* flush out window */ - flush_window(); - - /* return success */ - return 0; -} - -/* =========================================================================== - * Unzip in to out. This routine works on both gzip and pkzip files. - * - * IN assertions: the buffer inbuf contains already the beginning of - * the compressed data, from offsets inptr to insize-1 included. - * The magic header has already been checked. The output buffer is cleared. - * in, out: input and output file descriptors - */ -extern int unzip(FILE *l_in_file, FILE *l_out_file) -{ - const int extra_field = 0x04; /* bit 2 set: extra field present */ - const int orig_name = 0x08; /* bit 3 set: original file name present */ - const int comment = 0x10; /* bit 4 set: file comment present */ - unsigned char buf[8]; /* extended local header */ - unsigned char flags; /* compression flags */ - char magic[2]; /* magic header */ - int method; - typedef void (*sig_type) (int); - int exit_code=0; /* program exit code */ - int i; - - in_file = l_in_file; - out_file = l_out_file; - - if (signal(SIGINT, SIG_IGN) != SIG_IGN) { - (void) signal(SIGINT, (sig_type) abort_gzip); - } -#ifdef SIGTERM -// if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { -// (void) signal(SIGTERM, (sig_type) abort_gzip); -// } -#endif -#ifdef SIGHUP - if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { - (void) signal(SIGHUP, (sig_type) abort_gzip); - } -#endif - - /* Allocate all global buffers (for DYN_ALLOC option) */ - window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char))); - outcnt = 0; - bytes_out = 0L; - - magic[0] = fgetc(in_file); - magic[1] = fgetc(in_file); - - /* Magic header for gzip files, 1F 8B = \037\213 */ - if (memcmp(magic, "\037\213", 2) != 0) { - error_msg("Invalid gzip magic"); - return EXIT_FAILURE; - } - - method = (int) fgetc(in_file); - if (method != 8) { - error_msg("unknown method %d -- get newer version of gzip", method); - exit_code = 1; - return -1; - } - - flags = (unsigned char) fgetc(in_file); - - /* Ignore time stamp(4), extra flags(1), OS type(1) */ - for (i = 0; i < 6; i++) - fgetc(in_file); - - if ((flags & extra_field) != 0) { - size_t extra; - extra = fgetc(in_file); - extra += fgetc(in_file) << 8; - - for (i = 0; i < extra; i++) - fgetc(in_file); - } - - /* Discard original name if any */ - if ((flags & orig_name) != 0) { - while (fgetc(in_file) != 0); /* null */ - } - - /* Discard file comment if any */ - if ((flags & comment) != 0) { - while (fgetc(in_file) != 0); /* null */ - } - - if (method < 0) { - printf("it failed\n"); - return(exit_code); /* error message already emitted */ - } - - make_crc_table(); - - /* Decompress */ - if (method == 8) { - - int res = inflate(); - - if (res == 3) { - error_msg(memory_exhausted); - } else if (res != 0) { - error_msg("invalid compressed data--format violated"); - } - - } else { - error_msg("internal error, invalid method"); - } - - /* Get the crc and original length - * crc32 (see algorithm.doc) - * uncompressed input size modulo 2^32 - */ - fread(buf, 1, 8, in_file); - - /* Validate decompression - crc */ - if ((unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) { - error_msg("invalid compressed data--crc error"); - } - /* Validate decompression - size */ - if (((buf[4] | (buf[5] << 8)) |((buf[6] | (buf[7] << 8)) << 16)) != (unsigned long) bytes_out) { - error_msg("invalid compressed data--length error"); - } - - free(window); - free(crc_table); - - return 0; -} - -/* - * This needs access to global variables wondow and crc_table, so its not in its own file. - */ -extern void gz_close(int gunzip_pid) -{ - if (kill(gunzip_pid, SIGTERM) == -1) { - error_msg_and_die("*** Couldnt kill old gunzip process *** aborting"); - } - - if (waitpid(gunzip_pid, NULL, 0) == -1) { - printf("Couldnt wait ?"); - } - free(window); - free(crc_table); -} diff --git a/busybox/archival/libunarchive/unzip.c b/busybox/archival/libunarchive/unzip.c deleted file mode 100644 index ee746216d..000000000 --- a/busybox/archival/libunarchive/unzip.c +++ /dev/null @@ -1,1026 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * gunzip implementation for busybox - * - * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly. - * - * Originally adjusted for busybox by Sven Rudolph - * based on gzip sources - * - * Adjusted further by Erik Andersen , - * to support files as well as stdin/stdout, and to generally behave itself wrt - * command line handling. - * - * General cleanup to better adhere to the style guide and make use of standard - * busybox functions by 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 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 - * - * - * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface - * Copyright (C) 1992-1993 Jean-loup Gailly - * The unzip code was written and put in the public domain by Mark Adler. - * Portions of the lzw code are derived from the public domain 'compress' - * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, - * Ken Turkowski, Dave Mack and Peter Jannesen. - * - * See the license_msg below and the file COPYING for the software license. - * See the file algorithm.doc for the compression algorithms and file formats. - */ - -#if 0 -static char *license_msg[] = { - " Copyright (C) 1992-1993 Jean-loup Gailly", - " 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., 675 Mass Ave, Cambridge, MA 02139, USA.", - 0 -}; -#endif - -#include -#include -#include -#include -#include -#include "libbb.h" - -static FILE *in_file, *out_file; - -/* these are freed by gz_close */ -static unsigned char *window; -static unsigned long *crc_table; - -static unsigned long crc = 0xffffffffL; /* shift register contents */ - -/* Return codes from gzip */ -static const int ERROR = 1; - -/* - * window size--must be a power of two, and - * at least 32K for zip's deflate method - */ -static const int WSIZE = 0x8000; - -/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ -static const int BMAX = 16; /* maximum bit length of any code (16 for explode) */ -static const int N_MAX = 288; /* maximum number of codes in any set */ - -static long bytes_out; /* number of output bytes */ -static unsigned long outcnt; /* bytes in output buffer */ - -static unsigned hufts; /* track memory usage */ -static unsigned long bb; /* bit buffer */ -static unsigned bk; /* bits in bit buffer */ - -typedef struct huft_s { - unsigned char e; /* number of extra bits or operation */ - unsigned char b; /* number of bits in this code or subcode */ - union { - unsigned short n; /* literal, length base, or distance base */ - struct huft_s *t; /* pointer to next level of table */ - } v; -} huft_t; - -static const unsigned short mask_bits[] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - -//static int error_number = 0; -/* ======================================================================== - * Signal and error handler. - */ - -static void abort_gzip() -{ - error_msg("gzip aborted\n"); - exit(ERROR); -} - -static void make_crc_table() -{ - unsigned long table_entry; /* crc shift register */ - unsigned long poly = 0; /* polynomial exclusive-or pattern */ - int i; /* counter for all possible eight bit values */ - int k; /* byte being shifted into crc apparatus */ - - /* terms of polynomial defining this crc (except x^32): */ - static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - crc_table = (unsigned long *) malloc(256 * sizeof(unsigned long)); - - /* Make exclusive-or pattern from polynomial (0xedb88320) */ - for (i = 0; i < sizeof(p)/sizeof(int); i++) - poly |= 1L << (31 - p[i]); - - /* Compute and print table of CRC's, five per line */ - for (i = 0; i < 256; i++) { - table_entry = i; - /* The idea to initialize the register with the byte instead of - * zero was stolen from Haruhiko Okumura's ar002 - */ - for (k = 8; k; k--) { - table_entry = table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> 1; - } - crc_table[i]=table_entry; - } -} - -/* =========================================================================== - * Write the output window window[0..outcnt-1] and update crc and bytes_out. - * (Used for the decompressed data only.) - */ -static void flush_window(void) -{ - int n; - - if (outcnt == 0) - return; - - for (n = 0; n < outcnt; n++) { - crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8); - } - - if (fwrite(window, 1, outcnt, out_file) != outcnt) { - error_msg_and_die("Couldnt write"); - } - bytes_out += (unsigned long) outcnt; - outcnt = 0; -} - -/* - * Free the malloc'ed tables built by huft_build(), which makes a linked - * list of the tables it made, with the links in a dummy first entry of - * each table. - * t: table to free - */ -static int huft_free(huft_t *t) -{ - huft_t *p, *q; - - /* Go through linked list, freeing from the malloced (t[-1]) address. */ - p = t; - while (p != (huft_t *) NULL) { - q = (--p)->v.t; - free((char *) p); - p = q; - } - return 0; -} - -/* Given a list of code lengths and a maximum table size, make a set of - * tables to decode that set of codes. Return zero on success, one if - * the given code set is incomplete (the tables are still built in this - * case), two if the input is invalid (all zero length codes or an - * oversubscribed set of lengths), and three if not enough memory. - * - * b: code lengths in bits (all assumed <= BMAX) - * n: number of codes (assumed <= N_MAX) - * s: number of simple-valued codes (0..s-1) - * d: list of base values for non-simple codes - * e: list of extra bits for non-simple codes - * t: result: starting table - * m: maximum lookup bits, returns actual - */ -static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s, - const unsigned short *d, const unsigned short *e, huft_t **t, int *m) -{ - unsigned a; /* counter for codes of length k */ - unsigned c[BMAX + 1]; /* bit length count table */ - unsigned f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int h; /* table level */ - register unsigned i; /* counter, current code */ - register unsigned j; /* counter */ - register int k; /* number of bits in current code */ - int l; /* bits per table (returned in m) */ - register unsigned *p; /* pointer into c[], b[], or v[] */ - register huft_t *q; /* points to current table */ - huft_t r; /* table entry for structure assignment */ - huft_t *u[BMAX]; /* table stack */ - unsigned v[N_MAX]; /* values in order of bit length */ - register int w; /* bits before this table == (l * h) */ - unsigned x[BMAX + 1]; /* bit offsets, then code stack */ - unsigned *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - unsigned z; /* number of entries in current table */ - - /* Generate counts for each bit length */ - memset ((void *)(c), 0, sizeof(c)); - p = b; - i = n; - do { - c[*p]++; /* assume all entries <= BMAX */ - p++; /* Can't combine with above line (Solaris bug) */ - } while (--i); - if (c[0] == n) { /* null input--all zero length codes */ - *t = (huft_t *) NULL; - *m = 0; - return 0; - } - - /* Find minimum and maximum length, bound *m by those */ - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; /* minimum code length */ - if ((unsigned) l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; /* maximum code length */ - if ((unsigned) l > i) - l = i; - *m = l; - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return 2; /* bad input: more codes than bits */ - if ((y -= c[i]) < 0) - return 2; - c[i] += y; - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; - xp = x + 2; - while (--i) { /* note that i == g from above */ - *xp++ = (j += *p++); - } - - /* Make a table of values in order of bit lengths */ - p = b; - i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = -l; /* bits decoded == (l * h) */ - u[0] = (huft_t *) NULL; /* just to keep compilers happy */ - q = (huft_t *) NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) { - a = c[k]; - while (a--) { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l) { - h++; - w += l; /* previous table always l bits */ - - /* compute minimum size table less than or equal to l bits */ - z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */ - if ((f = 1 << (j = k - w)) > a + 1) { /* try a k-w bit table *//* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - while (++j < z) { /* try smaller tables up to z bits */ - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } - } - z = 1 << j; /* table entries for j-bit table */ - - /* allocate and link in new table */ - if ((q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t))) == NULL) { - if (h) { - huft_free(u[0]); - } - return 3; /* not enough memory */ - } - hufts += z + 1; /* track memory usage */ - *t = q + 1; /* link to list for huft_free() */ - *(t = &(q->v.t)) = NULL; - u[h] = ++q; /* table starts after link */ - - /* connect to last table, if there is one */ - if (h) { - x[h] = i; /* save pattern for backing up */ - r.b = (unsigned char) l; /* bits to dump before this table */ - r.e = (unsigned char) (16 + j); /* bits in this table */ - r.v.t = q; /* pointer to this table */ - j = i >> (w - l); /* (get around Turbo C bug) */ - u[h - 1][j] = r; /* connect to last table */ - } - } - - /* set up table entry in r */ - r.b = (unsigned char) (k - w); - if (p >= v + n) - r.e = 99; /* out of values--invalid code */ - else if (*p < s) { - r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ - r.v.n = (unsigned short) (*p); /* simple code is just the value */ - p++; /* one compiler does not like *p++ */ - } else { - r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ - r.v.n = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - while ((i & ((1 << w) - 1)) != x[h]) { - h--; /* don't need to update q */ - w -= l; - } - } - } - /* Return true (1) if we were given an incomplete table */ - return y != 0 && g != 1; -} - -/* - * inflate (decompress) the codes in a deflated (compressed) block. - * Return an error code or zero if it all goes ok. - * - * tl, td: literal/length and distance decoder tables - * bl, bd: number of bits decoded by tl[] and td[] - */ -static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd) -{ - register unsigned long e; /* table entry flag/number of extra bits */ - unsigned long n, d; /* length and index for copy */ - unsigned long w; /* current window position */ - huft_t *t; /* pointer to table entry */ - unsigned ml, md; /* masks for bl and bd bits */ - register unsigned long b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ - - /* make local copies of globals */ - b = bb; /* initialize bit buffer */ - k = bk; - w = outcnt; /* initialize window position */ - - /* inflate the coded data */ - ml = mask_bits[bl]; /* precompute masks for speed */ - md = mask_bits[bd]; - for (;;) { /* do until end of block */ - while (k < (unsigned) bl) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) - do { - if (e == 99) { - return 1; - } - b >>= t->b; - k -= t->b; - e -= 16; - while (k < e) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); - b >>= t->b; - k -= t->b; - if (e == 16) { /* then it's a literal */ - window[w++] = (unsigned char) t->v.n; - if (w == WSIZE) { - outcnt=(w), - flush_window(); - w = 0; - } - } else { /* it's an EOB or a length */ - - /* exit if end of block */ - if (e == 15) { - break; - } - - /* get length of block to copy */ - while (k < e) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - n = t->v.n + ((unsigned) b & mask_bits[e]); - b >>= e; - k -= e; - - /* decode distance of block to copy */ - while (k < (unsigned) bd) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - - if ((e = (t = td + ((unsigned) b & md))->e) > 16) - do { - if (e == 99) - return 1; - b >>= t->b; - k -= t->b; - e -= 16; - while (k < e) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); - b >>= t->b; - k -= t->b; - while (k < e) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - d = w - t->v.n - ((unsigned) b & mask_bits[e]); - b >>= e; - k -= e; - - /* do the copy */ - do { - n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e); -#if !defined(NOMEMCPY) && !defined(DEBUG) - if (w - d >= e) { /* (this test assumes unsigned comparison) */ - memcpy(window + w, window + d, e); - w += e; - d += e; - } else /* do it slow to avoid memcpy() overlap */ -#endif /* !NOMEMCPY */ - do { - window[w++] = window[d++]; - } while (--e); - if (w == WSIZE) { - outcnt=(w), - flush_window(); - w = 0; - } - } while (n); - } - } - - /* restore the globals from the locals */ - outcnt = w; /* restore global window pointer */ - bb = b; /* restore global bit buffer */ - bk = k; - - /* done */ - return 0; -} - -/* - * decompress an inflated block - * e: last block flag - * - * GLOBAL VARIABLES: bb, kk, - */ -static int inflate_block(int *e) -{ - unsigned t; /* block type */ - register unsigned long b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ - static unsigned short cplens[] = { /* Copy lengths for literal codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 - }; - /* note: see note #13 above about the 258 in this list. */ - static unsigned short cplext[] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 - }; /* 99==invalid */ - static unsigned short cpdist[] = { /* Copy offsets for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577 - }; - static unsigned short cpdext[] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13 - }; - - /* make local bit buffer */ - b = bb; - k = bk; - - /* read in last block bit */ - while (k < 1) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - *e = (int) b & 1; - b >>= 1; - k -= 1; - - /* read in block type */ - while (k < 2) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - t = (unsigned) b & 3; - b >>= 2; - k -= 2; - - /* restore the global bit buffer */ - bb = b; - bk = k; - - /* inflate that block type */ - switch (t) { - case 0: /* Inflate stored */ - { - unsigned long n; /* number of bytes in block */ - unsigned long w; /* current window position */ - register unsigned long b_stored; /* bit buffer */ - register unsigned long k_stored; /* number of bits in bit buffer */ - - /* make local copies of globals */ - b_stored = bb; /* initialize bit buffer */ - k_stored = bk; - w = outcnt; /* initialize window position */ - - /* go to byte boundary */ - n = k_stored & 7; - b_stored >>= n; - k_stored -= n; - - /* get the length and its complement */ - while (k_stored < 16) { - b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; - k_stored += 8; - } - n = ((unsigned) b_stored & 0xffff); - b_stored >>= 16; - k_stored -= 16; - while (k_stored < 16) { - b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; - k_stored += 8; - } - if (n != (unsigned) ((~b_stored) & 0xffff)) { - return 1; /* error in compressed data */ - } - b_stored >>= 16; - k_stored -= 16; - - /* read and output the compressed data */ - while (n--) { - while (k_stored < 8) { - b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; - k_stored += 8; - } - window[w++] = (unsigned char) b_stored; - if (w == (unsigned long)WSIZE) { - outcnt=(w), - flush_window(); - w = 0; - } - b_stored >>= 8; - k_stored -= 8; - } - - /* restore the globals from the locals */ - outcnt = w; /* restore global window pointer */ - bb = b_stored; /* restore global bit buffer */ - bk = k_stored; - return 0; - } - case 1: /* Inflate fixed - * decompress an inflated type 1 (fixed Huffman codes) block. We should - * either replace this with a custom decoder, or at least precompute the - * Huffman tables. - */ - { - int i; /* temporary variable */ - huft_t *tl; /* literal/length code table */ - huft_t *td; /* distance code table */ - int bl; /* lookup bits for tl */ - int bd; /* lookup bits for td */ - unsigned int l[288]; /* length list for huft_build */ - - /* set up literal table */ - for (i = 0; i < 144; i++) { - l[i] = 8; - } - for (; i < 256; i++) { - l[i] = 9; - } - for (; i < 280; i++) { - l[i] = 7; - } - for (; i < 288; i++) { /* make a complete, but wrong code set */ - l[i] = 8; - } - bl = 7; - if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) { - return i; - } - - /* set up distance table */ - for (i = 0; i < 30; i++) { /* make an incomplete code set */ - l[i] = 5; - } - bd = 5; - if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) { - huft_free(tl); - return i; - } - - /* decompress until an end-of-block code */ - if (inflate_codes(tl, td, bl, bd)) - return 1; - - /* free the decoding tables, return */ - huft_free(tl); - huft_free(td); - return 0; - } - case 2: /* Inflate dynamic */ - { - /* Tables for deflate from PKZIP's appnote.txt. */ - static unsigned border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 - }; - int dbits = 6; /* bits in base distance lookup table */ - int lbits = 9; /* bits in base literal/length lookup table */ - - int i; /* temporary variables */ - unsigned j; - unsigned l; /* last length */ - unsigned m; /* mask for bit lengths table */ - unsigned n; /* number of lengths to get */ - huft_t *tl; /* literal/length code table */ - huft_t *td; /* distance code table */ - int bl; /* lookup bits for tl */ - int bd; /* lookup bits for td */ - unsigned nb; /* number of bit length codes */ - unsigned nl; /* number of literal/length codes */ - unsigned nd; /* number of distance codes */ - - unsigned ll[286 + 30]; /* literal/length and distance code lengths */ - register unsigned long b_dynamic; /* bit buffer */ - register unsigned k_dynamic; /* number of bits in bit buffer */ - - /* make local bit buffer */ - b_dynamic = bb; - k_dynamic = bk; - - /* read in table lengths */ - while (k_dynamic < 5) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ - b_dynamic >>= 5; - k_dynamic -= 5; - while (k_dynamic < 5) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ - b_dynamic >>= 5; - k_dynamic -= 5; - while (k_dynamic < 4) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ - b_dynamic >>= 4; - k_dynamic -= 4; - if (nl > 286 || nd > 30) { - return 1; /* bad lengths */ - } - - /* read in bit-length-code lengths */ - for (j = 0; j < nb; j++) { - while (k_dynamic < 3) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - ll[border[j]] = (unsigned) b_dynamic & 7; - b_dynamic >>= 3; - k_dynamic -= 3; - } - for (; j < 19; j++) { - ll[border[j]] = 0; - } - - /* build decoding table for trees--single level, 7 bit lookup */ - bl = 7; - if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) { - if (i == 1) { - huft_free(tl); - } - return i; /* incomplete code set */ - } - - /* read in literal and distance code lengths */ - n = nl + nd; - m = mask_bits[bl]; - i = l = 0; - while ((unsigned) i < n) { - while (k_dynamic < (unsigned) bl) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - j = (td = tl + ((unsigned) b_dynamic & m))->b; - b_dynamic >>= j; - k_dynamic -= j; - j = td->v.n; - if (j < 16) { /* length of code in bits (0..15) */ - ll[i++] = l = j; /* save last length in l */ - } - else if (j == 16) { /* repeat last length 3 to 6 times */ - while (k_dynamic < 2) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - j = 3 + ((unsigned) b_dynamic & 3); - b_dynamic >>= 2; - k_dynamic -= 2; - if ((unsigned) i + j > n) { - return 1; - } - while (j--) { - ll[i++] = l; - } - } else if (j == 17) { /* 3 to 10 zero length codes */ - while (k_dynamic < 3) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - j = 3 + ((unsigned) b_dynamic & 7); - b_dynamic >>= 3; - k_dynamic -= 3; - if ((unsigned) i + j > n) { - return 1; - } - while (j--) { - ll[i++] = 0; - } - l = 0; - } else { /* j == 18: 11 to 138 zero length codes */ - while (k_dynamic < 7) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - j = 11 + ((unsigned) b_dynamic & 0x7f); - b_dynamic >>= 7; - k_dynamic -= 7; - if ((unsigned) i + j > n) { - return 1; - } - while (j--) { - ll[i++] = 0; - } - l = 0; - } - } - - /* free decoding table for trees */ - huft_free(tl); - - /* restore the global bit buffer */ - bb = b_dynamic; - bk = k_dynamic; - - /* build the decoding tables for literal/length and distance codes */ - bl = lbits; - if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) { - if (i == 1) { - error_msg("Incomplete literal tree"); - huft_free(tl); - } - return i; /* incomplete code set */ - } - bd = dbits; - if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { - if (i == 1) { - error_msg("incomplete distance tree"); - huft_free(td); - } - huft_free(tl); - return i; /* incomplete code set */ - } - - /* decompress until an end-of-block code */ - if (inflate_codes(tl, td, bl, bd)) - return 1; - - /* free the decoding tables, return */ - huft_free(tl); - huft_free(td); - return 0; - } - default: - /* bad block type */ - return 2; - } -} - -/* - * decompress an inflated entry - * - * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr - */ -static int inflate() -{ - int e; /* last block flag */ - int r; /* result code */ - unsigned h = 0; /* maximum struct huft's malloc'ed */ - - /* initialize window, bit buffer */ - outcnt = 0; - bk = 0; - bb = 0; - - /* decompress until the last block */ - do { - hufts = 0; - if ((r = inflate_block(&e)) != 0) { - return r; - } - if (hufts > h) { - h = hufts; - } - } while (!e); - - /* flush out window */ - flush_window(); - - /* return success */ - return 0; -} - -/* =========================================================================== - * Unzip in to out. This routine works on both gzip and pkzip files. - * - * IN assertions: the buffer inbuf contains already the beginning of - * the compressed data, from offsets inptr to insize-1 included. - * The magic header has already been checked. The output buffer is cleared. - * in, out: input and output file descriptors - */ -extern int unzip(FILE *l_in_file, FILE *l_out_file) -{ - const int extra_field = 0x04; /* bit 2 set: extra field present */ - const int orig_name = 0x08; /* bit 3 set: original file name present */ - const int comment = 0x10; /* bit 4 set: file comment present */ - unsigned char buf[8]; /* extended local header */ - unsigned char flags; /* compression flags */ - char magic[2]; /* magic header */ - int method; - typedef void (*sig_type) (int); - int exit_code=0; /* program exit code */ - int i; - - in_file = l_in_file; - out_file = l_out_file; - - if (signal(SIGINT, SIG_IGN) != SIG_IGN) { - (void) signal(SIGINT, (sig_type) abort_gzip); - } -#ifdef SIGTERM -// if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { -// (void) signal(SIGTERM, (sig_type) abort_gzip); -// } -#endif -#ifdef SIGHUP - if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { - (void) signal(SIGHUP, (sig_type) abort_gzip); - } -#endif - - /* Allocate all global buffers (for DYN_ALLOC option) */ - window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char))); - outcnt = 0; - bytes_out = 0L; - - magic[0] = fgetc(in_file); - magic[1] = fgetc(in_file); - - /* Magic header for gzip files, 1F 8B = \037\213 */ - if (memcmp(magic, "\037\213", 2) != 0) { - error_msg("Invalid gzip magic"); - return EXIT_FAILURE; - } - - method = (int) fgetc(in_file); - if (method != 8) { - error_msg("unknown method %d -- get newer version of gzip", method); - exit_code = 1; - return -1; - } - - flags = (unsigned char) fgetc(in_file); - - /* Ignore time stamp(4), extra flags(1), OS type(1) */ - for (i = 0; i < 6; i++) - fgetc(in_file); - - if ((flags & extra_field) != 0) { - size_t extra; - extra = fgetc(in_file); - extra += fgetc(in_file) << 8; - - for (i = 0; i < extra; i++) - fgetc(in_file); - } - - /* Discard original name if any */ - if ((flags & orig_name) != 0) { - while (fgetc(in_file) != 0); /* null */ - } - - /* Discard file comment if any */ - if ((flags & comment) != 0) { - while (fgetc(in_file) != 0); /* null */ - } - - if (method < 0) { - printf("it failed\n"); - return(exit_code); /* error message already emitted */ - } - - make_crc_table(); - - /* Decompress */ - if (method == 8) { - - int res = inflate(); - - if (res == 3) { - error_msg(memory_exhausted); - } else if (res != 0) { - error_msg("invalid compressed data--format violated"); - } - - } else { - error_msg("internal error, invalid method"); - } - - /* Get the crc and original length - * crc32 (see algorithm.doc) - * uncompressed input size modulo 2^32 - */ - fread(buf, 1, 8, in_file); - - /* Validate decompression - crc */ - if ((unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) { - error_msg("invalid compressed data--crc error"); - } - /* Validate decompression - size */ - if (((buf[4] | (buf[5] << 8)) |((buf[6] | (buf[7] << 8)) << 16)) != (unsigned long) bytes_out) { - error_msg("invalid compressed data--length error"); - } - - free(window); - free(crc_table); - - return 0; -} - -/* - * This needs access to global variables wondow and crc_table, so its not in its own file. - */ -extern void gz_close(int gunzip_pid) -{ - if (kill(gunzip_pid, SIGTERM) == -1) { - error_msg_and_die("*** Couldnt kill old gunzip process *** aborting"); - } - - if (waitpid(gunzip_pid, NULL, 0) == -1) { - printf("Couldnt wait ?"); - } - free(window); - free(crc_table); -} diff --git a/busybox/archival/rpm2cpio.c b/busybox/archival/rpm2cpio.c deleted file mode 100644 index 8d639d6ad..000000000 --- a/busybox/archival/rpm2cpio.c +++ /dev/null @@ -1,91 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini rpm2cpio implementation for busybox - * - * Copyright (C) 2001 by Laurence Anderson - * - * 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 "busybox.h" -#include /* For ntohl & htonl function */ -#include - -#define RPM_MAGIC "\355\253\356\333" -#define RPM_HEADER_MAGIC "\216\255\350" - -struct rpm_lead { - unsigned char magic[4]; - u_int8_t major, minor; - u_int16_t type; - u_int16_t archnum; - char name[66]; - u_int16_t osnum; - u_int16_t signature_type; - char reserved[16]; -}; - -struct rpm_header { - char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */ - u_int8_t version; /* 1 byte version number */ - u_int32_t reserved; /* 4 bytes reserved */ - u_int32_t entries; /* Number of entries in header (4 bytes) */ - u_int32_t size; /* Size of store (4 bytes) */ -}; - -void skip_header(FILE *rpmfile) -{ - struct rpm_header header; - - fread(&header, sizeof(struct rpm_header), 1, rpmfile); - if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) error_msg_and_die("Invalid RPM header magic"); /* Invalid magic */ - if (header.version != 1) error_msg_and_die("Unsupported RPM header version"); /* This program only supports v1 headers */ - header.entries = ntohl(header.entries); - header.size = ntohl(header.size); - fseek (rpmfile, 16 * header.entries, SEEK_CUR); /* Seek past index entries */ - fseek (rpmfile, header.size, SEEK_CUR); /* Seek past store */ -} - -/* No getopt required */ -extern int rpm2cpio_main(int argc, char **argv) -{ - struct rpm_lead lead; - int gunzip_pid; - FILE *rpmfile, *cpiofile; - - if (argc == 1) { - rpmfile = stdin; - } else { - rpmfile = fopen(argv[1], "r"); - if (!rpmfile) perror_msg_and_die("Can't open rpm file"); - /* set the buffer size */ - setvbuf(rpmfile, NULL, _IOFBF, 0x8000); - } - - fread (&lead, sizeof(struct rpm_lead), 1, rpmfile); - if (strncmp((char *) &lead.magic, RPM_MAGIC, 4) != 0) error_msg_and_die("Invalid RPM magic"); /* Just check the magic, the rest is irrelevant */ - /* Skip the signature header */ - skip_header(rpmfile); - fseek(rpmfile, (8 - (ftell(rpmfile) % 8)) % 8, SEEK_CUR); /* Pad to 8 byte boundary */ - /* Skip the main header */ - skip_header(rpmfile); - - cpiofile = gz_open(rpmfile, &gunzip_pid); - - copyfd(fileno(cpiofile), fileno(stdout)); - gz_close(gunzip_pid); - fclose(rpmfile); - return 0; -} diff --git a/busybox/archival/tar.c b/busybox/archival/tar.c deleted file mode 100644 index 389d7f02e..000000000 --- a/busybox/archival/tar.c +++ /dev/null @@ -1,1150 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini tar implementation for busybox - * - * Note, that as of BusyBox-0.43, tar has been completely rewritten from the - * ground up. It still has remnents of the old code lying about, but it is - * very different now (i.e., cleaner, less global variables, etc.) - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * - * Based in part in the tar implementation in sash - * Copyright (c) 1999 by David I. Bell - * Permission is granted to use, distribute, or modify this source, - * provided that this copyright notice remains intact. - * Permission to distribute sash derived code under the GPL has been granted. - * - * Based in part on the tar implementation from busybox-0.28 - * Copyright (C) 1995 Bruce Perens - * This is free software under the GNU General Public License. - * - * 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 -#include -#include -#include -#include -#include "busybox.h" - -/* Tar file constants */ -#ifndef MAJOR -#define MAJOR(dev) (((dev)>>8)&0xff) -#define MINOR(dev) ((dev)&0xff) -#endif - -enum { NAME_SIZE = 100 }; /* because gcc won't let me use 'static const int' */ - -/* POSIX tar Header Block, from POSIX 1003.1-1990 */ -struct TarHeader -{ - /* byte offset */ - char name[NAME_SIZE]; /* 0-99 */ - char mode[8]; /* 100-107 */ - char uid[8]; /* 108-115 */ - char gid[8]; /* 116-123 */ - char size[12]; /* 124-135 */ - char mtime[12]; /* 136-147 */ - char chksum[8]; /* 148-155 */ - char typeflag; /* 156-156 */ - char linkname[NAME_SIZE]; /* 157-256 */ - char magic[6]; /* 257-262 */ - char version[2]; /* 263-264 */ - char uname[32]; /* 265-296 */ - char gname[32]; /* 297-328 */ - char devmajor[8]; /* 329-336 */ - char devminor[8]; /* 337-344 */ - char prefix[155]; /* 345-499 */ - char padding[12]; /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */ -}; -typedef struct TarHeader TarHeader; - - -/* A few useful constants */ -#define TAR_MAGIC "ustar" /* ustar and a null */ -#define TAR_VERSION " " /* Be compatable with GNU tar format */ -static const int TAR_MAGIC_LEN = 6; -static const int TAR_VERSION_LEN = 2; -static const int TAR_BLOCK_SIZE = 512; - -/* A nice enum with all the possible tar file content types */ -enum TarFileType -{ - REGTYPE = '0', /* regular file */ - REGTYPE0 = '\0', /* regular file (ancient bug compat)*/ - LNKTYPE = '1', /* hard link */ - SYMTYPE = '2', /* symbolic link */ - CHRTYPE = '3', /* character special */ - BLKTYPE = '4', /* block special */ - DIRTYPE = '5', /* directory */ - FIFOTYPE = '6', /* FIFO special */ - CONTTYPE = '7', /* reserved */ - GNULONGLINK = 'K', /* GNU long (>100 chars) link name */ - GNULONGNAME = 'L', /* GNU long (>100 chars) file name */ -}; -typedef enum TarFileType TarFileType; - -/* This struct ignores magic, non-numeric user name, - * non-numeric group name, and the checksum, since - * these are all ignored by BusyBox tar. */ -struct TarInfo -{ - int tarFd; /* An open file descriptor for reading from the tarball */ - char * name; /* File name */ - mode_t mode; /* Unix mode, including device bits. */ - uid_t uid; /* Numeric UID */ - gid_t gid; /* Numeric GID */ - size_t size; /* Size of file */ - time_t mtime; /* Last-modified time */ - enum TarFileType type; /* Regular, directory, link, etc. */ - char * linkname; /* Name for symbolic and hard links */ - long devmajor; /* Major number for special device */ - long devminor; /* Minor number for special device */ -}; -typedef struct TarInfo TarInfo; - -/* Local procedures to restore files from a tar file. */ -static int readTarFile(int tarFd, int extractFlag, int listFlag, - int tostdoutFlag, int verboseFlag, char** extractList, - char** excludeList); - -#ifdef BB_FEATURE_TAR_CREATE -/* Local procedures to save files into a tar file. */ -static int writeTarFile(const char* tarName, int verboseFlag, char **argv, - char** excludeList); -#endif - -#if defined BB_FEATURE_TAR_EXCLUDE -static struct option longopts[] = { - { "exclude", 1, NULL, 'e' }, - { NULL, 0, NULL, 0 } -}; -#endif - -extern int tar_main(int argc, char **argv) -{ - char** excludeList=NULL; - char** extractList=NULL; - const char *tarName="-"; - const char *cwd=NULL; -#if defined BB_FEATURE_TAR_EXCLUDE - int excludeListSize=0; - FILE *fileList; - char file[256]; -#endif -#if defined BB_FEATURE_TAR_GZIP - FILE *comp_file = NULL; - int unzipFlag = FALSE; -#endif - int listFlag = FALSE; - int extractFlag = FALSE; - int createFlag = FALSE; - int verboseFlag = FALSE; - int tostdoutFlag = FALSE; - int status = FALSE; - int opt; - pid_t pid; - - if (argc <= 1) - show_usage(); - - if (argv[1][0] != '-') { - char *tmp = xmalloc(strlen(argv[1]) + 2); - tmp[0] = '-'; - strcpy(tmp + 1, argv[1]); - argv[1] = tmp; - } - - while ( -#ifndef BB_FEATURE_TAR_EXCLUDE - (opt = getopt(argc, argv, "cxtzvOf:pC:")) -#else - (opt = getopt_long(argc, argv, "cxtzvOf:X:pC:", longopts, NULL)) -#endif - > 0) { - switch (opt) { - case 'c': - if (extractFlag == TRUE || listFlag == TRUE) - goto flagError; - createFlag = TRUE; - break; - case 'x': - if (listFlag == TRUE || createFlag == TRUE) - goto flagError; - extractFlag = TRUE; - break; - case 't': - if (extractFlag == TRUE || createFlag == TRUE) - goto flagError; - listFlag = TRUE; - break; -#ifdef BB_FEATURE_TAR_GZIP - case 'z': - unzipFlag = TRUE; - break; -#endif - case 'v': - verboseFlag = TRUE; - break; - case 'O': - tostdoutFlag = TRUE; - break; - case 'f': - if (*tarName != '-') - error_msg_and_die( "Only one 'f' option allowed"); - tarName = optarg; - break; -#if defined BB_FEATURE_TAR_EXCLUDE - case 'e': - excludeList=xrealloc( excludeList, - sizeof(char *) * (excludeListSize+2)); - excludeList[excludeListSize] = optarg; - /* Tack a NULL onto the end of the list */ - excludeList[++excludeListSize] = NULL; - case 'X': - fileList = xfopen(optarg, "r"); - while (fgets(file, sizeof(file), fileList) != NULL) { - excludeList = xrealloc(excludeList, - sizeof(char *) * (excludeListSize+2)); - chomp(file); - excludeList[excludeListSize] = xstrdup(file); - /* Tack a NULL onto the end of the list */ - excludeList[++excludeListSize] = NULL; - } - fclose(fileList); - break; -#endif - case 'p': - break; - case 'C': - cwd = xgetcwd((char *)cwd); - if (chdir(optarg)) { - printf("cd: %s: %s\n", optarg, strerror(errno)); - return EXIT_FAILURE; - } - break; - default: - show_usage(); - } - } - - /* - * Do the correct type of action supplying the rest of the - * command line arguments as the list of files to process. - */ - if (createFlag == TRUE) { -#ifndef BB_FEATURE_TAR_CREATE - error_msg_and_die( "This version of tar was not compiled with tar creation support."); -#else -#ifdef BB_FEATURE_TAR_GZIP - if (unzipFlag==TRUE) - error_msg_and_die("Creation of compressed not internally support by tar, pipe to busybox gunzip"); -#endif - status = writeTarFile(tarName, verboseFlag, argv + optind, excludeList); -#endif - } - if (listFlag == TRUE || extractFlag == TRUE) { - int tarFd; - if (argv[optind]) - extractList = argv + optind; - /* Open the tar file for reading. */ - if (!strcmp(tarName, "-")) - tarFd = fileno(stdin); - else - tarFd = open(tarName, O_RDONLY); - if (tarFd < 0) - perror_msg_and_die("Error opening '%s'", tarName); - -#ifdef BB_FEATURE_TAR_GZIP - /* unzip tarFd in a seperate process */ - if (unzipFlag == TRUE) { - comp_file = fdopen(tarFd, "r"); - - /* set the buffer size */ - setvbuf(comp_file, NULL, _IOFBF, 0x8000); - - if ((tarFd = fileno(gz_open(comp_file, &pid))) == EXIT_FAILURE) { - error_msg_and_die("Couldnt unzip file"); - } - } -#endif - status = readTarFile(tarFd, extractFlag, listFlag, tostdoutFlag, - verboseFlag, extractList, excludeList); - close(tarFd); -#ifdef BB_FEATURE_TAR_GZIP - if (unzipFlag == TRUE) { - gz_close(pid); - fclose(comp_file); - } -#endif - } - - if (cwd) - chdir(cwd); - if (status == TRUE) - return EXIT_SUCCESS; - else - return EXIT_FAILURE; - - flagError: - error_msg_and_die( "Exactly one of 'c', 'x' or 't' must be specified"); -} - -static void -fixUpPermissions(TarInfo *header) -{ - struct utimbuf t; - /* Now set permissions etc. for the new file */ - chown(header->name, header->uid, header->gid); - chmod(header->name, header->mode); - /* Reset the time */ - t.actime = time(0); - t.modtime = header->mtime; - utime(header->name, &t); -} - -static int -tarExtractRegularFile(TarInfo *header, int extractFlag, int tostdoutFlag) -{ - size_t writeSize; - size_t readSize; - size_t actualWriteSz; - char buffer[20 * TAR_BLOCK_SIZE]; - size_t size = header->size; - int outFd=fileno(stdout); - - /* Open the file to be written, if a file is supposed to be written */ - if (extractFlag==TRUE && tostdoutFlag==FALSE) { - /* Create the path to the file, just in case it isn't there... - * This should not screw up path permissions or anything. */ - char *buf, *dir; - buf = xstrdup (header->name); - dir = dirname (buf); - make_directory (dir, -1, FILEUTILS_RECUR); - free (buf); - if ((outFd=open(header->name, O_CREAT|O_TRUNC|O_WRONLY, - header->mode & ~S_IFMT)) < 0) { - error_msg(io_error, header->name, strerror(errno)); - return( FALSE); - } - } - - /* Write out the file, if we are supposed to be doing that */ - while ( size > 0 ) { - actualWriteSz=0; - if ( size > sizeof(buffer) ) - writeSize = readSize = sizeof(buffer); - else { - int mod = size % TAR_BLOCK_SIZE; - if ( mod != 0 ) - readSize = size + (TAR_BLOCK_SIZE - mod); - else - readSize = size; - writeSize = size; - } - if ( (readSize = full_read(header->tarFd, buffer, readSize)) <= 0 ) { - /* Tarball seems to have a problem */ - error_msg("Unexpected EOF in archive"); - return( FALSE); - } - if ( readSize < writeSize ) - writeSize = readSize; - - /* Write out the file, if we are supposed to be doing that */ - if (extractFlag==TRUE) { - - if ((actualWriteSz=full_write(outFd, buffer, writeSize)) != writeSize ) { - /* Output file seems to have a problem */ - error_msg(io_error, header->name, strerror(errno)); - return( FALSE); - } - } else { - actualWriteSz=writeSize; - } - - size -= actualWriteSz; - } - - /* Now we are done writing the file out, so try - * and fix up the permissions and whatnot */ - if (extractFlag==TRUE && tostdoutFlag==FALSE) { - close(outFd); - fixUpPermissions(header); - } - return( TRUE); -} - -static int -tarExtractDirectory(TarInfo *header, int extractFlag, int tostdoutFlag) -{ - if (extractFlag==FALSE || tostdoutFlag==TRUE) - return( TRUE); - - if (make_directory(header->name, header->mode, FILEUTILS_RECUR) < 0) - return( FALSE); - - fixUpPermissions(header); - return( TRUE); -} - -static int -tarExtractHardLink(TarInfo *header, int extractFlag, int tostdoutFlag) -{ - if (extractFlag==FALSE || tostdoutFlag==TRUE) - return( TRUE); - - if (link(header->linkname, header->name) < 0) { - perror_msg("%s: Cannot create hard link to '%s'", header->name, - header->linkname); - return( FALSE); - } - - /* Now set permissions etc. for the new directory */ - fixUpPermissions(header); - return( TRUE); -} - -static int -tarExtractSymLink(TarInfo *header, int extractFlag, int tostdoutFlag) -{ - if (extractFlag==FALSE || tostdoutFlag==TRUE) - return( TRUE); - -#ifdef S_ISLNK - if (symlink(header->linkname, header->name) < 0) { - perror_msg("%s: Cannot create symlink to '%s'", header->name, - header->linkname); - return( FALSE); - } - /* Try to change ownership of the symlink. - * If libs doesn't support that, don't bother. - * Changing the pointed-to-file is the Wrong Thing(tm). - */ -#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) - lchown(header->name, header->uid, header->gid); -#endif - - /* Do not change permissions or date on symlink, - * since it changes the pointed to file instead. duh. */ -#else - error_msg("%s: Cannot create symlink to '%s': %s", - header->name, header->linkname, - "symlinks not supported"); -#endif - return( TRUE); -} - -static int -tarExtractSpecial(TarInfo *header, int extractFlag, int tostdoutFlag) -{ - if (extractFlag==FALSE || tostdoutFlag==TRUE) - return( TRUE); - - if (S_ISCHR(header->mode) || S_ISBLK(header->mode) || S_ISSOCK(header->mode)) { - if (mknod(header->name, header->mode, makedev(header->devmajor, header->devminor)) < 0) { - perror_msg("%s: Cannot mknod", header->name); - return( FALSE); - } - } else if (S_ISFIFO(header->mode)) { - if (mkfifo(header->name, header->mode) < 0) { - perror_msg("%s: Cannot mkfifo", header->name); - return( FALSE); - } - } - - /* Now set permissions etc. for the new directory */ - fixUpPermissions(header); - return( TRUE); -} - -/* Parse the tar header and fill in the nice struct with the details */ -static int -readTarHeader(struct TarHeader *rawHeader, struct TarInfo *header) -{ - int i; - long chksum, sum=0; - unsigned char *s = (unsigned char *)rawHeader; - - header->name = rawHeader->name; - /* Check for and relativify any absolute paths */ - if ( *(header->name) == '/' ) { - static int alreadyWarned=FALSE; - - while (*(header->name) == '/') - header->name++; - - if (alreadyWarned == FALSE) { - error_msg("Removing leading '/' from member names"); - alreadyWarned = TRUE; - } - } - - header->mode = strtol(rawHeader->mode, NULL, 8); - header->uid = strtol(rawHeader->uid, NULL, 8); - header->gid = strtol(rawHeader->gid, NULL, 8); - header->size = strtol(rawHeader->size, NULL, 8); - header->mtime = strtol(rawHeader->mtime, NULL, 8); - chksum = strtol(rawHeader->chksum, NULL, 8); - header->type = rawHeader->typeflag; - header->linkname = rawHeader->linkname; - header->devmajor = strtol(rawHeader->devmajor, NULL, 8); - header->devminor = strtol(rawHeader->devminor, NULL, 8); - - /* Check the checksum */ - for (i = sizeof(*rawHeader); i-- != 0;) { - sum += *s++; - } - /* Remove the effects of the checksum field (replace - * with blanks for the purposes of the checksum) */ - s = rawHeader->chksum; - for (i = sizeof(rawHeader->chksum) ; i-- != 0;) { - sum -= *s++; - } - sum += ' ' * sizeof(rawHeader->chksum); - if (sum == chksum ) - return ( TRUE); - return( FALSE); -} - -static int exclude_file(char **excluded_files, const char *file) -{ - int i; - - if (excluded_files == NULL) - return 0; - - for (i = 0; excluded_files[i] != NULL; i++) { - if (excluded_files[i][0] == '/') { - if (fnmatch(excluded_files[i], file, - FNM_PATHNAME | FNM_LEADING_DIR) == 0) - return 1; - } else { - const char *p; - - for (p = file; p[0] != '\0'; p++) { - if ((p == file || p[-1] == '/') && p[0] != '/' && - fnmatch(excluded_files[i], p, - FNM_PATHNAME | FNM_LEADING_DIR) == 0) - return 1; - } - } - } - - return 0; -} - -static int extract_file(char **extract_files, const char *file) -{ - int i; - - if (extract_files == NULL) - return 1; - - for (i = 0; extract_files[i] != NULL; i++) { - if (fnmatch(extract_files[i], file, FNM_LEADING_DIR) == 0) - return 1; - } - - return 0; -} - -/* - * Read a tar file and extract or list the specified files within it. - * If the list is empty than all files are extracted or listed. - */ -static int readTarFile(int tarFd, int extractFlag, int listFlag, - int tostdoutFlag, int verboseFlag, char** extractList, - char** excludeList) -{ - int status; - int errorFlag=FALSE; - int skipNextHeaderFlag=FALSE; - TarHeader rawHeader; - TarInfo header; - - /* Read the tar file, and iterate over it one file at a time */ - while ( (status = full_read(tarFd, (char*)&rawHeader, TAR_BLOCK_SIZE)) == TAR_BLOCK_SIZE ) { - - /* Try to read the header */ - if ( readTarHeader(&rawHeader, &header) == FALSE ) { - if ( *(header.name) == '\0' ) { - goto endgame; - } else { - errorFlag=TRUE; - error_msg("Bad tar header, skipping"); - continue; - } - } - if ( *(header.name) == '\0' ) - continue; - header.tarFd = tarFd; - - /* Skip funky extra GNU headers that precede long files */ - if ( (header.type == GNULONGNAME) || (header.type == GNULONGLINK) ) { - skipNextHeaderFlag=TRUE; - if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) - errorFlag = TRUE; - continue; - } - if ( skipNextHeaderFlag == TRUE ) { - skipNextHeaderFlag=FALSE; - error_msg(name_longer_than_foo, NAME_SIZE); - if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) - errorFlag = TRUE; - continue; - } - -#if defined BB_FEATURE_TAR_EXCLUDE - if (exclude_file(excludeList, header.name)) { - /* There are not the droids you're looking for, move along */ - /* If it is a regular file, pretend to extract it with - * the extractFlag set to FALSE, so the junk in the tarball - * is properly skipped over */ - if ( header.type==REGTYPE || header.type==REGTYPE0 ) { - if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) - errorFlag = TRUE; - } - continue; - } -#endif - - if (!extract_file(extractList, header.name)) { - /* There are not the droids you're looking for, move along */ - /* If it is a regular file, pretend to extract it with - * the extractFlag set to FALSE, so the junk in the tarball - * is properly skipped over */ - if ( header.type==REGTYPE || header.type==REGTYPE0 ) { - if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) - errorFlag = TRUE; - } - continue; - } - - if (listFlag == TRUE) { - /* Special treatment if the list (-t) flag is on */ - if (verboseFlag == TRUE) { - int len, len1; - char buf[35]; - struct tm *tm = localtime (&(header.mtime)); - - len=printf("%s ", mode_string(header.mode)); - my_getpwuid(buf, header.uid); - if (! *buf) - len+=printf("%d", header.uid); - else - len+=printf("%s", buf); - my_getgrgid(buf, header.gid); - if (! *buf) - len+=printf("/%-d ", header.gid); - else - len+=printf("/%-s ", buf); - - if (header.type==CHRTYPE || header.type==BLKTYPE) { - len1=snprintf(buf, sizeof(buf), "%ld,%-ld ", - header.devmajor, header.devminor); - } else { - len1=snprintf(buf, sizeof(buf), "%lu ", (long)header.size); - } - /* Jump through some hoops to make the columns match up */ - for(;(len+len1)<31;len++) - printf(" "); - printf(buf); - - /* Use ISO 8610 time format */ - if (tm) { - printf ("%04d-%02d-%02d %02d:%02d:%02d ", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - } - } - printf("%s", header.name); - if (verboseFlag == TRUE) { - if (header.type==LNKTYPE) /* If this is a link, say so */ - printf(" link to %s", header.linkname); - else if (header.type==SYMTYPE) - printf(" -> %s", header.linkname); - } - printf("\n"); - } - - /* List contents if we are supposed to do that */ - if (verboseFlag == TRUE && extractFlag == TRUE) { - /* Now the normal listing */ - FILE *vbFd = stdout; - if (tostdoutFlag == TRUE) // If the archive goes to stdout, verbose to stderr - vbFd = stderr; - fprintf(vbFd, "%s\n", header.name); - } - - /* Remove files if we would overwrite them */ - if (extractFlag == TRUE && tostdoutFlag == FALSE) - unlink(header.name); - - /* If we got here, we can be certain we have a legitimate - * header to work with. So work with it. */ - switch ( header.type ) { - case REGTYPE: - case REGTYPE0: - /* If the name ends in a '/' then assume it is - * supposed to be a directory, and fall through */ - if (!last_char_is(header.name,'/')) { - if (tarExtractRegularFile(&header, extractFlag, tostdoutFlag)==FALSE) - errorFlag=TRUE; - break; - } - case DIRTYPE: - if (tarExtractDirectory( &header, extractFlag, tostdoutFlag)==FALSE) - errorFlag=TRUE; - break; - case LNKTYPE: - if (tarExtractHardLink( &header, extractFlag, tostdoutFlag)==FALSE) - errorFlag=TRUE; - break; - case SYMTYPE: - if (tarExtractSymLink( &header, extractFlag, tostdoutFlag)==FALSE) - errorFlag=TRUE; - break; - case CHRTYPE: - case BLKTYPE: - case FIFOTYPE: - if (tarExtractSpecial( &header, extractFlag, tostdoutFlag)==FALSE) - errorFlag=TRUE; - break; -#if 0 - /* Handled earlier */ - case GNULONGNAME: - case GNULONGLINK: - skipNextHeaderFlag=TRUE; - break; -#endif - default: - error_msg("Unknown file type '%c' in tar file", header.type); - close( tarFd); - return( FALSE); - } - } - close(tarFd); - if (status > 0) { - /* Bummer - we read a partial header */ - perror_msg("Error reading tar file"); - return ( FALSE); - } - else if (errorFlag==TRUE) { - error_msg( "Error exit delayed from previous errors"); - return( FALSE); - } else - return( status); - - /* Stuff to do when we are done */ -endgame: - close( tarFd); - if ( *(header.name) == '\0' ) { - if (errorFlag==TRUE) - error_msg( "Error exit delayed from previous errors"); - else - return( TRUE); - } - return( FALSE); -} - - -#ifdef BB_FEATURE_TAR_CREATE - -/* -** writeTarFile(), writeFileToTarball(), and writeTarHeader() are -** the only functions that deal with the HardLinkInfo structure. -** Even these functions use the xxxHardLinkInfo() functions. -*/ -typedef struct HardLinkInfo HardLinkInfo; -struct HardLinkInfo -{ - HardLinkInfo *next; /* Next entry in list */ - dev_t dev; /* Device number */ - ino_t ino; /* Inode number */ - short linkCount; /* (Hard) Link Count */ - char name[1]; /* Start of filename (must be last) */ -}; - -/* Some info to be carried along when creating a new tarball */ -struct TarBallInfo -{ - char* fileName; /* File name of the tarball */ - int tarFd; /* Open-for-write file descriptor - for the tarball */ - struct stat statBuf; /* Stat info for the tarball, letting - us know the inode and device that the - tarball lives, so we can avoid trying - to include the tarball into itself */ - int verboseFlag; /* Whether to print extra stuff or not */ - char** excludeList; /* List of files to not include */ - HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */ - HardLinkInfo *hlInfo; /* Hard Link Info for the current file */ -}; -typedef struct TarBallInfo TarBallInfo; - - -/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */ -static void -addHardLinkInfo (HardLinkInfo **hlInfoHeadPtr, dev_t dev, ino_t ino, - short linkCount, const char *name) -{ - /* Note: hlInfoHeadPtr can never be NULL! */ - HardLinkInfo *hlInfo; - - hlInfo = (HardLinkInfo *)xmalloc(sizeof(HardLinkInfo)+strlen(name)+1); - if (hlInfo) { - hlInfo->next = *hlInfoHeadPtr; - *hlInfoHeadPtr = hlInfo; - hlInfo->dev = dev; - hlInfo->ino = ino; - hlInfo->linkCount = linkCount; - strcpy(hlInfo->name, name); - } - return; -} - -static void -freeHardLinkInfo (HardLinkInfo **hlInfoHeadPtr) -{ - HardLinkInfo *hlInfo = NULL; - HardLinkInfo *hlInfoNext = NULL; - - if (hlInfoHeadPtr) { - hlInfo = *hlInfoHeadPtr; - while (hlInfo) { - hlInfoNext = hlInfo->next; - free(hlInfo); - hlInfo = hlInfoNext; - } - *hlInfoHeadPtr = NULL; - } - return; -} - -/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */ -static HardLinkInfo * -findHardLinkInfo (HardLinkInfo *hlInfo, dev_t dev, ino_t ino) -{ - while(hlInfo) { - if ((ino == hlInfo->ino) && (dev == hlInfo->dev)) - break; - hlInfo = hlInfo->next; - } - return(hlInfo); -} - -/* Put an octal string into the specified buffer. - * The number is zero and space padded and possibly null padded. - * Returns TRUE if successful. */ -static int putOctal (char *cp, int len, long value) -{ - int tempLength; - char tempBuffer[32]; - char *tempString = tempBuffer; - - /* Create a string of the specified length with an initial space, - * leading zeroes and the octal number, and a trailing null. */ - sprintf (tempString, "%0*lo", len - 1, value); - - /* If the string is too large, suppress the leading space. */ - tempLength = strlen (tempString) + 1; - if (tempLength > len) { - tempLength--; - tempString++; - } - - /* If the string is still too large, suppress the trailing null. */ - if (tempLength > len) - tempLength--; - - /* If the string is still too large, fail. */ - if (tempLength > len) - return FALSE; - - /* Copy the string to the field. */ - memcpy (cp, tempString, len); - - return TRUE; -} - -/* Write out a tar header for the specified file/directory/whatever */ -static int -writeTarHeader(struct TarBallInfo *tbInfo, const char *header_name, - const char *real_name, struct stat *statbuf) -{ - long chksum=0; - struct TarHeader header; - const unsigned char *cp = (const unsigned char *) &header; - ssize_t size = sizeof(struct TarHeader); - - memset( &header, 0, size); - - strncpy(header.name, header_name, sizeof(header.name)); - - putOctal(header.mode, sizeof(header.mode), statbuf->st_mode); - putOctal(header.uid, sizeof(header.uid), statbuf->st_uid); - putOctal(header.gid, sizeof(header.gid), statbuf->st_gid); - putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */ - putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime); - strncpy(header.magic, TAR_MAGIC TAR_VERSION, - TAR_MAGIC_LEN + TAR_VERSION_LEN ); - - /* Enter the user and group names (default to root if it fails) */ - my_getpwuid(header.uname, statbuf->st_uid); - if (! *header.uname) - strcpy(header.uname, "root"); - my_getgrgid(header.gname, statbuf->st_gid); - if (! *header.uname) - strcpy(header.uname, "root"); - - if (tbInfo->hlInfo) { - /* This is a hard link */ - header.typeflag = LNKTYPE; - strncpy(header.linkname, tbInfo->hlInfo->name, sizeof(header.linkname)); - } else if (S_ISLNK(statbuf->st_mode)) { - char *lpath = xreadlink(real_name); - if (!lpath) /* Already printed err msg inside xreadlink() */ - return ( FALSE); - header.typeflag = SYMTYPE; - strncpy(header.linkname, lpath, sizeof(header.linkname)); - free(lpath); - } else if (S_ISDIR(statbuf->st_mode)) { - header.typeflag = DIRTYPE; - strncat(header.name, "/", sizeof(header.name)); - } else if (S_ISCHR(statbuf->st_mode)) { - header.typeflag = CHRTYPE; - putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev)); - putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev)); - } else if (S_ISBLK(statbuf->st_mode)) { - header.typeflag = BLKTYPE; - putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev)); - putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev)); - } else if (S_ISFIFO(statbuf->st_mode)) { - header.typeflag = FIFOTYPE; - } else if (S_ISREG(statbuf->st_mode)) { - header.typeflag = REGTYPE; - putOctal(header.size, sizeof(header.size), statbuf->st_size); - } else { - error_msg("%s: Unknown file type", real_name); - return ( FALSE); - } - - /* Calculate and store the checksum (i.e., the sum of all of the bytes of - * the header). The checksum field must be filled with blanks for the - * calculation. The checksum field is formatted differently from the - * other fields: it has [6] digits, a null, then a space -- rather than - * digits, followed by a null like the other fields... */ - memset(header.chksum, ' ', sizeof(header.chksum)); - cp = (const unsigned char *) &header; - while (size-- > 0) - chksum += *cp++; - putOctal(header.chksum, 7, chksum); - - /* Now write the header out to disk */ - if ((size=full_write(tbInfo->tarFd, (char*)&header, sizeof(struct TarHeader))) < 0) { - error_msg(io_error, real_name, strerror(errno)); - return ( FALSE); - } - /* Pad the header up to the tar block size */ - for (; sizetarFd, "\0", 1); - } - /* Now do the verbose thing (or not) */ - if (tbInfo->verboseFlag==TRUE) { - FILE *vbFd = stdout; - if (tbInfo->tarFd == fileno(stdout)) // If the archive goes to stdout, verbose to stderr - vbFd = stderr; - fprintf(vbFd, "%s\n", header.name); - } - - return ( TRUE); -} - - -static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData) -{ - struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData; - const char *header_name; - - /* - ** Check to see if we are dealing with a hard link. - ** If so - - ** Treat the first occurance of a given dev/inode as a file while - ** treating any additional occurances as hard links. This is done - ** by adding the file information to the HardLinkInfo linked list. - */ - tbInfo->hlInfo = NULL; - if (statbuf->st_nlink > 1) { - tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf->st_dev, - statbuf->st_ino); - if (tbInfo->hlInfo == NULL) - addHardLinkInfo (&tbInfo->hlInfoHead, statbuf->st_dev, - statbuf->st_ino, statbuf->st_nlink, fileName); - } - - /* It is against the rules to archive a socket */ - if (S_ISSOCK(statbuf->st_mode)) { - error_msg("%s: socket ignored", fileName); - return( TRUE); - } - - /* It is a bad idea to store the archive we are in the process of creating, - * so check the device and inode to be sure that this particular file isn't - * the new tarball */ - if (tbInfo->statBuf.st_dev == statbuf->st_dev && - tbInfo->statBuf.st_ino == statbuf->st_ino) { - error_msg("%s: file is the archive; skipping", fileName); - return( TRUE); - } - - header_name = fileName; - while (header_name[0] == '/') { - static int alreadyWarned=FALSE; - if (alreadyWarned==FALSE) { - error_msg("Removing leading '/' from member names"); - alreadyWarned=TRUE; - } - header_name++; - } - - if (strlen(fileName) >= NAME_SIZE) { - error_msg(name_longer_than_foo, NAME_SIZE); - return ( TRUE); - } - - if (header_name[0] == '\0') - return TRUE; - -#if defined BB_FEATURE_TAR_EXCLUDE - if (exclude_file(tbInfo->excludeList, header_name)) { - return SKIP; - } -#endif - - if (writeTarHeader(tbInfo, header_name, fileName, statbuf)==FALSE) { - return( FALSE); - } - - /* Now, if the file is a regular file, copy it out to the tarball */ - if ((tbInfo->hlInfo == NULL) - && (S_ISREG(statbuf->st_mode))) { - int inputFileFd; - char buffer[BUFSIZ]; - ssize_t size=0, readSize=0; - - /* open the file we want to archive, and make sure all is well */ - if ((inputFileFd = open(fileName, O_RDONLY)) < 0) { - error_msg("%s: Cannot open: %s", fileName, strerror(errno)); - return( FALSE); - } - - /* write the file to the archive */ - while ( (size = full_read(inputFileFd, buffer, sizeof(buffer))) > 0 ) { - if (full_write(tbInfo->tarFd, buffer, size) != size ) { - /* Output file seems to have a problem */ - error_msg(io_error, fileName, strerror(errno)); - return( FALSE); - } - readSize+=size; - } - if (size == -1) { - error_msg(io_error, fileName, strerror(errno)); - return( FALSE); - } - /* Pad the file up to the tar block size */ - for (; (readSize%TAR_BLOCK_SIZE) != 0; readSize++) { - write(tbInfo->tarFd, "\0", 1); - } - close( inputFileFd); - } - - return( TRUE); -} - -static int writeTarFile(const char* tarName, int verboseFlag, char **argv, - char** excludeList) -{ - int tarFd=-1; - int errorFlag=FALSE; - ssize_t size; - struct TarBallInfo tbInfo; - tbInfo.verboseFlag = verboseFlag; - tbInfo.hlInfoHead = NULL; - - /* Make sure there is at least one file to tar up. */ - if (*argv == NULL) - error_msg_and_die("Cowardly refusing to create an empty archive"); - - /* Open the tar file for writing. */ - if (!strcmp(tarName, "-")) - tbInfo.tarFd = fileno(stdout); - else - tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (tbInfo.tarFd < 0) { - perror_msg( "Error opening '%s'", tarName); - freeHardLinkInfo(&tbInfo.hlInfoHead); - return ( FALSE); - } - tbInfo.excludeList=excludeList; - /* Store the stat info for the tarball's file, so - * can avoid including the tarball into itself.... */ - if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) - error_msg_and_die(io_error, tarName, strerror(errno)); - - /* Read the directory/files and iterate over them one at a time */ - while (*argv != NULL) { - if (recursive_action(*argv++, TRUE, FALSE, FALSE, - writeFileToTarball, writeFileToTarball, - (void*) &tbInfo) == FALSE) { - errorFlag = TRUE; - } - } - /* Write two empty blocks to the end of the archive */ - for (size=0; size<(2*TAR_BLOCK_SIZE); size++) { - write(tbInfo.tarFd, "\0", 1); - } - - /* To be pedantically correct, we would check if the tarball - * is smaller than 20 tar blocks, and pad it if it was smaller, - * but that isn't necessary for GNU tar interoperability, and - * so is considered a waste of space */ - - /* Hang up the tools, close up shop, head home */ - close(tarFd); - if (errorFlag == TRUE) { - error_msg("Error exit delayed from previous errors"); - freeHardLinkInfo(&tbInfo.hlInfoHead); - return(FALSE); - } - freeHardLinkInfo(&tbInfo.hlInfoHead); - return( TRUE); -} - - -#endif - diff --git a/busybox/ash.c b/busybox/ash.c deleted file mode 100644 index c0d47559d..000000000 --- a/busybox/ash.c +++ /dev/null @@ -1,12888 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * ash shell port for busybox - * - * Copyright (c) 1989, 1991, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * 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 - * - * This version of ash is adapted from the source in Debian's ash 0.3.8-5 - * package. - * - * Modified by Erik Andersen and - * Vladimir Oleynik to be used in busybox - * - * - * Original copyright notice is retained at the end of this file. - */ - - -/* These defines allow you to adjust the feature set to be compiled - * into the ash shell. As a rule, enabling these options will make - * ash get bigger... With all of these options off, ash adds about - * 60k to busybox on an x86 system.*/ - - -/* Enable job control. This allows you to run jobs in the background, - * which is great when ash is being used as an interactive shell, but - * it completely useless for is all you are doing is running scripts. - * This adds about 2.5k on an x86 system. */ -#undef JOBS - -/* This enables alias support in ash. If you want to support things - * like "alias ls='ls -l'" with ash, enable this. This is only useful - * when ash is used as an intractive shell. This adds about 1.5k */ -#define ASH_ALIAS - -/* If you need ash to act as a full Posix shell, with full math - * support, enable this. This adds a bit over 2k an x86 system. */ -//#undef ASH_MATH_SUPPORT -#define ASH_MATH_SUPPORT - -/* Getopts is used by shell procedures to parse positional parameters. - * You probably want to leave this disabled, and use the busybox getopt - * applet if you want to do this sort of thing. There are some scripts - * out there that use it, so if you need it, enable it. Most people will - * leave this disabled. This adds 1k on an x86 system. */ -#undef ASH_GETOPTS - -/* This allows you to override shell builtins and use whatever is on - * the filesystem. This is most useful when ash is acting as a - * standalone shell. Adds about 272 bytes. */ -#undef ASH_CMDCMD - - -/* Optimize size vs speed as size */ -#define ASH_OPTIMIZE_FOR_SIZE - -/* Enable this to compile in extra debugging noise. When debugging is - * on, debugging info will be written to $HOME/trace and a quit signal - * will generate a core dump. */ -#undef DEBUG - -/* These are here to work with glibc -- Don't change these... */ -#undef FNMATCH_BROKEN -#undef GLOB_BROKEN -#define IFS_BROKEN - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#if !defined(FNMATCH_BROKEN) -#include -#endif -#if !defined(GLOB_BROKEN) -#include -#endif - -#ifdef JOBS -#include -#endif - -#include "busybox.h" -#include "cmdedit.h" - -/* - * This file was generated by the mksyntax program. - */ - -/* Syntax classes */ -#define CWORD 0 /* character is nothing special */ -#define CNL 1 /* newline character */ -#define CBACK 2 /* a backslash character */ -#define CSQUOTE 3 /* single quote */ -#define CDQUOTE 4 /* double quote */ -#define CENDQUOTE 5 /* a terminating quote */ -#define CBQUOTE 6 /* backwards single quote */ -#define CVAR 7 /* a dollar sign */ -#define CENDVAR 8 /* a '}' character */ -#define CLP 9 /* a left paren in arithmetic */ -#define CRP 10 /* a right paren in arithmetic */ -#define CENDFILE 11 /* end of file */ -#define CCTL 12 /* like CWORD, except it must be escaped */ -#define CSPCL 13 /* these terminate a word */ -#define CIGN 14 /* character should be ignored */ - -/* Syntax classes for is_ functions */ -#define ISDIGIT 01 /* a digit */ -#define ISUPPER 02 /* an upper case letter */ -#define ISLOWER 04 /* a lower case letter */ -#define ISUNDER 010 /* an underscore */ -#define ISSPECL 020 /* the name of a special parameter */ - -#define SYNBASE 130 -#define PEOF -130 - -#define PEOA -129 - -#define TEOF 0 -#define TNL 1 -#define TSEMI 2 -#define TBACKGND 3 -#define TAND 4 -#define TOR 5 -#define TPIPE 6 -#define TLP 7 -#define TRP 8 -#define TENDCASE 9 -#define TENDBQUOTE 10 -#define TREDIR 11 -#define TWORD 12 -#define TASSIGN 13 -#define TNOT 14 -#define TCASE 15 -#define TDO 16 -#define TDONE 17 -#define TELIF 18 -#define TELSE 19 -#define TESAC 20 -#define TFI 21 -#define TFOR 22 -#define TIF 23 -#define TIN 24 -#define TTHEN 25 -#define TUNTIL 26 -#define TWHILE 27 -#define TBEGIN 28 -#define TEND 29 - - -#define BASESYNTAX (basesyntax + SYNBASE) -#define DQSYNTAX (dqsyntax + SYNBASE) -#define SQSYNTAX (sqsyntax + SYNBASE) -#define ARISYNTAX (arisyntax + SYNBASE) - -/* control characters in argument strings */ -#define CTLESC '\201' -#define CTLVAR '\202' -#define CTLENDVAR '\203' -#define CTLBACKQ '\204' -#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ -/* CTLBACKQ | CTLQUOTE == '\205' */ -#define CTLARI '\206' -#define CTLENDARI '\207' -#define CTLQUOTEMARK '\210' - -#define is_digit(c) ((c)>='0' && (c)<='9') -#define is_alpha(c) (((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c))) -#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c)))) -#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c)))) -#define is_special(c) ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT)) -#define digit_val(c) ((c) - '0') - - -#define _DIAGASSERT(x) - - - -#define S_DFL 1 /* default signal handling (SIG_DFL) */ -#define S_CATCH 2 /* signal is caught */ -#define S_IGN 3 /* signal is ignored (SIG_IGN) */ -#define S_HARD_IGN 4 /* signal is ignored permenantly */ -#define S_RESET 5 /* temporary - to reset a hard ignored sig */ - - -/* variable substitution byte (follows CTLVAR) */ -#define VSTYPE 0x0f /* type of variable substitution */ -#define VSNUL 0x10 /* colon--treat the empty string as unset */ -#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ - -/* values of VSTYPE field */ -#define VSNORMAL 0x1 /* normal variable: $var or ${var} */ -#define VSMINUS 0x2 /* ${var-text} */ -#define VSPLUS 0x3 /* ${var+text} */ -#define VSQUESTION 0x4 /* ${var?message} */ -#define VSASSIGN 0x5 /* ${var=text} */ -#define VSTRIMLEFT 0x6 /* ${var#pattern} */ -#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */ -#define VSTRIMRIGHT 0x8 /* ${var%pattern} */ -#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */ -#define VSLENGTH 0xa /* ${#var} */ - -/* flags passed to redirect */ -#define REDIR_PUSH 01 /* save previous values of file descriptors */ -#define REDIR_BACKQ 02 /* save the command output to pipe */ - -/* - * BSD setjmp saves the signal mask, which violates ANSI C and takes time, - * so we use _setjmp instead. - */ - -#if defined(BSD) -#define setjmp(jmploc) _setjmp(jmploc) -#define longjmp(jmploc, val) _longjmp(jmploc, val) -#endif - -/* - * Most machines require the value returned from malloc to be aligned - * in some way. The following macro will get this right on many machines. - */ - -#ifndef ALIGN -union align { - int i; - char *cp; -}; - -#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1)) -#endif - -#ifdef BB_LOCALE_SUPPORT -#include -static void change_lc_all(const char *value); -static void change_lc_ctype(const char *value); -#endif - -/* - * These macros allow the user to suspend the handling of interrupt signals - * over a period of time. This is similar to SIGHOLD to or sigblock, but - * much more efficient and portable. (But hacking the kernel is so much - * more fun than worrying about efficiency and portability. :-)) - */ - -static void onint (void); -static volatile int suppressint; -static volatile int intpending; - -#define INTOFF suppressint++ -#ifndef ASH_OPTIMIZE_FOR_SIZE -#define INTON { if (--suppressint == 0 && intpending) onint(); } -#define FORCEINTON {suppressint = 0; if (intpending) onint();} -#else -static void __inton (void); -static void forceinton (void); -#define INTON __inton() -#define FORCEINTON forceinton() -#endif - -#define CLEAR_PENDING_INT intpending = 0 -#define int_pending() intpending - - -typedef void *pointer; -#ifndef NULL -#define NULL (void *)0 -#endif - -static inline pointer ckmalloc (int sz) { return xmalloc(sz); } -static inline pointer ckrealloc(void *p, int sz) { return xrealloc(p, sz); } -static inline char * savestr (const char *s) { return xstrdup(s); } - -static pointer stalloc (int); -static void stunalloc (pointer); -static void ungrabstackstr (char *, char *); -static char * growstackstr(void); -static char * makestrspace(size_t newlen); -static char *sstrdup (const char *); - -/* - * Parse trees for commands are allocated in lifo order, so we use a stack - * to make this more efficient, and also to avoid all sorts of exception - * handling code to handle interrupts in the middle of a parse. - * - * The size 504 was chosen because the Ultrix malloc handles that size - * well. - */ - -#define MINSIZE 504 /* minimum size of a block */ - - -struct stack_block { - struct stack_block *prev; - char space[MINSIZE]; -}; - -static struct stack_block stackbase; -static struct stack_block *stackp = &stackbase; -static struct stackmark *markp; -static char *stacknxt = stackbase.space; -static int stacknleft = MINSIZE; - - -#define equal(s1, s2) (strcmp(s1, s2) == 0) - -#define stackblock() stacknxt -#define stackblocksize() stacknleft -#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize() - -#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c))) -#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); } -#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0')) - - -#define USTPUTC(c, p) (--sstrnleft, *p++ = (c)) -#define STUNPUTC(p) (++sstrnleft, --p) -#define STTOPC(p) p[-1] -#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount)) -#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft) - -#define ckfree(p) free((pointer)(p)) - - -#ifdef DEBUG -#define TRACE(param) trace param -static void trace (const char *, ...); -static void trargs (char **); -static void showtree (union node *); -static void trputc (int); -static void trputs (const char *); -static void opentrace (void); -#else -#define TRACE(param) -#endif - -#define NSEMI 0 -#define NCMD 1 -#define NPIPE 2 -#define NREDIR 3 -#define NBACKGND 4 -#define NSUBSHELL 5 -#define NAND 6 -#define NOR 7 -#define NIF 8 -#define NWHILE 9 -#define NUNTIL 10 -#define NFOR 11 -#define NCASE 12 -#define NCLIST 13 -#define NDEFUN 14 -#define NARG 15 -#define NTO 16 -#define NFROM 17 -#define NFROMTO 18 -#define NAPPEND 19 -#define NTOOV 20 -#define NTOFD 21 -#define NFROMFD 22 -#define NHERE 23 -#define NXHERE 24 -#define NNOT 25 - -/* - * expandarg() flags - */ -#define EXP_FULL 0x1 /* perform word splitting & file globbing */ -#define EXP_TILDE 0x2 /* do normal tilde expansion */ -#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ -#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ -#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ -#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */ - - -#define NOPTS 16 - -static char optet_vals[NOPTS]; - -static const char * const optlist[NOPTS] = { - "e" "errexit", - "f" "noglob", - "I" "ignoreeof", - "i" "interactive", - "m" "monitor", - "n" "noexec", - "s" "stdin", - "x" "xtrace", - "v" "verbose", - "V" "vi", - "E" "emacs", - "C" "noclobber", - "a" "allexport", - "b" "notify", - "u" "nounset", - "q" "quietprofile" -}; - -#define optent_name(optent) (optent+1) -#define optent_letter(optent) optent[0] -#define optent_val(optent) optet_vals[optent] - -#define eflag optent_val(0) -#define fflag optent_val(1) -#define Iflag optent_val(2) -#define iflag optent_val(3) -#define mflag optent_val(4) -#define nflag optent_val(5) -#define sflag optent_val(6) -#define xflag optent_val(7) -#define vflag optent_val(8) -#define Vflag optent_val(9) -#define Eflag optent_val(10) -#define Cflag optent_val(11) -#define aflag optent_val(12) -#define bflag optent_val(13) -#define uflag optent_val(14) -#define qflag optent_val(15) - - -/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ -#define FORK_FG 0 -#define FORK_BG 1 -#define FORK_NOJOB 2 - - -struct nbinary { - int type; - union node *ch1; - union node *ch2; -}; - - -struct ncmd { - int type; - int backgnd; - union node *assign; - union node *args; - union node *redirect; -}; - - -struct npipe { - int type; - int backgnd; - struct nodelist *cmdlist; -}; - - -struct nredir { - int type; - union node *n; - union node *redirect; -}; - - -struct nif { - int type; - union node *test; - union node *ifpart; - union node *elsepart; -}; - - -struct nfor { - int type; - union node *args; - union node *body; - char *var; -}; - - -struct ncase { - int type; - union node *expr; - union node *cases; -}; - - -struct nclist { - int type; - union node *next; - union node *pattern; - union node *body; -}; - - -struct narg { - int type; - union node *next; - char *text; - struct nodelist *backquote; -}; - - -struct nfile { - int type; - union node *next; - int fd; - union node *fname; - char *expfname; -}; - - -struct ndup { - int type; - union node *next; - int fd; - int dupfd; - union node *vname; -}; - - -struct nhere { - int type; - union node *next; - int fd; - union node *doc; -}; - - -struct nnot { - int type; - union node *com; -}; - - -union node { - int type; - struct nbinary nbinary; - struct ncmd ncmd; - struct npipe npipe; - struct nredir nredir; - struct nif nif; - struct nfor nfor; - struct ncase ncase; - struct nclist nclist; - struct narg narg; - struct nfile nfile; - struct ndup ndup; - struct nhere nhere; - struct nnot nnot; -}; - - -struct nodelist { - struct nodelist *next; - union node *n; -}; - -struct backcmd { /* result of evalbackcmd */ - int fd; /* file descriptor to read from */ - char *buf; /* buffer */ - int nleft; /* number of chars in buffer */ - struct job *jp; /* job structure for command */ -}; - -struct cmdentry { - int cmdtype; - union param { - int index; - union node *func; - const struct builtincmd *cmd; - } u; -}; - -struct strlist { - struct strlist *next; - char *text; -}; - - -struct arglist { - struct strlist *list; - struct strlist **lastp; -}; - -struct strpush { - struct strpush *prev; /* preceding string on stack */ - char *prevstring; - int prevnleft; -#ifdef ASH_ALIAS - struct alias *ap; /* if push was associated with an alias */ -#endif - char *string; /* remember the string since it may change */ -}; - -struct parsefile { - struct parsefile *prev; /* preceding file on stack */ - int linno; /* current line */ - int fd; /* file descriptor (or -1 if string) */ - int nleft; /* number of chars left in this line */ - int lleft; /* number of chars left in this buffer */ - char *nextc; /* next char in buffer */ - char *buf; /* input buffer */ - struct strpush *strpush; /* for pushing strings at this level */ - struct strpush basestrpush; /* so pushing one is fast */ -}; - -struct stackmark { - struct stack_block *stackp; - char *stacknxt; - int stacknleft; - struct stackmark *marknext; -}; - -struct shparam { - int nparam; /* # of positional parameters (without $0) */ - unsigned char malloc; /* if parameter list dynamically allocated */ - char **p; /* parameter list */ - int optind; /* next parameter to be processed by getopts */ - int optoff; /* used by getopts */ -}; - -/* - * When commands are first encountered, they are entered in a hash table. - * This ensures that a full path search will not have to be done for them - * on each invocation. - * - * We should investigate converting to a linear search, even though that - * would make the command name "hash" a misnomer. - */ -#define CMDTABLESIZE 31 /* should be prime */ -#define ARB 1 /* actual size determined at run time */ - - - -struct tblentry { - struct tblentry *next; /* next entry in hash chain */ - union param param; /* definition of builtin function */ - short cmdtype; /* index identifying command */ - char rehash; /* if set, cd done since entry created */ - char cmdname[ARB]; /* name of command */ -}; - - -static struct tblentry *cmdtable[CMDTABLESIZE]; -static int builtinloc = -1; /* index in path of %builtin, or -1 */ -static int exerrno = 0; /* Last exec error */ - - -static void tryexec (char *, char **, char **); -static void printentry (struct tblentry *, int); -static void clearcmdentry (int); -static struct tblentry *cmdlookup (const char *, int); -static void delete_cmd_entry (void); -static int path_change (const char *, int *); - - -static void flushall (void); -static void out2fmt (const char *, ...) - __attribute__((__format__(__printf__,1,2))); -static int xwrite (int, const char *, int); - -static void outstr (const char *p, FILE *file) { fputs(p, file); } -static void out1str(const char *p) { outstr(p, stdout); } -static void out2str(const char *p) { outstr(p, stderr); } - -#ifndef ASH_OPTIMIZE_FOR_SIZE -#define out2c(c) putc((c), stderr) -#else -static void out2c(int c) { putc(c, stderr); } -#endif - -/* syntax table used when not in quotes */ -static const char basesyntax[257] = { - CENDFILE, CSPCL, CWORD, CCTL, - CCTL, CCTL, CCTL, CCTL, - CCTL, CCTL, CCTL, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CSPCL, - CNL, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CSPCL, CWORD, - CDQUOTE, CWORD, CVAR, CWORD, - CSPCL, CSQUOTE, CSPCL, CSPCL, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CSPCL, CSPCL, CWORD, - CSPCL, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CBACK, CWORD, - CWORD, CWORD, CBQUOTE, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CSPCL, CENDVAR, - CWORD -}; - -/* syntax table used when in double quotes */ -static const char dqsyntax[257] = { - CENDFILE, CIGN, CWORD, CCTL, - CCTL, CCTL, CCTL, CCTL, - CCTL, CCTL, CCTL, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CNL, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CCTL, - CENDQUOTE,CWORD, CVAR, CWORD, - CWORD, CWORD, CWORD, CWORD, - CCTL, CWORD, CWORD, CCTL, - CWORD, CCTL, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CCTL, CWORD, CWORD, CCTL, - CWORD, CCTL, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CCTL, CBACK, CCTL, - CWORD, CWORD, CBQUOTE, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CENDVAR, - CCTL -}; - -/* syntax table used when in single quotes */ -static const char sqsyntax[257] = { - CENDFILE, CIGN, CWORD, CCTL, - CCTL, CCTL, CCTL, CCTL, - CCTL, CCTL, CCTL, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CNL, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CCTL, - CWORD, CWORD, CWORD, CWORD, - CWORD, CENDQUOTE,CWORD, CWORD, - CCTL, CWORD, CWORD, CCTL, - CWORD, CCTL, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CCTL, CWORD, CWORD, CCTL, - CWORD, CCTL, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CCTL, CCTL, CCTL, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CCTL -}; - -/* syntax table used when in arithmetic */ -static const char arisyntax[257] = { - CENDFILE, CIGN, CWORD, CCTL, - CCTL, CCTL, CCTL, CCTL, - CCTL, CCTL, CCTL, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CNL, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CDQUOTE, CWORD, CVAR, CWORD, - CWORD, CSQUOTE, CLP, CRP, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CBACK, CWORD, - CWORD, CWORD, CBQUOTE, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CENDVAR, - CWORD -}; - -/* character classification table */ -static const char is_type[257] = { - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, ISSPECL, - 0, ISSPECL, ISSPECL, 0, - 0, 0, 0, 0, - ISSPECL, 0, 0, ISSPECL, - 0, 0, ISDIGIT, ISDIGIT, - ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, - ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, - 0, 0, 0, 0, - 0, ISSPECL, ISSPECL, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, 0, 0, 0, - 0, ISUNDER, 0, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, 0, 0, 0, - 0 -}; - -/* Array indicating which tokens mark the end of a list */ -static const char tokendlist[] = { - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, -}; - -static const char *const tokname[] = { - "end of file", - "newline", - "\";\"", - "\"&\"", - "\"&&\"", - "\"||\"", - "\"|\"", - "\"(\"", - "\")\"", - "\";;\"", - "\"`\"", - "redirection", - "word", - "assignment", - "\"!\"", - "\"case\"", - "\"do\"", - "\"done\"", - "\"elif\"", - "\"else\"", - "\"esac\"", - "\"fi\"", - "\"for\"", - "\"if\"", - "\"in\"", - "\"then\"", - "\"until\"", - "\"while\"", - "\"{\"", - "\"}\"", -}; - -#define KWDOFFSET 14 - -static const char *const parsekwd[] = { - "!", - "case", - "do", - "done", - "elif", - "else", - "esac", - "fi", - "for", - "if", - "in", - "then", - "until", - "while", - "{", - "}" -}; - - -static int plinno = 1; /* input line number */ - -static int parselleft; /* copy of parsefile->lleft */ - -static struct parsefile basepf; /* top level input file */ -static char basebuf[BUFSIZ]; /* buffer for top level input file */ -static struct parsefile *parsefile = &basepf; /* current input file */ - -/* - * NEOF is returned by parsecmd when it encounters an end of file. It - * must be distinct from NULL, so we use the address of a variable that - * happens to be handy. - */ - -static int tokpushback; /* last token pushed back */ -#define NEOF ((union node *)&tokpushback) -static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ - - -static void error (const char *, ...) __attribute__((__noreturn__)); -static void exerror (int, const char *, ...) __attribute__((__noreturn__)); -static void shellexec (char **, char **, const char *, int) - __attribute__((noreturn)); -static void exitshell (int) __attribute__((noreturn)); - -static int goodname(const char *); -static void ignoresig (int); -static void onsig (int); -static void dotrap (void); -static int decode_signal (const char *, int); - -static void shprocvar(void); -static void deletefuncs(void); -static void setparam (char **); -static void freeparam (volatile struct shparam *); - -/* reasons for skipping commands (see comment on breakcmd routine) */ -#define SKIPBREAK 1 -#define SKIPCONT 2 -#define SKIPFUNC 3 -#define SKIPFILE 4 - -/* values of cmdtype */ -#define CMDUNKNOWN -1 /* no entry in table for command */ -#define CMDNORMAL 0 /* command is an executable program */ -#define CMDBUILTIN 1 /* command is a shell builtin */ -#define CMDFUNCTION 2 /* command is a shell function */ - -#define DO_ERR 1 /* find_command prints errors */ -#define DO_ABS 2 /* find_command checks absolute paths */ -#define DO_NOFUN 4 /* find_command ignores functions */ -#define DO_BRUTE 8 /* find_command ignores hash table */ - -/* - * Shell variables. - */ - -/* flags */ -#define VEXPORT 0x01 /* variable is exported */ -#define VREADONLY 0x02 /* variable cannot be modified */ -#define VSTRFIXED 0x04 /* variable struct is staticly allocated */ -#define VTEXTFIXED 0x08 /* text is staticly allocated */ -#define VSTACK 0x10 /* text is allocated on the stack */ -#define VUNSET 0x20 /* the variable is not set */ -#define VNOFUNC 0x40 /* don't call the callback function */ - - -struct var { - struct var *next; /* next entry in hash list */ - int flags; /* flags are defined above */ - char *text; /* name=value */ - void (*func) (const char *); - /* function to be called when */ - /* the variable gets set/unset */ -}; - -struct localvar { - struct localvar *next; /* next local variable in list */ - struct var *vp; /* the variable that was made local */ - int flags; /* saved flags */ - char *text; /* saved text */ -}; - - -#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) -#define rmescapes(p) _rmescapes((p), 0) -static char *_rmescapes (char *, int); -#else -static void rmescapes (char *); -#endif - -static int casematch (union node *, const char *); -static void clearredir(void); -static void popstring(void); -static void readcmdfile (const char *); - -static int number (const char *); -static int is_number (const char *, int *num); -static char *single_quote (const char *); -static int nextopt (const char *); - -static void redirect (union node *, int); -static void popredir (void); -static int dup_as_newfd (int, int); - -static void changepath(const char *newval); -static void getoptsreset(const char *value); - - -static int parsenleft; /* copy of parsefile->nleft */ -static char *parsenextc; /* copy of parsefile->nextc */ -static int rootpid; /* pid of main shell */ -static int rootshell; /* true if we aren't a child of the main shell */ - -static const char spcstr[] = " "; -static const char snlfmt[] = "%s\n"; - -static int sstrnleft; -static int herefd = -1; - -static struct localvar *localvars; - -static struct var vifs; -static struct var vmail; -static struct var vmpath; -static struct var vpath; -static struct var vps1; -static struct var vps2; -static struct var voptind; -#ifdef BB_LOCALE_SUPPORT -static struct var vlc_all; -static struct var vlc_ctype; -#endif - -struct varinit { - struct var *var; - int flags; - const char *text; - void (*func) (const char *); -}; - -static const char defpathvar[] = - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; -#define defpath (defpathvar + 5) - -#ifdef IFS_BROKEN -static const char defifsvar[] = "IFS= \t\n"; -#define defifs (defifsvar + 4) -#else -static const char defifs[] = " \t\n"; -#endif - -static const struct varinit varinit[] = { -#ifdef IFS_BROKEN - { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar, -#else - { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=", -#endif - NULL }, - { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=", - NULL }, - { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=", - NULL }, - { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar, - changepath }, - /* - * vps1 depends on uid - */ - { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ", - NULL }, - { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1", - getoptsreset }, -#ifdef BB_LOCALE_SUPPORT - { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=", - change_lc_all }, - { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=", - change_lc_ctype }, -#endif - { NULL, 0, NULL, - NULL } -}; - -#define VTABSIZE 39 - -static struct var *vartab[VTABSIZE]; - -/* - * The following macros access the values of the above variables. - * They have to skip over the name. They return the null string - * for unset variables. - */ - -#define ifsval() (vifs.text + 4) -#define ifsset() ((vifs.flags & VUNSET) == 0) -#define mailval() (vmail.text + 5) -#define mpathval() (vmpath.text + 9) -#define pathval() (vpath.text + 5) -#define ps1val() (vps1.text + 4) -#define ps2val() (vps2.text + 4) -#define optindval() (voptind.text + 7) - -#define mpathset() ((vmpath.flags & VUNSET) == 0) - -static void initvar (void); -static void setvar (const char *, const char *, int); -static void setvareq (char *, int); -static void listsetvar (struct strlist *); -static const char *lookupvar (const char *); -static const char *bltinlookup (const char *); -static char **environment (void); -static int showvarscmd (int, char **); -static void mklocal (char *); -static void poplocalvars (void); -static int unsetvar (const char *); -static int varequal (const char *, const char *); - - -static char *arg0; /* value of $0 */ -static struct shparam shellparam; /* current positional parameters */ -static char **argptr; /* argument list for builtin commands */ -static char *optionarg; /* set by nextopt (like getopt) */ -static char *optptr; /* used by nextopt */ -static char *minusc; /* argument to -c option */ - - -#ifdef ASH_ALIAS - -#define ALIASINUSE 1 -#define ALIASDEAD 2 - -#define ATABSIZE 39 - -struct alias { - struct alias *next; - char *name; - char *val; - int flag; -}; - -static struct alias *atab[ATABSIZE]; - -static void setalias (char *, char *); -static struct alias **hashalias (const char *); -static struct alias *freealias (struct alias *); -static struct alias **__lookupalias (const char *); - -static void -setalias(name, val) - char *name, *val; -{ - struct alias *ap, **app; - - app = __lookupalias(name); - ap = *app; - INTOFF; - if (ap) { - if (!(ap->flag & ALIASINUSE)) { - ckfree(ap->val); - } - ap->val = savestr(val); - ap->flag &= ~ALIASDEAD; - } else { - /* not found */ - ap = ckmalloc(sizeof (struct alias)); - ap->name = savestr(name); - ap->val = savestr(val); - ap->flag = 0; - ap->next = 0; - *app = ap; - } - INTON; -} - -static int -unalias(char *name) -{ - struct alias **app; - - app = __lookupalias(name); - - if (*app) { - INTOFF; - *app = freealias(*app); - INTON; - return (0); - } - - return (1); -} - -static void -rmaliases(void) -{ - struct alias *ap, **app; - int i; - - INTOFF; - for (i = 0; i < ATABSIZE; i++) { - app = &atab[i]; - for (ap = *app; ap; ap = *app) { - *app = freealias(*app); - if (ap == *app) { - app = &ap->next; - } - } - } - INTON; -} - -static struct alias * -lookupalias(const char *name, int check) -{ - struct alias *ap = *__lookupalias(name); - - if (check && ap && (ap->flag & ALIASINUSE)) - return (NULL); - return (ap); -} - -static void -printalias(const struct alias *ap) { - char *p; - - p = single_quote(ap->val); - printf("alias %s=%s\n", ap->name, p); - stunalloc(p); -} - - -/* - * TODO - sort output - */ -static int -aliascmd(int argc, char **argv) -{ - char *n, *v; - int ret = 0; - struct alias *ap; - - if (argc == 1) { - int i; - - for (i = 0; i < ATABSIZE; i++) - for (ap = atab[i]; ap; ap = ap->next) { - printalias(ap); - } - return (0); - } - while ((n = *++argv) != NULL) { - if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */ - if ((ap = *__lookupalias(n)) == NULL) { - out2fmt("%s: %s not found\n", "alias", n); - ret = 1; - } else - printalias(ap); - } - else { - *v++ = '\0'; - setalias(n, v); - } - } - - return (ret); -} - -static int -unaliascmd(int argc, char **argv) -{ - int i; - - while ((i = nextopt("a")) != '\0') { - if (i == 'a') { - rmaliases(); - return (0); - } - } - for (i = 0; *argptr; argptr++) { - if (unalias(*argptr)) { - out2fmt("%s: %s not found\n", "unalias", *argptr); - i = 1; - } - } - - return (i); -} - -static struct alias ** -hashalias(p) - const char *p; - { - unsigned int hashval; - - hashval = *p << 4; - while (*p) - hashval+= *p++; - return &atab[hashval % ATABSIZE]; -} - -static struct alias * -freealias(struct alias *ap) { - struct alias *next; - - if (ap->flag & ALIASINUSE) { - ap->flag |= ALIASDEAD; - return ap; - } - - next = ap->next; - ckfree(ap->name); - ckfree(ap->val); - ckfree(ap); - return next; -} - - -static struct alias ** -__lookupalias(const char *name) { - struct alias **app = hashalias(name); - - for (; *app; app = &(*app)->next) { - if (equal(name, (*app)->name)) { - break; - } - } - - return app; -} -#endif - -#ifdef ASH_MATH_SUPPORT -/* The generated file arith.c has been replaced with a custom hand - * written implementation written by Aaron Lehmann . - * This is now part of libbb, so that it can be used by all the shells - * in busybox. */ -#define ARITH_NUM 257 -#define ARITH_LPAREN 258 -#define ARITH_RPAREN 259 -#define ARITH_OR 260 -#define ARITH_AND 261 -#define ARITH_BOR 262 -#define ARITH_BXOR 263 -#define ARITH_BAND 264 -#define ARITH_EQ 265 -#define ARITH_NE 266 -#define ARITH_LT 267 -#define ARITH_GT 268 -#define ARITH_GE 269 -#define ARITH_LE 270 -#define ARITH_LSHIFT 271 -#define ARITH_RSHIFT 272 -#define ARITH_ADD 273 -#define ARITH_SUB 274 -#define ARITH_MUL 275 -#define ARITH_DIV 276 -#define ARITH_REM 277 -#define ARITH_UNARYMINUS 278 -#define ARITH_UNARYPLUS 279 -#define ARITH_NOT 280 -#define ARITH_BNOT 281 - -static void expari (int); -#endif - -static char *trap[NSIG]; /* trap handler commands */ -static char sigmode[NSIG - 1]; /* current value of signal */ -static char gotsig[NSIG - 1]; /* indicates specified signal received */ -static int pendingsigs; /* indicates some signal received */ - -/* - * This file was generated by the mkbuiltins program. - */ - -#ifdef JOBS -static int bgcmd (int, char **); -static int fgcmd (int, char **); -static int killcmd (int, char **); -#endif -static int bltincmd (int, char **); -static int cdcmd (int, char **); -static int breakcmd (int, char **); -#ifdef ASH_CMDCMD -static int commandcmd (int, char **); -#endif -static int dotcmd (int, char **); -static int evalcmd (int, char **); -static int execcmd (int, char **); -static int exitcmd (int, char **); -static int exportcmd (int, char **); -static int histcmd (int, char **); -static int hashcmd (int, char **); -static int helpcmd (int, char **); -static int jobscmd (int, char **); -static int localcmd (int, char **); -#ifndef BB_PWD -static int pwdcmd (int, char **); -#endif -static int readcmd (int, char **); -static int returncmd (int, char **); -static int setcmd (int, char **); -static int setvarcmd (int, char **); -static int shiftcmd (int, char **); -static int trapcmd (int, char **); -static int umaskcmd (int, char **); -#ifdef ASH_ALIAS -static int aliascmd (int, char **); -static int unaliascmd (int, char **); -#endif -static int unsetcmd (int, char **); -static int waitcmd (int, char **); -static int ulimitcmd (int, char **); -static int timescmd (int, char **); -#ifdef ASH_MATH_SUPPORT -static int letcmd (int, char **); -#endif -static int typecmd (int, char **); -#ifdef ASH_GETOPTS -static int getoptscmd (int, char **); -#endif - -#ifndef BB_TRUE_FALSE -static int true_main (int, char **); -static int false_main (int, char **); -#endif - -static void setpwd (const char *, int); - - -#define BUILTIN_NOSPEC "0" -#define BUILTIN_SPECIAL "1" -#define BUILTIN_REGULAR "2" -#define BUILTIN_ASSIGN "4" -#define BUILTIN_SPEC_ASSG "5" -#define BUILTIN_REG_ASSG "6" - -#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1) -#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2) -#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4) - -struct builtincmd { - const char *name; - int (*const builtinfunc) (int, char **); - //unsigned flags; -}; - - -/* It is CRUCIAL that this listing be kept in ascii order, otherwise - * the binary search in find_builtin() will stop working. If you value - * your kneecaps, you'll be sure to *make sure* that any changes made - * to this array result in the listing remaining in ascii order. You - * have been warned. - */ -static const struct builtincmd builtincmds[] = { - { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */ - { BUILTIN_SPECIAL ":", true_main }, -#ifdef ASH_ALIAS - { BUILTIN_REG_ASSG "alias", aliascmd }, -#endif -#ifdef JOBS - { BUILTIN_REGULAR "bg", bgcmd }, -#endif - { BUILTIN_SPECIAL "break", breakcmd }, - { BUILTIN_SPECIAL "builtin", bltincmd }, - { BUILTIN_REGULAR "cd", cdcmd }, - { BUILTIN_NOSPEC "chdir", cdcmd }, -#ifdef ASH_CMDCMD - { BUILTIN_REGULAR "command", commandcmd }, -#endif - { BUILTIN_SPECIAL "continue", breakcmd }, - { BUILTIN_SPECIAL "eval", evalcmd }, - { BUILTIN_SPECIAL "exec", execcmd }, - { BUILTIN_SPECIAL "exit", exitcmd }, - { BUILTIN_SPEC_ASSG "export", exportcmd }, - { BUILTIN_REGULAR "false", false_main }, - { BUILTIN_REGULAR "fc", histcmd }, -#ifdef JOBS - { BUILTIN_REGULAR "fg", fgcmd }, -#endif -#ifdef ASH_GETOPTS - { BUILTIN_REGULAR "getopts", getoptscmd }, -#endif - { BUILTIN_NOSPEC "hash", hashcmd }, - { BUILTIN_NOSPEC "help", helpcmd }, - { BUILTIN_REGULAR "jobs", jobscmd }, -#ifdef JOBS - { BUILTIN_REGULAR "kill", killcmd }, -#endif -#ifdef ASH_MATH_SUPPORT - { BUILTIN_REGULAR "let", letcmd }, -#endif - { BUILTIN_ASSIGN "local", localcmd }, -#ifndef BB_PWD - { BUILTIN_NOSPEC "pwd", pwdcmd }, -#endif - { BUILTIN_REGULAR "read", readcmd }, - { BUILTIN_SPEC_ASSG "readonly", exportcmd }, - { BUILTIN_SPECIAL "return", returncmd }, - { BUILTIN_SPECIAL "set", setcmd }, - { BUILTIN_NOSPEC "setvar", setvarcmd }, - { BUILTIN_SPECIAL "shift", shiftcmd }, - { BUILTIN_SPECIAL "times", timescmd }, - { BUILTIN_SPECIAL "trap", trapcmd }, - { BUILTIN_REGULAR "true", true_main }, - { BUILTIN_NOSPEC "type", typecmd }, - { BUILTIN_NOSPEC "ulimit", ulimitcmd }, - { BUILTIN_REGULAR "umask", umaskcmd }, -#ifdef ASH_ALIAS - { BUILTIN_REGULAR "unalias", unaliascmd }, -#endif - { BUILTIN_SPECIAL "unset", unsetcmd }, - { BUILTIN_REGULAR "wait", waitcmd }, -}; -#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) ) - -static const struct builtincmd *DOTCMD = &builtincmds[0]; -static struct builtincmd *BLTINCMD; -static struct builtincmd *EXECCMD; -static struct builtincmd *EVALCMD; - -/* states */ -#define JOBSTOPPED 1 /* all procs are stopped */ -#define JOBDONE 2 /* all procs are completed */ - -/* - * A job structure contains information about a job. A job is either a - * single process or a set of processes contained in a pipeline. In the - * latter case, pidlist will be non-NULL, and will point to a -1 terminated - * array of pids. - */ - -struct procstat { - pid_t pid; /* process id */ - int status; /* status flags (defined above) */ - char *cmd; /* text of command being run */ -}; - - -static int job_warning; /* user was warned about stopped jobs */ - -#ifdef JOBS -static void setjobctl(int enable); -#else -#define setjobctl(on) /* do nothing */ -#endif - - -struct job { - struct procstat ps0; /* status of process */ - struct procstat *ps; /* status or processes when more than one */ - short nprocs; /* number of processes */ - short pgrp; /* process group of this job */ - char state; /* true if job is finished */ - char used; /* true if this entry is in used */ - char changed; /* true if status has changed */ -#ifdef JOBS - char jobctl; /* job running under job control */ -#endif -}; - -static struct job *jobtab; /* array of jobs */ -static int njobs; /* size of array */ -static int backgndpid = -1; /* pid of last background process */ -#ifdef JOBS -static int initialpgrp; /* pgrp of shell on invocation */ -static int curjob; /* current job */ -static int jobctl; -#endif -static int intreceived; - -static struct job *makejob (const union node *, int); -static int forkshell (struct job *, const union node *, int); -static int waitforjob (struct job *); - -static int docd (char *, int); -static char *getcomponent (void); -static void updatepwd (const char *); -static void getpwd (void); - -static char *padvance (const char **, const char *); - -static char nullstr[1]; /* zero length string */ -static char *curdir = nullstr; /* current working directory */ -static char *cdcomppath; - -static int -cdcmd(argc, argv) - int argc; - char **argv; -{ - const char *dest; - const char *path; - char *p; - struct stat statb; - int print = 0; - - nextopt(nullstr); - if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL) - error("HOME not set"); - if (*dest == '\0') - dest = "."; - if (dest[0] == '-' && dest[1] == '\0') { - dest = bltinlookup("OLDPWD"); - if (!dest || !*dest) { - dest = curdir; - } - print = 1; - if (dest) - print = 1; - else - dest = "."; - } - if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL) - path = nullstr; - while ((p = padvance(&path, dest)) != NULL) { - if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { - if (!print) { - /* - * XXX - rethink - */ - if (p[0] == '.' && p[1] == '/' && p[2] != '\0') - p += 2; - print = strcmp(p, dest); - } - if (docd(p, print) >= 0) - return 0; - - } - } - error("can't cd to %s", dest); - /* NOTREACHED */ -} - - -/* - * Actually do the chdir. In an interactive shell, print the - * directory name if "print" is nonzero. - */ - -static int -docd(dest, print) - char *dest; - int print; -{ - char *p; - char *q; - char *component; - struct stat statb; - int first; - int badstat; - - TRACE(("docd(\"%s\", %d) called\n", dest, print)); - - /* - * Check each component of the path. If we find a symlink or - * something we can't stat, clear curdir to force a getcwd() - * next time we get the value of the current directory. - */ - badstat = 0; - cdcomppath = sstrdup(dest); - STARTSTACKSTR(p); - if (*dest == '/') { - STPUTC('/', p); - cdcomppath++; - } - first = 1; - while ((q = getcomponent()) != NULL) { - if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0')) - continue; - if (! first) - STPUTC('/', p); - first = 0; - component = q; - while (*q) - STPUTC(*q++, p); - if (equal(component, "..")) - continue; - STACKSTRNUL(p); - if ((lstat(stackblock(), &statb) < 0) - || (S_ISLNK(statb.st_mode))) { - /* print = 1; */ - badstat = 1; - break; - } - } - - INTOFF; - if (chdir(dest) < 0) { - INTON; - return -1; - } - updatepwd(badstat ? NULL : dest); - INTON; - if (print && iflag) - printf(snlfmt, curdir); - return 0; -} - - -/* - * Get the next component of the path name pointed to by cdcomppath. - * This routine overwrites the string pointed to by cdcomppath. - */ - -static char * -getcomponent() { - char *p; - char *start; - - if ((p = cdcomppath) == NULL) - return NULL; - start = cdcomppath; - while (*p != '/' && *p != '\0') - p++; - if (*p == '\0') { - cdcomppath = NULL; - } else { - *p++ = '\0'; - cdcomppath = p; - } - return start; -} - - - -/* - * Update curdir (the name of the current directory) in response to a - * cd command. We also call hashcd to let the routines in exec.c know - * that the current directory has changed. - */ - -static void hashcd (void); - -static void -updatepwd(const char *dir) -{ - char *new; - char *p; - size_t len; - - hashcd(); /* update command hash table */ - - /* - * If our argument is NULL, we don't know the current directory - * any more because we traversed a symbolic link or something - * we couldn't stat(). - */ - if (dir == NULL || curdir == nullstr) { - setpwd(0, 1); - return; - } - len = strlen(dir); - cdcomppath = sstrdup(dir); - STARTSTACKSTR(new); - if (*dir != '/') { - p = curdir; - while (*p) - STPUTC(*p++, new); - if (p[-1] == '/') - STUNPUTC(new); - } - while ((p = getcomponent()) != NULL) { - if (equal(p, "..")) { - while (new > stackblock() && (STUNPUTC(new), *new) != '/'); - } else if (*p != '\0' && ! equal(p, ".")) { - STPUTC('/', new); - while (*p) - STPUTC(*p++, new); - } - } - if (new == stackblock()) - STPUTC('/', new); - STACKSTRNUL(new); - setpwd(stackblock(), 1); -} - - -#ifndef BB_PWD -static int -pwdcmd(argc, argv) - int argc; - char **argv; -{ - printf(snlfmt, curdir); - return 0; -} -#endif - -/* - * Find out what the current directory is. If we already know the current - * directory, this routine returns immediately. - */ -static void -getpwd(void) -{ - curdir = xgetcwd(0); - if(curdir==0) - curdir = nullstr; -} - -static void -setpwd(const char *val, int setold) -{ - if (setold) { - setvar("OLDPWD", curdir, VEXPORT); - } - INTOFF; - if (curdir != nullstr) { - free(curdir); - curdir = nullstr; - } - if (!val) { - getpwd(); - } else { - curdir = savestr(val); - } - INTON; - setvar("PWD", curdir, VEXPORT); -} - -/* - * Errors and exceptions. - */ - -/* - * Code to handle exceptions in C. - */ - -/* - * We enclose jmp_buf in a structure so that we can declare pointers to - * jump locations. The global variable handler contains the location to - * jump to when an exception occurs, and the global variable exception - * contains a code identifying the exeception. To implement nested - * exception handlers, the user should save the value of handler on entry - * to an inner scope, set handler to point to a jmploc structure for the - * inner scope, and restore handler on exit from the scope. - */ - -struct jmploc { - jmp_buf loc; -}; - -/* exceptions */ -#define EXINT 0 /* SIGINT received */ -#define EXERROR 1 /* a generic error */ -#define EXSHELLPROC 2 /* execute a shell procedure */ -#define EXEXEC 3 /* command execution failed */ - -static struct jmploc *handler; -static int exception; - -static void exverror (int, const char *, va_list) - __attribute__((__noreturn__)); - -/* - * Called to raise an exception. Since C doesn't include exceptions, we - * just do a longjmp to the exception handler. The type of exception is - * stored in the global variable "exception". - */ - -static void exraise (int) __attribute__((__noreturn__)); - -static void -exraise(int e) -{ -#ifdef DEBUG - if (handler == NULL) - abort(); -#endif - flushall(); - exception = e; - longjmp(handler->loc, 1); -} - - -/* - * Called from trap.c when a SIGINT is received. (If the user specifies - * that SIGINT is to be trapped or ignored using the trap builtin, then - * this routine is not called.) Suppressint is nonzero when interrupts - * are held using the INTOFF macro. The call to _exit is necessary because - * there is a short period after a fork before the signal handlers are - * set to the appropriate value for the child. (The test for iflag is - * just defensive programming.) - */ - -static void -onint(void) { - sigset_t mysigset; - - if (suppressint) { - intpending++; - return; - } - intpending = 0; - sigemptyset(&mysigset); - sigprocmask(SIG_SETMASK, &mysigset, NULL); - if (rootshell && iflag) - exraise(EXINT); - else { - signal(SIGINT, SIG_DFL); - raise(SIGINT); - } - /* NOTREACHED */ -} - - -static char *commandname; /* currently executing command */ - -/* - * Exverror is called to raise the error exception. If the first argument - * is not NULL then error prints an error message using printf style - * formatting. It then raises the error exception. - */ -static void -exverror(int cond, const char *msg, va_list ap) -{ - CLEAR_PENDING_INT; - INTOFF; - -#ifdef DEBUG - if (msg) - TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid())); - else - TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid())); -#endif - if (msg) { - if (commandname) - out2fmt("%s: ", commandname); - vfprintf(stderr, msg, ap); - out2c('\n'); - } - exraise(cond); - /* NOTREACHED */ -} - - -static void -error(const char *msg, ...) -{ - va_list ap; - va_start(ap, msg); - exverror(EXERROR, msg, ap); - /* NOTREACHED */ - va_end(ap); -} - - -static void -exerror(int cond, const char *msg, ...) -{ - va_list ap; - va_start(ap, msg); - exverror(cond, msg, ap); - /* NOTREACHED */ - va_end(ap); -} - - - -/* - * Table of error messages. - */ - -struct errname { - short errcode; /* error number */ - char action; /* operation which encountered the error */ -}; - -/* - * Types of operations (passed to the errmsg routine). - */ - -#define E_OPEN 01 /* opening a file */ -#define E_CREAT 02 /* creating a file */ -#define E_EXEC 04 /* executing a program */ - -#define ALL (E_OPEN|E_CREAT|E_EXEC) - -static const struct errname errormsg[] = { - { EINTR, ALL }, - { EACCES, ALL }, - { EIO, ALL }, - { ENOENT, E_OPEN }, - { ENOENT, E_CREAT }, - { ENOENT, E_EXEC }, - { ENOTDIR, E_OPEN }, - { ENOTDIR, E_CREAT }, - { ENOTDIR, E_EXEC }, - { EISDIR, ALL }, - { EEXIST, E_CREAT }, -#ifdef EMFILE - { EMFILE, ALL }, -#endif - { ENFILE, ALL }, - { ENOSPC, ALL }, -#ifdef EDQUOT - { EDQUOT, ALL }, -#endif -#ifdef ENOSR - { ENOSR, ALL }, -#endif - { ENXIO, ALL }, - { EROFS, ALL }, - { ETXTBSY, ALL }, -#ifdef EAGAIN - { EAGAIN, E_EXEC }, -#endif - { ENOMEM, ALL }, -#ifdef ENOLINK - { ENOLINK, ALL }, -#endif -#ifdef EMULTIHOP - { EMULTIHOP, ALL }, -#endif -#ifdef ECOMM - { ECOMM, ALL }, -#endif -#ifdef ESTALE - { ESTALE, ALL }, -#endif -#ifdef ETIMEDOUT - { ETIMEDOUT, ALL }, -#endif -#ifdef ELOOP - { ELOOP, ALL }, -#endif - { E2BIG, E_EXEC }, -#ifdef ELIBACC - { ELIBACC, E_EXEC }, -#endif -}; - -#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname)) - -/* - * Return a string describing an error. The returned string may be a - * pointer to a static buffer that will be overwritten on the next call. - * Action describes the operation that got the error. - */ - -static const char * -errmsg(int e, int action) -{ - struct errname const *ep; - static char buf[12]; - - for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) { - if (ep->errcode == e && (ep->action & action) != 0) - return strerror(e); - } - - snprintf(buf, sizeof buf, "error %d", e); - return buf; -} - - -#ifdef ASH_OPTIMIZE_FOR_SIZE -static void -__inton() { - if (--suppressint == 0 && intpending) { - onint(); - } -} -static void forceinton (void) { - suppressint = 0; - if (intpending) - onint(); -} -#endif - -/* flags in argument to evaltree */ -#define EV_EXIT 01 /* exit after evaluating tree */ -#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ -#define EV_BACKCMD 04 /* command executing within back quotes */ - -static int evalskip; /* set if we are skipping commands */ -static int skipcount; /* number of levels to skip */ -static int loopnest; /* current loop nesting level */ -static int funcnest; /* depth of function calls */ - - -static struct strlist *cmdenviron; /* environment for builtin command */ -static int exitstatus; /* exit status of last command */ -static int oexitstatus; /* saved exit status */ - -static void evalsubshell (const union node *, int); -static void expredir (union node *); -static void prehash (union node *); -static void eprintlist (struct strlist *); - -static union node *parsecmd(int); -/* - * Called to reset things after an exception. - */ - -/* - * The eval commmand. - */ -static void evalstring (char *, int); - -static int -evalcmd(argc, argv) - int argc; - char **argv; -{ - char *p; - char *concat; - char **ap; - - if (argc > 1) { - p = argv[1]; - if (argc > 2) { - STARTSTACKSTR(concat); - ap = argv + 2; - for (;;) { - while (*p) - STPUTC(*p++, concat); - if ((p = *ap++) == NULL) - break; - STPUTC(' ', concat); - } - STPUTC('\0', concat); - p = grabstackstr(concat); - } - evalstring(p, EV_TESTED); - } - return exitstatus; -} - -/* - * Execute a command or commands contained in a string. - */ - -static void evaltree (union node *, int); -static void setinputstring (char *); -static void popfile (void); -static void setstackmark(struct stackmark *mark); -static void popstackmark(struct stackmark *mark); - - -static void -evalstring(char *s, int flag) -{ - union node *n; - struct stackmark smark; - - setstackmark(&smark); - setinputstring(s); - while ((n = parsecmd(0)) != NEOF) { - evaltree(n, flag); - popstackmark(&smark); - } - popfile(); - popstackmark(&smark); -} - -static struct builtincmd *find_builtin (const char *); -static void expandarg (union node *, struct arglist *, int); -static void calcsize (const union node *); -static union node *copynode (const union node *); - -/* - * Make a copy of a parse tree. - */ - -static int funcblocksize; /* size of structures in function */ -static int funcstringsize; /* size of strings in node */ -static pointer funcblock; /* block to allocate function from */ -static char *funcstring; /* block to allocate strings from */ - - -static inline union node * -copyfunc(union node *n) -{ - if (n == NULL) - return NULL; - funcblocksize = 0; - funcstringsize = 0; - calcsize(n); - funcblock = ckmalloc(funcblocksize + funcstringsize); - funcstring = (char *) funcblock + funcblocksize; - return copynode(n); -} - -/* - * Free a parse tree. - */ - -static void -freefunc(union node *n) -{ - if (n) - ckfree(n); -} - - -/* - * Add a new command entry, replacing any existing command entry for - * the same name. - */ - -static inline void -addcmdentry(char *name, struct cmdentry *entry) -{ - struct tblentry *cmdp; - - INTOFF; - cmdp = cmdlookup(name, 1); - if (cmdp->cmdtype == CMDFUNCTION) { - freefunc(cmdp->param.func); - } - cmdp->cmdtype = entry->cmdtype; - cmdp->param = entry->u; - INTON; -} - -static inline void -evalloop(const union node *n, int flags) -{ - int status; - - loopnest++; - status = 0; - for (;;) { - evaltree(n->nbinary.ch1, EV_TESTED); - if (evalskip) { -skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { - evalskip = 0; - continue; - } - if (evalskip == SKIPBREAK && --skipcount <= 0) - evalskip = 0; - break; - } - if (n->type == NWHILE) { - if (exitstatus != 0) - break; - } else { - if (exitstatus == 0) - break; - } - evaltree(n->nbinary.ch2, flags & EV_TESTED); - status = exitstatus; - if (evalskip) - goto skipping; - } - loopnest--; - exitstatus = status; -} - -static void -evalfor(const union node *n, int flags) -{ - struct arglist arglist; - union node *argp; - struct strlist *sp; - struct stackmark smark; - - setstackmark(&smark); - arglist.lastp = &arglist.list; - for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { - oexitstatus = exitstatus; - expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); - if (evalskip) - goto out; - } - *arglist.lastp = NULL; - - exitstatus = 0; - loopnest++; - for (sp = arglist.list ; sp ; sp = sp->next) { - setvar(n->nfor.var, sp->text, 0); - evaltree(n->nfor.body, flags & EV_TESTED); - if (evalskip) { - if (evalskip == SKIPCONT && --skipcount <= 0) { - evalskip = 0; - continue; - } - if (evalskip == SKIPBREAK && --skipcount <= 0) - evalskip = 0; - break; - } - } - loopnest--; -out: - popstackmark(&smark); -} - -static inline void -evalcase(const union node *n, int flags) -{ - union node *cp; - union node *patp; - struct arglist arglist; - struct stackmark smark; - - setstackmark(&smark); - arglist.lastp = &arglist.list; - oexitstatus = exitstatus; - expandarg(n->ncase.expr, &arglist, EXP_TILDE); - for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { - for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { - if (casematch(patp, arglist.list->text)) { - if (evalskip == 0) { - evaltree(cp->nclist.body, flags); - } - goto out; - } - } - } -out: - popstackmark(&smark); -} - -/* - * Evaluate a pipeline. All the processes in the pipeline are children - * of the process creating the pipeline. (This differs from some versions - * of the shell, which make the last process in a pipeline the parent - * of all the rest.) - */ - -static inline void -evalpipe(n) - union node *n; -{ - struct job *jp; - struct nodelist *lp; - int pipelen; - int prevfd; - int pip[2]; - - TRACE(("evalpipe(0x%lx) called\n", (long)n)); - pipelen = 0; - for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) - pipelen++; - INTOFF; - jp = makejob(n, pipelen); - prevfd = -1; - for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { - prehash(lp->n); - pip[1] = -1; - if (lp->next) { - if (pipe(pip) < 0) { - close(prevfd); - error("Pipe call failed"); - } - } - if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { - INTON; - if (prevfd > 0) { - close(0); - dup_as_newfd(prevfd, 0); - close(prevfd); - if (pip[0] == 0) { - pip[0] = -1; - } - } - if (pip[1] >= 0) { - if (pip[0] >= 0) { - close(pip[0]); - } - if (pip[1] != 1) { - close(1); - dup_as_newfd(pip[1], 1); - close(pip[1]); - } - } - evaltree(lp->n, EV_EXIT); - } - if (prevfd >= 0) - close(prevfd); - prevfd = pip[0]; - close(pip[1]); - } - INTON; - if (n->npipe.backgnd == 0) { - INTOFF; - exitstatus = waitforjob(jp); - TRACE(("evalpipe: job done exit status %d\n", exitstatus)); - INTON; - } -} - -static void find_command (const char *, struct cmdentry *, int, const char *); - -static int -isassignment(const char *word) { - if (!is_name(*word)) { - return 0; - } - do { - word++; - } while (is_in_name(*word)); - return *word == '='; -} - - -static void -evalcommand(union node *cmd, int flags) -{ - struct stackmark smark; - union node *argp; - struct arglist arglist; - struct arglist varlist; - char **argv; - int argc; - char **envp; - struct strlist *sp; - int mode; - struct cmdentry cmdentry; - struct job *jp; - char *volatile savecmdname; - volatile struct shparam saveparam; - struct localvar *volatile savelocalvars; - volatile int e; - char *lastarg; - const char *path; - const struct builtincmd *firstbltin; - struct jmploc *volatile savehandler; - struct jmploc jmploc; -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &argv; - (void) &argc; - (void) &lastarg; - (void) &flags; -#endif - - /* First expand the arguments. */ - TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); - setstackmark(&smark); - arglist.lastp = &arglist.list; - varlist.lastp = &varlist.list; - arglist.list = 0; - oexitstatus = exitstatus; - exitstatus = 0; - path = pathval(); - for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { - expandarg(argp, &varlist, EXP_VARTILDE); - } - for ( - argp = cmd->ncmd.args; argp && !arglist.list; - argp = argp->narg.next - ) { - expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); - } - if (argp) { - struct builtincmd *bcmd; - int pseudovarflag; - bcmd = find_builtin(arglist.list->text); - pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd); - for (; argp; argp = argp->narg.next) { - if (pseudovarflag && isassignment(argp->narg.text)) { - expandarg(argp, &arglist, EXP_VARTILDE); - continue; - } - expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); - } - } - *arglist.lastp = NULL; - *varlist.lastp = NULL; - expredir(cmd->ncmd.redirect); - argc = 0; - for (sp = arglist.list ; sp ; sp = sp->next) - argc++; - argv = stalloc(sizeof (char *) * (argc + 1)); - - for (sp = arglist.list ; sp ; sp = sp->next) { - TRACE(("evalcommand arg: %s\n", sp->text)); - *argv++ = sp->text; - } - *argv = NULL; - lastarg = NULL; - if (iflag && funcnest == 0 && argc > 0) - lastarg = argv[-1]; - argv -= argc; - - /* Print the command if xflag is set. */ - if (xflag) { - out2c('+'); - eprintlist(varlist.list); - eprintlist(arglist.list); - out2c('\n'); - } - - /* Now locate the command. */ - if (argc == 0) { - cmdentry.cmdtype = CMDBUILTIN; - firstbltin = cmdentry.u.cmd = BLTINCMD; - } else { - const char *oldpath; - int findflag = DO_ERR; - int oldfindflag; - - /* - * Modify the command lookup path, if a PATH= assignment - * is present - */ - for (sp = varlist.list ; sp ; sp = sp->next) - if (varequal(sp->text, defpathvar)) { - path = sp->text + 5; - findflag |= DO_BRUTE; - } - oldpath = path; - oldfindflag = findflag; - firstbltin = 0; - for(;;) { - find_command(argv[0], &cmdentry, findflag, path); - if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ - exitstatus = 127; - goto out; - } - /* implement bltin and command here */ - if (cmdentry.cmdtype != CMDBUILTIN) { - break; - } - if (!firstbltin) { - firstbltin = cmdentry.u.cmd; - } - if (cmdentry.u.cmd == BLTINCMD) { - for(;;) { - struct builtincmd *bcmd; - - argv++; - if (--argc == 0) - goto found; - if (!(bcmd = find_builtin(*argv))) { - out2fmt("%s: not found\n", *argv); - exitstatus = 127; - goto out; - } - cmdentry.u.cmd = bcmd; - if (bcmd != BLTINCMD) - break; - } - } - if (cmdentry.u.cmd == find_builtin("command")) { - argv++; - if (--argc == 0) { - goto found; - } - if (*argv[0] == '-') { - if (!equal(argv[0], "-p")) { - argv--; - argc++; - break; - } - argv++; - if (--argc == 0) { - goto found; - } - path = defpath; - findflag |= DO_BRUTE; - } else { - path = oldpath; - findflag = oldfindflag; - } - findflag |= DO_NOFUN; - continue; - } -found: - break; - } - } - - /* Fork off a child process if necessary. */ - if (cmd->ncmd.backgnd - || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0) - ) { - jp = makejob(cmd, 1); - mode = cmd->ncmd.backgnd; - if (forkshell(jp, cmd, mode) != 0) - goto parent; /* at end of routine */ - flags |= EV_EXIT; - } - - /* This is the child process if a fork occurred. */ - /* Execute the command. */ - if (cmdentry.cmdtype == CMDFUNCTION) { -#ifdef DEBUG - trputs("Shell function: "); trargs(argv); -#endif - exitstatus = oexitstatus; - redirect(cmd->ncmd.redirect, REDIR_PUSH); - saveparam = shellparam; - shellparam.malloc = 0; - shellparam.nparam = argc - 1; - shellparam.p = argv + 1; - INTOFF; - savelocalvars = localvars; - localvars = NULL; - INTON; - if (setjmp(jmploc.loc)) { - if (exception == EXSHELLPROC) { - freeparam((volatile struct shparam *) - &saveparam); - } else { - saveparam.optind = shellparam.optind; - saveparam.optoff = shellparam.optoff; - freeparam(&shellparam); - shellparam = saveparam; - } - poplocalvars(); - localvars = savelocalvars; - handler = savehandler; - longjmp(handler->loc, 1); - } - savehandler = handler; - handler = &jmploc; - for (sp = varlist.list ; sp ; sp = sp->next) - mklocal(sp->text); - funcnest++; - evaltree(cmdentry.u.func, flags & EV_TESTED); - funcnest--; - INTOFF; - poplocalvars(); - localvars = savelocalvars; - saveparam.optind = shellparam.optind; - saveparam.optoff = shellparam.optoff; - freeparam(&shellparam); - shellparam = saveparam; - handler = savehandler; - popredir(); - INTON; - if (evalskip == SKIPFUNC) { - evalskip = 0; - skipcount = 0; - } - if (flags & EV_EXIT) - exitshell(exitstatus); - } else if (cmdentry.cmdtype == CMDBUILTIN) { -#ifdef DEBUG - trputs("builtin command: "); trargs(argv); -#endif - mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH; - redirect(cmd->ncmd.redirect, mode); - savecmdname = commandname; - if (IS_BUILTIN_SPECIAL(firstbltin)) { - listsetvar(varlist.list); - } else { - cmdenviron = varlist.list; - } - e = -1; - if (setjmp(jmploc.loc)) { - e = exception; - exitstatus = (e == EXINT)? SIGINT+128 : 2; - goto cmddone; - } - savehandler = handler; - handler = &jmploc; - commandname = argv[0]; - argptr = argv + 1; - optptr = NULL; /* initialize nextopt */ - exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv); - flushall(); -cmddone: - cmdenviron = NULL; - if (e != EXSHELLPROC) { - commandname = savecmdname; - if (flags & EV_EXIT) - exitshell(exitstatus); - } - handler = savehandler; - if (e != -1) { - if ((e != EXERROR && e != EXEXEC) - || cmdentry.u.cmd == BLTINCMD - || cmdentry.u.cmd == DOTCMD - || cmdentry.u.cmd == EVALCMD - || cmdentry.u.cmd == EXECCMD) - exraise(e); - FORCEINTON; - } - if (cmdentry.u.cmd != EXECCMD) - popredir(); - } else { -#ifdef DEBUG - trputs("normal command: "); trargs(argv); -#endif - redirect(cmd->ncmd.redirect, 0); - clearredir(); - for (sp = varlist.list ; sp ; sp = sp->next) - setvareq(sp->text, VEXPORT|VSTACK); - envp = environment(); - shellexec(argv, envp, path, cmdentry.u.index); - } - goto out; - -parent: /* parent process gets here (if we forked) */ - if (mode == 0) { /* argument to fork */ - INTOFF; - exitstatus = waitforjob(jp); - INTON; - } - -out: - if (lastarg) - setvar("_", lastarg, 0); - popstackmark(&smark); -} - -/* - * Evaluate a parse tree. The value is left in the global variable - * exitstatus. - */ -static void -evaltree(n, flags) - union node *n; - int flags; -{ - int checkexit = 0; - if (n == NULL) { - TRACE(("evaltree(NULL) called\n")); - goto out; - } - TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type)); - switch (n->type) { - case NSEMI: - evaltree(n->nbinary.ch1, flags & EV_TESTED); - if (evalskip) - goto out; - evaltree(n->nbinary.ch2, flags); - break; - case NAND: - evaltree(n->nbinary.ch1, EV_TESTED); - if (evalskip || exitstatus != 0) - goto out; - evaltree(n->nbinary.ch2, flags); - break; - case NOR: - evaltree(n->nbinary.ch1, EV_TESTED); - if (evalskip || exitstatus == 0) - goto out; - evaltree(n->nbinary.ch2, flags); - break; - case NREDIR: - expredir(n->nredir.redirect); - redirect(n->nredir.redirect, REDIR_PUSH); - evaltree(n->nredir.n, flags); - popredir(); - break; - case NSUBSHELL: - evalsubshell(n, flags); - break; - case NBACKGND: - evalsubshell(n, flags); - break; - case NIF: { - evaltree(n->nif.test, EV_TESTED); - if (evalskip) - goto out; - if (exitstatus == 0) - evaltree(n->nif.ifpart, flags); - else if (n->nif.elsepart) - evaltree(n->nif.elsepart, flags); - else - exitstatus = 0; - break; - } - case NWHILE: - case NUNTIL: - evalloop(n, flags); - break; - case NFOR: - evalfor(n, flags); - break; - case NCASE: - evalcase(n, flags); - break; - case NDEFUN: { - struct builtincmd *bcmd; - struct cmdentry entry; - if ( - (bcmd = find_builtin(n->narg.text)) && - IS_BUILTIN_SPECIAL(bcmd) - ) { - out2fmt("%s is a special built-in\n", n->narg.text); - exitstatus = 1; - break; - } - entry.cmdtype = CMDFUNCTION; - entry.u.func = copyfunc(n->narg.next); - addcmdentry(n->narg.text, &entry); - exitstatus = 0; - break; - } - case NNOT: - evaltree(n->nnot.com, EV_TESTED); - exitstatus = !exitstatus; - break; - - case NPIPE: - evalpipe(n); - checkexit = 1; - break; - case NCMD: - evalcommand(n, flags); - checkexit = 1; - break; -#ifdef DEBUG - default: - printf("Node type = %d\n", n->type); - break; -#endif - } -out: - if (pendingsigs) - dotrap(); - if ( - flags & EV_EXIT || - (checkexit && eflag && exitstatus && !(flags & EV_TESTED)) - ) - exitshell(exitstatus); -} - -/* - * Kick off a subshell to evaluate a tree. - */ - -static void -evalsubshell(const union node *n, int flags) -{ - struct job *jp; - int backgnd = (n->type == NBACKGND); - - expredir(n->nredir.redirect); - jp = makejob(n, 1); - if (forkshell(jp, n, backgnd) == 0) { - if (backgnd) - flags &=~ EV_TESTED; - redirect(n->nredir.redirect, 0); - evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ - } - if (! backgnd) { - INTOFF; - exitstatus = waitforjob(jp); - INTON; - } -} - -/* - * Compute the names of the files in a redirection list. - */ - -static void fixredir(union node *n, const char *text, int err); - -static void -expredir(union node *n) -{ - union node *redir; - - for (redir = n ; redir ; redir = redir->nfile.next) { - struct arglist fn; - fn.lastp = &fn.list; - oexitstatus = exitstatus; - switch (redir->type) { - case NFROMTO: - case NFROM: - case NTO: - case NAPPEND: - case NTOOV: - expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); - redir->nfile.expfname = fn.list->text; - break; - case NFROMFD: - case NTOFD: - if (redir->ndup.vname) { - expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); - fixredir(redir, fn.list->text, 1); - } - break; - } - } -} - - -/* - * Execute a command inside back quotes. If it's a builtin command, we - * want to save its output in a block obtained from malloc. Otherwise - * we fork off a subprocess and get the output of the command via a pipe. - * Should be called with interrupts off. - */ - -static void -evalbackcmd(union node *n, struct backcmd *result) -{ - int pip[2]; - struct job *jp; - struct stackmark smark; /* unnecessary */ - - setstackmark(&smark); - result->fd = -1; - result->buf = NULL; - result->nleft = 0; - result->jp = NULL; - if (n == NULL) { - exitstatus = 0; - goto out; - } - exitstatus = 0; - if (pipe(pip) < 0) - error("Pipe call failed"); - jp = makejob(n, 1); - if (forkshell(jp, n, FORK_NOJOB) == 0) { - FORCEINTON; - close(pip[0]); - if (pip[1] != 1) { - close(1); - dup_as_newfd(pip[1], 1); - close(pip[1]); - } - eflag = 0; - evaltree(n, EV_EXIT); - } - close(pip[1]); - result->fd = pip[0]; - result->jp = jp; -out: - popstackmark(&smark); - TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", - result->fd, result->buf, result->nleft, result->jp)); -} - - -/* - * Execute a simple command. - */ - -/* - * Search for a command. This is called before we fork so that the - * location of the command will be available in the parent as well as - * the child. The check for "goodname" is an overly conservative - * check that the name will not be subject to expansion. - */ - -static void -prehash(n) - union node *n; -{ - struct cmdentry entry; - - if (n->type == NCMD && n->ncmd.args) - if (goodname(n->ncmd.args->narg.text)) - find_command(n->ncmd.args->narg.text, &entry, 0, - pathval()); -} - - -/* - * Builtin commands. Builtin commands whose functions are closely - * tied to evaluation are implemented here. - */ - -/* - * No command given, or a bltin command with no arguments. Set the - * specified variables. - */ - -int -bltincmd(argc, argv) - int argc; - char **argv; -{ - /* - * Preserve exitstatus of a previous possible redirection - * as POSIX mandates - */ - return exitstatus; -} - - -/* - * Handle break and continue commands. Break, continue, and return are - * all handled by setting the evalskip flag. The evaluation routines - * above all check this flag, and if it is set they start skipping - * commands rather than executing them. The variable skipcount is - * the number of loops to break/continue, or the number of function - * levels to return. (The latter is always 1.) It should probably - * be an error to break out of more loops than exist, but it isn't - * in the standard shell so we don't make it one here. - */ - -static int -breakcmd(argc, argv) - int argc; - char **argv; -{ - int n = argc > 1 ? number(argv[1]) : 1; - - if (n > loopnest) - n = loopnest; - if (n > 0) { - evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; - skipcount = n; - } - return 0; -} - - -/* - * The return command. - */ - -static int -returncmd(argc, argv) - int argc; - char **argv; -{ - int ret = argc > 1 ? number(argv[1]) : oexitstatus; - - if (funcnest) { - evalskip = SKIPFUNC; - skipcount = 1; - return ret; - } - else { - /* Do what ksh does; skip the rest of the file */ - evalskip = SKIPFILE; - skipcount = 1; - return ret; - } -} - - -#ifndef BB_TRUE_FALSE -static int -false_main(argc, argv) - int argc; - char **argv; -{ - return 1; -} - - -static int -true_main(argc, argv) - int argc; - char **argv; -{ - return 0; -} -#endif - -/* - * Controls whether the shell is interactive or not. - */ - -static void setsignal(int signo); -static void chkmail(int silent); - - -static void -setinteractive(int on) -{ - static int is_interactive; - static int do_banner=0; - - if (on == is_interactive) - return; - setsignal(SIGINT); - setsignal(SIGQUIT); - setsignal(SIGTERM); - chkmail(1); - is_interactive = on; - if (do_banner==0 && is_interactive) { - /* Looks like they want an interactive shell */ - printf( "\n\n" BB_BANNER " Built-in shell (ash)\n"); - printf( "Enter 'help' for a list of built-in commands.\n\n"); - do_banner=1; - } -} - -static void -optschanged(void) -{ - setinteractive(iflag); - setjobctl(mflag); -} - - -static int -execcmd(argc, argv) - int argc; - char **argv; -{ - if (argc > 1) { - struct strlist *sp; - - iflag = 0; /* exit on error */ - mflag = 0; - optschanged(); - for (sp = cmdenviron; sp ; sp = sp->next) - setvareq(sp->text, VEXPORT|VSTACK); - shellexec(argv + 1, environment(), pathval(), 0); - } - return 0; -} - -static void -eprintlist(struct strlist *sp) -{ - for (; sp; sp = sp->next) { - out2fmt(" %s",sp->text); - } -} - -/* - * Exec a program. Never returns. If you change this routine, you may - * have to change the find_command routine as well. - */ - -static const char *pathopt; /* set by padvance */ - -static void -shellexec(argv, envp, path, idx) - char **argv, **envp; - const char *path; - int idx; -{ - char *cmdname; - int e; - - if (strchr(argv[0], '/') != NULL) { - tryexec(argv[0], argv, envp); - e = errno; - } else { - e = ENOENT; - while ((cmdname = padvance(&path, argv[0])) != NULL) { - if (--idx < 0 && pathopt == NULL) { - tryexec(cmdname, argv, envp); - if (errno != ENOENT && errno != ENOTDIR) - e = errno; - } - stunalloc(cmdname); - } - } - - /* Map to POSIX errors */ - switch (e) { - case EACCES: - exerrno = 126; - break; - case ENOENT: - exerrno = 127; - break; - default: - exerrno = 2; - break; - } - exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC)); - /* NOTREACHED */ -} - -/* - * Clear traps on a fork. - */ -static void -clear_traps(void) { - char **tp; - - for (tp = trap ; tp < &trap[NSIG] ; tp++) { - if (*tp && **tp) { /* trap not NULL or SIG_IGN */ - INTOFF; - ckfree(*tp); - *tp = NULL; - if (tp != &trap[0]) - setsignal(tp - trap); - INTON; - } - } -} - - -static void -initshellproc(void) { - -#ifdef ASH_ALIAS - /* from alias.c: */ - { - rmaliases(); - } -#endif - /* from eval.c: */ - { - exitstatus = 0; - } - - /* from exec.c: */ - { - deletefuncs(); - } - - /* from jobs.c: */ - { - backgndpid = -1; -#ifdef JOBS - jobctl = 0; -#endif - } - - /* from options.c: */ - { - int i; - - for (i = 0; i < NOPTS; i++) - optent_val(i) = 0; - optschanged(); - - } - - /* from redir.c: */ - { - clearredir(); - } - - /* from trap.c: */ - { - char *sm; - - clear_traps(); - for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) { - if (*sm == S_IGN) - *sm = S_HARD_IGN; - } - } - - /* from var.c: */ - { - shprocvar(); - } -} - -static int preadbuffer(void); -static void pushfile (void); - -/* - * Read a character from the script, returning PEOF on end of file. - * Nul characters in the input are silently discarded. - */ - -#ifndef ASH_OPTIMIZE_FOR_SIZE -#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer()) -static int -pgetc(void) -{ - return pgetc_macro(); -} -#else -static int -pgetc_macro(void) -{ - return --parsenleft >= 0? *parsenextc++ : preadbuffer(); -} - -static inline int -pgetc(void) -{ - return pgetc_macro(); -} -#endif - - -/* - * Undo the last call to pgetc. Only one character may be pushed back. - * PEOF may be pushed back. - */ - -static void -pungetc() { - parsenleft++; - parsenextc--; -} - - -static void -popfile(void) { - struct parsefile *pf = parsefile; - - INTOFF; - if (pf->fd >= 0) - close(pf->fd); - if (pf->buf) - ckfree(pf->buf); - while (pf->strpush) - popstring(); - parsefile = pf->prev; - ckfree(pf); - parsenleft = parsefile->nleft; - parselleft = parsefile->lleft; - parsenextc = parsefile->nextc; - plinno = parsefile->linno; - INTON; -} - - -/* - * Return to top level. - */ - -static void -popallfiles(void) { - while (parsefile != &basepf) - popfile(); -} - -/* - * Close the file(s) that the shell is reading commands from. Called - * after a fork is done. - */ - -static void -closescript() { - popallfiles(); - if (parsefile->fd > 0) { - close(parsefile->fd); - parsefile->fd = 0; - } -} - - -/* - * Like setinputfile, but takes an open file descriptor. Call this with - * interrupts off. - */ - -static void -setinputfd(fd, push) - int fd, push; -{ - (void) fcntl(fd, F_SETFD, FD_CLOEXEC); - if (push) { - pushfile(); - parsefile->buf = 0; - } else { - closescript(); - while (parsefile->strpush) - popstring(); - } - parsefile->fd = fd; - if (parsefile->buf == NULL) - parsefile->buf = ckmalloc(BUFSIZ); - parselleft = parsenleft = 0; - plinno = 1; -} - - -/* - * Set the input to take input from a file. If push is set, push the - * old input onto the stack first. - */ - -static void -setinputfile(const char *fname, int push) -{ - int fd; - int myfileno2; - - INTOFF; - if ((fd = open(fname, O_RDONLY)) < 0) - error("Can't open %s", fname); - if (fd < 10) { - myfileno2 = dup_as_newfd(fd, 10); - close(fd); - if (myfileno2 < 0) - error("Out of file descriptors"); - fd = myfileno2; - } - setinputfd(fd, push); - INTON; -} - - -static void -tryexec(char *cmd, char **argv, char **envp) -{ - int e; - -#ifdef BB_FEATURE_SH_STANDALONE_SHELL - char *name = cmd; - char** argv_l=argv; - int argc_l; -#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN - name = get_last_path_component(name); -#endif - argv_l=envp; - for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++) - putenv(*argv_l); - argv_l=argv; - for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++) - optind = 1; - run_applet_by_name(name, argc_l, argv); -#endif - execve(cmd, argv, envp); - e = errno; - if (e == ENOEXEC) { - INTOFF; - initshellproc(); - setinputfile(cmd, 0); - commandname = arg0 = savestr(argv[0]); - setparam(argv + 1); - exraise(EXSHELLPROC); - } - errno = e; -} - -static char *commandtext (const union node *); - -/* - * Do a path search. The variable path (passed by reference) should be - * set to the start of the path before the first call; padvance will update - * this value as it proceeds. Successive calls to padvance will return - * the possible path expansions in sequence. If an option (indicated by - * a percent sign) appears in the path entry then the global variable - * pathopt will be set to point to it; otherwise pathopt will be set to - * NULL. - */ - -static const char *pathopt; - -static void growstackblock(void); - - -static char * -padvance(const char **path, const char *name) -{ - const char *p; - char *q; - const char *start; - int len; - - if (*path == NULL) - return NULL; - start = *path; - for (p = start ; *p && *p != ':' && *p != '%' ; p++); - len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ - while (stackblocksize() < len) - growstackblock(); - q = stackblock(); - if (p != start) { - memcpy(q, start, p - start); - q += p - start; - *q++ = '/'; - } - strcpy(q, name); - pathopt = NULL; - if (*p == '%') { - pathopt = ++p; - while (*p && *p != ':') p++; - } - if (*p == ':') - *path = p + 1; - else - *path = NULL; - return stalloc(len); -} - -/* - * Wrapper around strcmp for qsort/bsearch/... - */ -static int -pstrcmp(const void *a, const void *b) -{ - return strcmp((const char *) a, *(const char *const *) b); -} - -/* - * Find a keyword is in a sorted array. - */ - -static const char *const * -findkwd(const char *s) -{ - return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *), - sizeof(const char *), pstrcmp); -} - - -/*** Command hashing code ***/ - - -static int -hashcmd(argc, argv) - int argc; - char **argv; -{ - struct tblentry **pp; - struct tblentry *cmdp; - int c; - int verbose; - struct cmdentry entry; - char *name; -#ifdef ASH_ALIAS - const struct alias *ap; -#endif - - verbose = 0; - while ((c = nextopt("rvV")) != '\0') { - if (c == 'r') { - clearcmdentry(0); - return 0; - } else if (c == 'v' || c == 'V') { - verbose = c; - } - } - if (*argptr == NULL) { - for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { - for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { - if (cmdp->cmdtype != CMDBUILTIN) { - printentry(cmdp, verbose); - } - } - } - return 0; - } - c = 0; - while ((name = *argptr++) != NULL) { - if ((cmdp = cmdlookup(name, 0)) != NULL - && (cmdp->cmdtype == CMDNORMAL - || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) - delete_cmd_entry(); -#ifdef ASH_ALIAS - /* Then look at the aliases */ - if ((ap = lookupalias(name, 0)) != NULL) { - if (verbose=='v') - printf("%s is an alias for %s\n", name, ap->val); - else - printalias(ap); - continue; - } -#endif - /* First look at the keywords */ - if (findkwd(name)!=0) { - if (verbose=='v') - printf("%s is a shell keyword\n", name); - else - printf(snlfmt, name); - continue; - } - - find_command(name, &entry, DO_ERR, pathval()); - if (entry.cmdtype == CMDUNKNOWN) c = 1; - else if (verbose) { - cmdp = cmdlookup(name, 0); - if (cmdp) printentry(cmdp, verbose=='v'); - flushall(); - } - } - return c; -} - -static void -printentry(cmdp, verbose) - struct tblentry *cmdp; - int verbose; - { - int idx; - const char *path; - char *name; - - printf("%s%s", cmdp->cmdname, (verbose ? " is " : "")); - if (cmdp->cmdtype == CMDNORMAL) { - idx = cmdp->param.index; - path = pathval(); - do { - name = padvance(&path, cmdp->cmdname); - stunalloc(name); - } while (--idx >= 0); - if(verbose) - out1str(name); - } else if (cmdp->cmdtype == CMDBUILTIN) { - if(verbose) - out1str("a shell builtin"); - } else if (cmdp->cmdtype == CMDFUNCTION) { - if (verbose) { - INTOFF; - out1str("a function\n"); - name = commandtext(cmdp->param.func); - printf("%s() {\n %s\n}", cmdp->cmdname, name); - ckfree(name); - INTON; - } -#ifdef DEBUG - } else { - error("internal error: cmdtype %d", cmdp->cmdtype); -#endif - } - printf(snlfmt, cmdp->rehash ? "*" : nullstr); -} - - - -/*** List the available builtins ***/ - - -static int helpcmd(int argc, char** argv) -{ - int col, i; - - printf("\nBuilt-in commands:\n-------------------\n"); - for (col=0, i=0; i < NUMBUILTINS; i++) { - col += printf("%c%s", ((col == 0) ? '\t' : ' '), - builtincmds[i].name+1); - if (col > 60) { - printf("\n"); - col = 0; - } - } -#ifdef BB_FEATURE_SH_STANDALONE_SHELL - { - extern const struct BB_applet applets[]; - extern const size_t NUM_APPLETS; - - for (i=0; i < NUM_APPLETS; i++) { - - col += printf("%c%s", ((col == 0) ? '\t' : ' '), - applets[i].name); - if (col > 60) { - printf("\n"); - col = 0; - } - } - } -#endif - printf("\n\n"); - return EXIT_SUCCESS; -} - -/* - * Resolve a command name. If you change this routine, you may have to - * change the shellexec routine as well. - */ - -static int prefix (const char *, const char *); - -static void -find_command(const char *name, struct cmdentry *entry, int act, const char *path) -{ - struct tblentry *cmdp; - int idx; - int prev; - char *fullname; - struct stat statb; - int e; - int bltin; - int firstchange; - int updatetbl; - int regular; - struct builtincmd *bcmd; - - /* If name contains a slash, don't use the hash table */ - if (strchr(name, '/') != NULL) { - if (act & DO_ABS) { - while (stat(name, &statb) < 0) { - if (errno != ENOENT && errno != ENOTDIR) - e = errno; - entry->cmdtype = CMDUNKNOWN; - entry->u.index = -1; - return; - } - entry->cmdtype = CMDNORMAL; - entry->u.index = -1; - return; - } - entry->cmdtype = CMDNORMAL; - entry->u.index = 0; - return; - } - - updatetbl = 1; - if (act & DO_BRUTE) { - firstchange = path_change(path, &bltin); - } else { - bltin = builtinloc; - firstchange = 9999; - } - - /* If name is in the table, and not invalidated by cd, we're done */ - if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) { - if (cmdp->cmdtype == CMDFUNCTION) { - if (act & DO_NOFUN) { - updatetbl = 0; - } else { - goto success; - } - } else if (act & DO_BRUTE) { - if ((cmdp->cmdtype == CMDNORMAL && - cmdp->param.index >= firstchange) || - (cmdp->cmdtype == CMDBUILTIN && - ((builtinloc < 0 && bltin >= 0) ? - bltin : builtinloc) >= firstchange)) { - /* need to recompute the entry */ - } else { - goto success; - } - } else { - goto success; - } - } - - bcmd = find_builtin(name); - regular = bcmd && IS_BUILTIN_REGULAR(bcmd); - - if (regular) { - if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) { - goto success; - } - } else if (act & DO_BRUTE) { - if (firstchange == 0) { - updatetbl = 0; - } - } - - /* If %builtin not in path, check for builtin next */ - if (regular || (bltin < 0 && bcmd)) { -builtin: - if (!updatetbl) { - entry->cmdtype = CMDBUILTIN; - entry->u.cmd = bcmd; - return; - } - INTOFF; - cmdp = cmdlookup(name, 1); - cmdp->cmdtype = CMDBUILTIN; - cmdp->param.cmd = bcmd; - INTON; - goto success; - } - - /* We have to search path. */ - prev = -1; /* where to start */ - if (cmdp && cmdp->rehash) { /* doing a rehash */ - if (cmdp->cmdtype == CMDBUILTIN) - prev = builtinloc; - else - prev = cmdp->param.index; - } - - e = ENOENT; - idx = -1; -loop: - while ((fullname = padvance(&path, name)) != NULL) { - stunalloc(fullname); - idx++; - if (idx >= firstchange) { - updatetbl = 0; - } - if (pathopt) { - if (prefix("builtin", pathopt)) { - if ((bcmd = find_builtin(name))) { - goto builtin; - } - continue; - } else if (!(act & DO_NOFUN) && - prefix("func", pathopt)) { - /* handled below */ - } else { - continue; /* ignore unimplemented options */ - } - } - /* if rehash, don't redo absolute path names */ - if (fullname[0] == '/' && idx <= prev && - idx < firstchange) { - if (idx < prev) - continue; - TRACE(("searchexec \"%s\": no change\n", name)); - goto success; - } - while (stat(fullname, &statb) < 0) { - if (errno != ENOENT && errno != ENOTDIR) - e = errno; - goto loop; - } - e = EACCES; /* if we fail, this will be the error */ - if (!S_ISREG(statb.st_mode)) - continue; - if (pathopt) { /* this is a %func directory */ - stalloc(strlen(fullname) + 1); - readcmdfile(fullname); - if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION) - error("%s not defined in %s", name, fullname); - stunalloc(fullname); - goto success; - } - TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); - /* If we aren't called with DO_BRUTE and cmdp is set, it must - be a function and we're being called with DO_NOFUN */ - if (!updatetbl) { - entry->cmdtype = CMDNORMAL; - entry->u.index = idx; - return; - } - INTOFF; - cmdp = cmdlookup(name, 1); - cmdp->cmdtype = CMDNORMAL; - cmdp->param.index = idx; - INTON; - goto success; - } - - /* We failed. If there was an entry for this command, delete it */ - if (cmdp && updatetbl) - delete_cmd_entry(); - if (act & DO_ERR) - out2fmt("%s: %s\n", name, errmsg(e, E_EXEC)); - entry->cmdtype = CMDUNKNOWN; - return; - -success: - cmdp->rehash = 0; - entry->cmdtype = cmdp->cmdtype; - entry->u = cmdp->param; -} - - - -/* - * Search the table of builtin commands. - */ - -static int -bstrcmp(const void *name, const void *b) -{ - return strcmp((const char *)name, (*(const char *const *) b)+1); -} - -static struct builtincmd * -find_builtin(const char *name) -{ - struct builtincmd *bp; - - bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd), - bstrcmp - ); - return bp; -} - - -/* - * Called when a cd is done. Marks all commands so the next time they - * are executed they will be rehashed. - */ - -static void -hashcd(void) { - struct tblentry **pp; - struct tblentry *cmdp; - - for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { - for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { - if (cmdp->cmdtype == CMDNORMAL - || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)) - cmdp->rehash = 1; - } - } -} - - - -/* - * Called before PATH is changed. The argument is the new value of PATH; - * pathval() still returns the old value at this point. Called with - * interrupts off. - */ - -static void -changepath(const char *newval) -{ - int firstchange; - int bltin; - - firstchange = path_change(newval, &bltin); - if (builtinloc < 0 && bltin >= 0) - builtinloc = bltin; /* zap builtins */ - clearcmdentry(firstchange); - builtinloc = bltin; -} - - -/* - * Clear out command entries. The argument specifies the first entry in - * PATH which has changed. - */ - -static void -clearcmdentry(firstchange) - int firstchange; -{ - struct tblentry **tblp; - struct tblentry **pp; - struct tblentry *cmdp; - - INTOFF; - for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) { - pp = tblp; - while ((cmdp = *pp) != NULL) { - if ((cmdp->cmdtype == CMDNORMAL && - cmdp->param.index >= firstchange) - || (cmdp->cmdtype == CMDBUILTIN && - builtinloc >= firstchange)) { - *pp = cmdp->next; - ckfree(cmdp); - } else { - pp = &cmdp->next; - } - } - } - INTON; -} - - -/* - * Delete all functions. - */ - -static void -deletefuncs(void) { - struct tblentry **tblp; - struct tblentry **pp; - struct tblentry *cmdp; - - INTOFF; - for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) { - pp = tblp; - while ((cmdp = *pp) != NULL) { - if (cmdp->cmdtype == CMDFUNCTION) { - *pp = cmdp->next; - freefunc(cmdp->param.func); - ckfree(cmdp); - } else { - pp = &cmdp->next; - } - } - } - INTON; -} - - - -/* - * Locate a command in the command hash table. If "add" is nonzero, - * add the command to the table if it is not already present. The - * variable "lastcmdentry" is set to point to the address of the link - * pointing to the entry, so that delete_cmd_entry can delete the - * entry. - */ - -static struct tblentry **lastcmdentry; - -static struct tblentry * -cmdlookup(const char *name, int add) -{ - int hashval; - const char *p; - struct tblentry *cmdp; - struct tblentry **pp; - - p = name; - hashval = *p << 4; - while (*p) - hashval += *p++; - hashval &= 0x7FFF; - pp = &cmdtable[hashval % CMDTABLESIZE]; - for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { - if (equal(cmdp->cmdname, name)) - break; - pp = &cmdp->next; - } - if (add && cmdp == NULL) { - INTOFF; - cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB - + strlen(name) + 1); - cmdp->next = NULL; - cmdp->cmdtype = CMDUNKNOWN; - cmdp->rehash = 0; - strcpy(cmdp->cmdname, name); - INTON; - } - lastcmdentry = pp; - return cmdp; -} - -/* - * Delete the command entry returned on the last lookup. - */ - -static void -delete_cmd_entry() { - struct tblentry *cmdp; - - INTOFF; - cmdp = *lastcmdentry; - *lastcmdentry = cmdp->next; - ckfree(cmdp); - INTON; -} - - - - - -static const short nodesize[26] = { - ALIGN(sizeof (struct nbinary)), - ALIGN(sizeof (struct ncmd)), - ALIGN(sizeof (struct npipe)), - ALIGN(sizeof (struct nredir)), - ALIGN(sizeof (struct nredir)), - ALIGN(sizeof (struct nredir)), - ALIGN(sizeof (struct nbinary)), - ALIGN(sizeof (struct nbinary)), - ALIGN(sizeof (struct nif)), - ALIGN(sizeof (struct nbinary)), - ALIGN(sizeof (struct nbinary)), - ALIGN(sizeof (struct nfor)), - ALIGN(sizeof (struct ncase)), - ALIGN(sizeof (struct nclist)), - ALIGN(sizeof (struct narg)), - ALIGN(sizeof (struct narg)), - ALIGN(sizeof (struct nfile)), - ALIGN(sizeof (struct nfile)), - ALIGN(sizeof (struct nfile)), - ALIGN(sizeof (struct nfile)), - ALIGN(sizeof (struct nfile)), - ALIGN(sizeof (struct ndup)), - ALIGN(sizeof (struct ndup)), - ALIGN(sizeof (struct nhere)), - ALIGN(sizeof (struct nhere)), - ALIGN(sizeof (struct nnot)), -}; - - - -/* - * Delete a function if it exists. - */ - -static void -unsetfunc(char *name) -{ - struct tblentry *cmdp; - - if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) { - freefunc(cmdp->param.func); - delete_cmd_entry(); - } -} - - -/* - * Locate and print what a word is... - */ - -static int -typecmd(int argc, char **argv) -{ - int i; - int err = 0; - char *argv_a[2]; - - argv_a[1] = 0; - - for (i = 1; i < argc; i++) { - argv_a[0] = argv[i]; - argptr = argv_a; - optptr = "v"; - err |= hashcmd(argc, argv); - } - return err; -} - -#ifdef ASH_CMDCMD -static int -commandcmd(argc, argv) - int argc; - char **argv; -{ - int c; - int default_path = 0; - int verify_only = 0; - int verbose_verify_only = 0; - - while ((c = nextopt("pvV")) != '\0') - switch (c) { - case 'p': - default_path = 1; - break; - case 'v': - verify_only = 1; - break; - case 'V': - verbose_verify_only = 1; - break; - } - - if (default_path + verify_only + verbose_verify_only > 1 || - !*argptr) { - out2str( - "command [-p] command [arg ...]\n" - "command {-v|-V} command\n"); - return EX_USAGE; - } - - if (verify_only || verbose_verify_only) { - char *argv_a[2]; - - argv_a[1] = 0; - argv_a[0] = *argptr; - argptr = argv_a; - optptr = verbose_verify_only ? "v" : "V"; /* reverse special */ - return hashcmd(argc, argv); - } - - return 0; -} -#endif - -static int -path_change(newval, bltin) - const char *newval; - int *bltin; -{ - const char *old, *new; - int idx; - int firstchange; - - old = pathval(); - new = newval; - firstchange = 9999; /* assume no change */ - idx = 0; - *bltin = -1; - for (;;) { - if (*old != *new) { - firstchange = idx; - if ((*old == '\0' && *new == ':') - || (*old == ':' && *new == '\0')) - firstchange++; - old = new; /* ignore subsequent differences */ - } - if (*new == '\0') - break; - if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1)) - *bltin = idx; - if (*new == ':') { - idx++; - } - new++, old++; - } - if (builtinloc >= 0 && *bltin < 0) - firstchange = 0; - return firstchange; -} -/* - * Routines to expand arguments to commands. We have to deal with - * backquotes, shell variables, and file metacharacters. - */ -/* - * _rmescape() flags - */ -#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ -#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ - -/* - * Structure specifying which parts of the string should be searched - * for IFS characters. - */ - -struct ifsregion { - struct ifsregion *next; /* next region in list */ - int begoff; /* offset of start of region */ - int endoff; /* offset of end of region */ - int nulonly; /* search for nul bytes only */ -}; - - -static char *expdest; /* output of current string */ -static struct nodelist *argbackq; /* list of back quote expressions */ -static struct ifsregion ifsfirst; /* first struct in list of ifs regions */ -static struct ifsregion *ifslastp; /* last struct in list */ -static struct arglist exparg; /* holds expanded arg list */ - -static void argstr (char *, int); -static char *exptilde (char *, int); -static void expbackq (union node *, int, int); -static int subevalvar (char *, char *, int, int, int, int, int); -static int varisset (char *, int); -static void strtodest (const char *, const char *, int); -static void varvalue (char *, int, int); -static void recordregion (int, int, int); -static void removerecordregions (int); -static void ifsbreakup (char *, struct arglist *); -static void ifsfree (void); -static void expandmeta (struct strlist *, int); -#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) -#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB) -#if !defined(GLOB_BROKEN) -static void addglob (const glob_t *); -#endif -#endif -#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) -static void expmeta (char *, char *); -#endif -#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) -static struct strlist *expsort (struct strlist *); -static struct strlist *msort (struct strlist *, int); -#endif -static int patmatch (char *, char *, int); -#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) -static int patmatch2 (char *, char *, int); -#else -static int pmatch (char *, char *, int); -#define patmatch2 patmatch -#endif -static char *cvtnum (int, char *); - -/* - * Expand shell variables and backquotes inside a here document. - */ - -/* arg: the document, fd: where to write the expanded version */ -static inline void -expandhere(union node *arg, int fd) -{ - herefd = fd; - expandarg(arg, (struct arglist *)NULL, 0); - xwrite(fd, stackblock(), expdest - stackblock()); -} - - -/* - * Perform variable substitution and command substitution on an argument, - * placing the resulting list of arguments in arglist. If EXP_FULL is true, - * perform splitting and file name expansion. When arglist is NULL, perform - * here document expansion. - */ - -static void -expandarg(arg, arglist, flag) - union node *arg; - struct arglist *arglist; - int flag; -{ - struct strlist *sp; - char *p; - - argbackq = arg->narg.backquote; - STARTSTACKSTR(expdest); - ifsfirst.next = NULL; - ifslastp = NULL; - argstr(arg->narg.text, flag); - if (arglist == NULL) { - return; /* here document expanded */ - } - STPUTC('\0', expdest); - p = grabstackstr(expdest); - exparg.lastp = &exparg.list; - /* - * TODO - EXP_REDIR - */ - if (flag & EXP_FULL) { - ifsbreakup(p, &exparg); - *exparg.lastp = NULL; - exparg.lastp = &exparg.list; - expandmeta(exparg.list, flag); - } else { - if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ - rmescapes(p); - sp = (struct strlist *)stalloc(sizeof (struct strlist)); - sp->text = p; - *exparg.lastp = sp; - exparg.lastp = &sp->next; - } - ifsfree(); - *exparg.lastp = NULL; - if (exparg.list) { - *arglist->lastp = exparg.list; - arglist->lastp = exparg.lastp; - } -} - - -/* - * Expand a variable, and return a pointer to the next character in the - * input string. - */ - -static inline char * -evalvar(p, flag) - char *p; - int flag; -{ - int subtype; - int varflags; - char *var; - const char *val; - int patloc; - int c; - int set; - int special; - int startloc; - int varlen; - int easy; - int quotes = flag & (EXP_FULL | EXP_CASE); - - varflags = *p++; - subtype = varflags & VSTYPE; - var = p; - special = 0; - if (! is_name(*p)) - special = 1; - p = strchr(p, '=') + 1; -again: /* jump here after setting a variable with ${var=text} */ - if (special) { - set = varisset(var, varflags & VSNUL); - val = NULL; - } else { - val = lookupvar(var); - if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { - val = NULL; - set = 0; - } else - set = 1; - } - varlen = 0; - startloc = expdest - stackblock(); - if (set && subtype != VSPLUS) { - /* insert the value of the variable */ - if (special) { - varvalue(var, varflags & VSQUOTE, flag); - if (subtype == VSLENGTH) { - varlen = expdest - stackblock() - startloc; - STADJUST(-varlen, expdest); - } - } else { - if (subtype == VSLENGTH) { - varlen = strlen(val); - } else { - strtodest( - val, - varflags & VSQUOTE ? - DQSYNTAX : BASESYNTAX, - quotes - ); - } - } - } - - if (subtype == VSPLUS) - set = ! set; - - easy = ((varflags & VSQUOTE) == 0 || - (*var == '@' && shellparam.nparam != 1)); - - - switch (subtype) { - case VSLENGTH: - expdest = cvtnum(varlen, expdest); - goto record; - - case VSNORMAL: - if (!easy) - break; -record: - recordregion(startloc, expdest - stackblock(), - varflags & VSQUOTE); - break; - - case VSPLUS: - case VSMINUS: - if (!set) { - argstr(p, flag); - break; - } - if (easy) - goto record; - break; - - case VSTRIMLEFT: - case VSTRIMLEFTMAX: - case VSTRIMRIGHT: - case VSTRIMRIGHTMAX: - if (!set) - break; - /* - * Terminate the string and start recording the pattern - * right after it - */ - STPUTC('\0', expdest); - patloc = expdest - stackblock(); - if (subevalvar(p, NULL, patloc, subtype, - startloc, varflags, quotes) == 0) { - int amount = (expdest - stackblock() - patloc) + 1; - STADJUST(-amount, expdest); - } - /* Remove any recorded regions beyond start of variable */ - removerecordregions(startloc); - goto record; - - case VSASSIGN: - case VSQUESTION: - if (!set) { - if (subevalvar(p, var, 0, subtype, startloc, - varflags, quotes)) { - varflags &= ~VSNUL; - /* - * Remove any recorded regions beyond - * start of variable - */ - removerecordregions(startloc); - goto again; - } - break; - } - if (easy) - goto record; - break; - -#ifdef DEBUG - default: - abort(); -#endif - } - - if (subtype != VSNORMAL) { /* skip to end of alternative */ - int nesting = 1; - for (;;) { - if ((c = *p++) == CTLESC) - p++; - else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { - if (set) - argbackq = argbackq->next; - } else if (c == CTLVAR) { - if ((*p++ & VSTYPE) != VSNORMAL) - nesting++; - } else if (c == CTLENDVAR) { - if (--nesting == 0) - break; - } - } - } - return p; -} - - -/* - * Perform variable and command substitution. If EXP_FULL is set, output CTLESC - * characters to allow for further processing. Otherwise treat - * $@ like $* since no splitting will be performed. - */ - -static void -argstr(p, flag) - char *p; - int flag; -{ - char c; - int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ - int firsteq = 1; - - if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE))) - p = exptilde(p, flag); - for (;;) { - switch (c = *p++) { - case '\0': - case CTLENDVAR: /* ??? */ - goto breakloop; - case CTLQUOTEMARK: - /* "$@" syntax adherence hack */ - if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=') - break; - if ((flag & EXP_FULL) != 0) - STPUTC(c, expdest); - break; - case CTLESC: - if (quotes) - STPUTC(c, expdest); - c = *p++; - STPUTC(c, expdest); - break; - case CTLVAR: - p = evalvar(p, flag); - break; - case CTLBACKQ: - case CTLBACKQ|CTLQUOTE: - expbackq(argbackq->n, c & CTLQUOTE, flag); - argbackq = argbackq->next; - break; -#ifdef ASH_MATH_SUPPORT - case CTLENDARI: - expari(flag); - break; -#endif - case ':': - case '=': - /* - * sort of a hack - expand tildes in variable - * assignments (after the first '=' and after ':'s). - */ - STPUTC(c, expdest); - if (flag & EXP_VARTILDE && *p == '~') { - if (c == '=') { - if (firsteq) - firsteq = 0; - else - break; - } - p = exptilde(p, flag); - } - break; - default: - STPUTC(c, expdest); - } - } -breakloop:; - return; -} - -static char * -exptilde(p, flag) - char *p; - int flag; -{ - char c, *startp = p; - struct passwd *pw; - const char *home; - int quotes = flag & (EXP_FULL | EXP_CASE); - - while ((c = *p) != '\0') { - switch(c) { - case CTLESC: - return (startp); - case CTLQUOTEMARK: - return (startp); - case ':': - if (flag & EXP_VARTILDE) - goto done; - break; - case '/': - goto done; - } - p++; - } -done: - *p = '\0'; - if (*(startp+1) == '\0') { - if ((home = lookupvar("HOME")) == NULL) - goto lose; - } else { - if ((pw = getpwnam(startp+1)) == NULL) - goto lose; - home = pw->pw_dir; - } - if (*home == '\0') - goto lose; - *p = c; - strtodest(home, SQSYNTAX, quotes); - return (p); -lose: - *p = c; - return (startp); -} - - -static void -removerecordregions(int endoff) -{ - if (ifslastp == NULL) - return; - - if (ifsfirst.endoff > endoff) { - while (ifsfirst.next != NULL) { - struct ifsregion *ifsp; - INTOFF; - ifsp = ifsfirst.next->next; - ckfree(ifsfirst.next); - ifsfirst.next = ifsp; - INTON; - } - if (ifsfirst.begoff > endoff) - ifslastp = NULL; - else { - ifslastp = &ifsfirst; - ifsfirst.endoff = endoff; - } - return; - } - - ifslastp = &ifsfirst; - while (ifslastp->next && ifslastp->next->begoff < endoff) - ifslastp=ifslastp->next; - while (ifslastp->next != NULL) { - struct ifsregion *ifsp; - INTOFF; - ifsp = ifslastp->next->next; - ckfree(ifslastp->next); - ifslastp->next = ifsp; - INTON; - } - if (ifslastp->endoff > endoff) - ifslastp->endoff = endoff; -} - - -#ifdef ASH_MATH_SUPPORT -/* - * Expand arithmetic expression. Backup to start of expression, - * evaluate, place result in (backed up) result, adjust string position. - */ -static void -expari(int flag) -{ - char *p, *start; - int errcode; - int result; - int begoff; - int quotes = flag & (EXP_FULL | EXP_CASE); - int quoted; - - /* ifsfree(); */ - - /* - * This routine is slightly over-complicated for - * efficiency. First we make sure there is - * enough space for the result, which may be bigger - * than the expression if we add exponentation. Next we - * scan backwards looking for the start of arithmetic. If the - * next previous character is a CTLESC character, then we - * have to rescan starting from the beginning since CTLESC - * characters have to be processed left to right. - */ - CHECKSTRSPACE(10, expdest); - USTPUTC('\0', expdest); - start = stackblock(); - p = expdest - 1; - while (*p != CTLARI && p >= start) - --p; - if (*p != CTLARI) - error("missing CTLARI (shouldn't happen)"); - if (p > start && *(p-1) == CTLESC) - for (p = start; *p != CTLARI; p++) - if (*p == CTLESC) - p++; - - if (p[1] == '"') - quoted=1; - else - quoted=0; - begoff = p - start; - removerecordregions(begoff); - if (quotes) - rmescapes(p+2); - result = arith(p+2, &errcode); - if (errcode < 0) { - if(errcode == -2) - error("divide by zero"); - else - error("syntax error: \"%s\"\n", p+2); - } - snprintf(p, 12, "%d", result); - - while (*p++) - ; - - if (quoted == 0) - recordregion(begoff, p - 1 - start, 0); - result = expdest - p + 1; - STADJUST(-result, expdest); -} -#endif - -/* - * Expand stuff in backwards quotes. - */ - -static void -expbackq(cmd, quoted, flag) - union node *cmd; - int quoted; - int flag; -{ - volatile struct backcmd in; - int i; - char buf[128]; - char *p; - char *dest = expdest; - volatile struct ifsregion saveifs; - struct ifsregion *volatile savelastp; - struct nodelist *volatile saveargbackq; - char lastc; - int startloc = dest - stackblock(); - char const *syntax = quoted? DQSYNTAX : BASESYNTAX; - volatile int saveherefd; - int quotes = flag & (EXP_FULL | EXP_CASE); - struct jmploc jmploc; - struct jmploc *volatile savehandler; - int ex; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &dest; - (void) &syntax; -#endif - - in.fd = -1; - in.buf = 0; - in.jp = 0; - - INTOFF; - saveifs = ifsfirst; - savelastp = ifslastp; - saveargbackq = argbackq; - saveherefd = herefd; - herefd = -1; - if ((ex = setjmp(jmploc.loc))) { - goto err1; - } - savehandler = handler; - handler = &jmploc; - INTON; - p = grabstackstr(dest); - evalbackcmd(cmd, (struct backcmd *) &in); - ungrabstackstr(p, dest); -err1: - INTOFF; - ifsfirst = saveifs; - ifslastp = savelastp; - argbackq = saveargbackq; - herefd = saveherefd; - if (ex) { - goto err2; - } - - p = in.buf; - lastc = '\0'; - for (;;) { - if (--in.nleft < 0) { - if (in.fd < 0) - break; - i = safe_read(in.fd, buf, sizeof buf); - TRACE(("expbackq: read returns %d\n", i)); - if (i <= 0) - break; - p = buf; - in.nleft = i - 1; - } - lastc = *p++; - if (lastc != '\0') { - if (quotes && syntax[(int)lastc] == CCTL) - STPUTC(CTLESC, dest); - STPUTC(lastc, dest); - } - } - - /* Eat all trailing newlines */ - for (; dest > stackblock() && dest[-1] == '\n';) - STUNPUTC(dest); - -err2: - if (in.fd >= 0) - close(in.fd); - if (in.buf) - ckfree(in.buf); - if (in.jp) - exitstatus = waitforjob(in.jp); - handler = savehandler; - if (ex) { - longjmp(handler->loc, 1); - } - if (quoted == 0) - recordregion(startloc, dest - stackblock(), 0); - TRACE(("evalbackq: size=%d: \"%.*s\"\n", - (dest - stackblock()) - startloc, - (dest - stackblock()) - startloc, - stackblock() + startloc)); - expdest = dest; - INTON; -} - -static int -subevalvar(p, str, strloc, subtype, startloc, varflags, quotes) - char *p; - char *str; - int strloc; - int subtype; - int startloc; - int varflags; - int quotes; -{ - char *startp; - char *loc = NULL; - char *q; - int c = 0; - int saveherefd = herefd; - struct nodelist *saveargbackq = argbackq; - int amount; - - herefd = -1; - argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); - STACKSTRNUL(expdest); - herefd = saveherefd; - argbackq = saveargbackq; - startp = stackblock() + startloc; - if (str == NULL) - str = stackblock() + strloc; - - switch (subtype) { - case VSASSIGN: - setvar(str, startp, 0); - amount = startp - expdest; - STADJUST(amount, expdest); - varflags &= ~VSNUL; - if (c != 0) - *loc = c; - return 1; - - case VSQUESTION: - if (*p != CTLENDVAR) { - out2fmt(snlfmt, startp); - error((char *)NULL); - } - error("%.*s: parameter %snot set", p - str - 1, - str, (varflags & VSNUL) ? "null or " - : nullstr); - /* NOTREACHED */ - - case VSTRIMLEFT: - for (loc = startp; loc < str; loc++) { - c = *loc; - *loc = '\0'; - if (patmatch2(str, startp, quotes)) - goto recordleft; - *loc = c; - if (quotes && *loc == CTLESC) - loc++; - } - return 0; - - case VSTRIMLEFTMAX: - for (loc = str - 1; loc >= startp;) { - c = *loc; - *loc = '\0'; - if (patmatch2(str, startp, quotes)) - goto recordleft; - *loc = c; - loc--; - if (quotes && loc > startp && *(loc - 1) == CTLESC) { - for (q = startp; q < loc; q++) - if (*q == CTLESC) - q++; - if (q > loc) - loc--; - } - } - return 0; - - case VSTRIMRIGHT: - for (loc = str - 1; loc >= startp;) { - if (patmatch2(str, loc, quotes)) - goto recordright; - loc--; - if (quotes && loc > startp && *(loc - 1) == CTLESC) { - for (q = startp; q < loc; q++) - if (*q == CTLESC) - q++; - if (q > loc) - loc--; - } - } - return 0; - - case VSTRIMRIGHTMAX: - for (loc = startp; loc < str - 1; loc++) { - if (patmatch2(str, loc, quotes)) - goto recordright; - if (quotes && *loc == CTLESC) - loc++; - } - return 0; - -#ifdef DEBUG - default: - abort(); -#endif - } - -recordleft: - *loc = c; - amount = ((str - 1) - (loc - startp)) - expdest; - STADJUST(amount, expdest); - while (loc != str - 1) - *startp++ = *loc++; - return 1; - -recordright: - amount = loc - expdest; - STADJUST(amount, expdest); - STPUTC('\0', expdest); - STADJUST(-1, expdest); - return 1; -} - - -/* - * Test whether a specialized variable is set. - */ - -static int -varisset(name, nulok) - char *name; - int nulok; -{ - if (*name == '!') - return backgndpid != -1; - else if (*name == '@' || *name == '*') { - if (*shellparam.p == NULL) - return 0; - - if (nulok) { - char **av; - - for (av = shellparam.p; *av; av++) - if (**av != '\0') - return 1; - return 0; - } - } else if (is_digit(*name)) { - char *ap; - int num = atoi(name); - - if (num > shellparam.nparam) - return 0; - - if (num == 0) - ap = arg0; - else - ap = shellparam.p[num - 1]; - - if (nulok && (ap == NULL || *ap == '\0')) - return 0; - } - return 1; -} - -/* - * Put a string on the stack. - */ - -static void -strtodest(p, syntax, quotes) - const char *p; - const char *syntax; - int quotes; -{ - while (*p) { - if (quotes && syntax[(int) *p] == CCTL) - STPUTC(CTLESC, expdest); - STPUTC(*p++, expdest); - } -} - -/* - * Add the value of a specialized variable to the stack string. - */ - -static void -varvalue(name, quoted, flags) - char *name; - int quoted; - int flags; -{ - int num; - char *p; - int i; - int sep; - int sepq = 0; - char **ap; - char const *syntax; - int allow_split = flags & EXP_FULL; - int quotes = flags & (EXP_FULL | EXP_CASE); - - syntax = quoted ? DQSYNTAX : BASESYNTAX; - switch (*name) { - case '$': - num = rootpid; - goto numvar; - case '?': - num = oexitstatus; - goto numvar; - case '#': - num = shellparam.nparam; - goto numvar; - case '!': - num = backgndpid; -numvar: - expdest = cvtnum(num, expdest); - break; - case '-': - for (i = 0 ; i < NOPTS ; i++) { - if (optent_val(i)) - STPUTC(optent_letter(optlist[i]), expdest); - } - break; - case '@': - if (allow_split && quoted) { - sep = 1 << CHAR_BIT; - goto param; - } - /* fall through */ - case '*': - sep = ifsset() ? ifsval()[0] : ' '; - if (quotes) { - sepq = syntax[(int) sep] == CCTL; - } -param: - for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { - strtodest(p, syntax, quotes); - if (*ap && sep) { - if (sepq) - STPUTC(CTLESC, expdest); - STPUTC(sep, expdest); - } - } - break; - case '0': - strtodest(arg0, syntax, quotes); - break; - default: - num = atoi(name); - if (num > 0 && num <= shellparam.nparam) { - strtodest(shellparam.p[num - 1], syntax, quotes); - } - break; - } -} - - -/* - * Record the fact that we have to scan this region of the - * string for IFS characters. - */ - -static void -recordregion(start, end, nulonly) - int start; - int end; - int nulonly; -{ - struct ifsregion *ifsp; - - if (ifslastp == NULL) { - ifsp = &ifsfirst; - } else { - INTOFF; - ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); - ifsp->next = NULL; - ifslastp->next = ifsp; - INTON; - } - ifslastp = ifsp; - ifslastp->begoff = start; - ifslastp->endoff = end; - ifslastp->nulonly = nulonly; -} - - - -/* - * Break the argument string into pieces based upon IFS and add the - * strings to the argument list. The regions of the string to be - * searched for IFS characters have been stored by recordregion. - */ -static void -ifsbreakup(string, arglist) - char *string; - struct arglist *arglist; - { - struct ifsregion *ifsp; - struct strlist *sp; - char *start; - char *p; - char *q; - const char *ifs, *realifs; - int ifsspc; - int nulonly; - - - start = string; - ifsspc = 0; - nulonly = 0; - realifs = ifsset() ? ifsval() : defifs; - if (ifslastp != NULL) { - ifsp = &ifsfirst; - do { - p = string + ifsp->begoff; - nulonly = ifsp->nulonly; - ifs = nulonly ? nullstr : realifs; - ifsspc = 0; - while (p < string + ifsp->endoff) { - q = p; - if (*p == CTLESC) - p++; - if (strchr(ifs, *p)) { - if (!nulonly) - ifsspc = (strchr(defifs, *p) != NULL); - /* Ignore IFS whitespace at start */ - if (q == start && ifsspc) { - p++; - start = p; - continue; - } - *q = '\0'; - sp = (struct strlist *)stalloc(sizeof *sp); - sp->text = start; - *arglist->lastp = sp; - arglist->lastp = &sp->next; - p++; - if (!nulonly) { - for (;;) { - if (p >= string + ifsp->endoff) { - break; - } - q = p; - if (*p == CTLESC) - p++; - if (strchr(ifs, *p) == NULL ) { - p = q; - break; - } else if (strchr(defifs, *p) == NULL) { - if (ifsspc) { - p++; - ifsspc = 0; - } else { - p = q; - break; - } - } else - p++; - } - } - start = p; - } else - p++; - } - } while ((ifsp = ifsp->next) != NULL); - if (!(*start || (!ifsspc && start > string && nulonly))) { - return; - } - } - - sp = (struct strlist *)stalloc(sizeof *sp); - sp->text = start; - *arglist->lastp = sp; - arglist->lastp = &sp->next; -} - -static void -ifsfree() -{ - while (ifsfirst.next != NULL) { - struct ifsregion *ifsp; - INTOFF; - ifsp = ifsfirst.next->next; - ckfree(ifsfirst.next); - ifsfirst.next = ifsp; - INTON; - } - ifslastp = NULL; - ifsfirst.next = NULL; -} - -/* - * Add a file name to the list. - */ - -static void -addfname(const char *name) -{ - char *p; - struct strlist *sp; - - p = sstrdup(name); - sp = (struct strlist *)stalloc(sizeof *sp); - sp->text = p; - *exparg.lastp = sp; - exparg.lastp = &sp->next; -} - -/* - * Expand shell metacharacters. At this point, the only control characters - * should be escapes. The results are stored in the list exparg. - */ - -#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) -static void -expandmeta(str, flag) - struct strlist *str; - int flag; -{ - const char *p; - glob_t pglob; - /* TODO - EXP_REDIR */ - - while (str) { - if (fflag) - goto nometa; - p = preglob(str->text); - INTOFF; - switch (glob(p, 0, 0, &pglob)) { - case 0: - if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0])) - goto nometa2; - addglob(&pglob); - globfree(&pglob); - INTON; - break; - case GLOB_NOMATCH: -nometa2: - globfree(&pglob); - INTON; -nometa: - *exparg.lastp = str; - rmescapes(str->text); - exparg.lastp = &str->next; - break; - default: /* GLOB_NOSPACE */ - error("Out of space"); - } - str = str->next; - } -} - - -/* - * Add the result of glob(3) to the list. - */ - -static void -addglob(pglob) - const glob_t *pglob; -{ - char **p = pglob->gl_pathv; - - do { - addfname(*p); - } while (*++p); -} - - -#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */ -static char *expdir; - - -static void -expandmeta(str, flag) - struct strlist *str; - int flag; -{ - char *p; - struct strlist **savelastp; - struct strlist *sp; - char c; - /* TODO - EXP_REDIR */ - - while (str) { - if (fflag) - goto nometa; - p = str->text; - for (;;) { /* fast check for meta chars */ - if ((c = *p++) == '\0') - goto nometa; - if (c == '*' || c == '?' || c == '[' || c == '!') - break; - } - savelastp = exparg.lastp; - INTOFF; - if (expdir == NULL) { - int i = strlen(str->text); - expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ - } - - expmeta(expdir, str->text); - ckfree(expdir); - expdir = NULL; - INTON; - if (exparg.lastp == savelastp) { - /* - * no matches - */ -nometa: - *exparg.lastp = str; - rmescapes(str->text); - exparg.lastp = &str->next; - } else { - *exparg.lastp = NULL; - *savelastp = sp = expsort(*savelastp); - while (sp->next != NULL) - sp = sp->next; - exparg.lastp = &sp->next; - } - str = str->next; - } -} - - -/* - * Do metacharacter (i.e. *, ?, [...]) expansion. - */ - -static void -expmeta(enddir, name) - char *enddir; - char *name; - { - char *p; - const char *cp; - char *q; - char *start; - char *endname; - int metaflag; - struct stat statb; - DIR *dirp; - struct dirent *dp; - int atend; - int matchdot; - - metaflag = 0; - start = name; - for (p = name ; ; p++) { - if (*p == '*' || *p == '?') - metaflag = 1; - else if (*p == '[') { - q = p + 1; - if (*q == '!') - q++; - for (;;) { - while (*q == CTLQUOTEMARK) - q++; - if (*q == CTLESC) - q++; - if (*q == '/' || *q == '\0') - break; - if (*++q == ']') { - metaflag = 1; - break; - } - } - } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) { - metaflag = 1; - } else if (*p == '\0') - break; - else if (*p == CTLQUOTEMARK) - continue; - else if (*p == CTLESC) - p++; - if (*p == '/') { - if (metaflag) - break; - start = p + 1; - } - } - if (metaflag == 0) { /* we've reached the end of the file name */ - if (enddir != expdir) - metaflag++; - for (p = name ; ; p++) { - if (*p == CTLQUOTEMARK) - continue; - if (*p == CTLESC) - p++; - *enddir++ = *p; - if (*p == '\0') - break; - } - if (metaflag == 0 || lstat(expdir, &statb) >= 0) - addfname(expdir); - return; - } - endname = p; - if (start != name) { - p = name; - while (p < start) { - while (*p == CTLQUOTEMARK) - p++; - if (*p == CTLESC) - p++; - *enddir++ = *p++; - } - } - if (enddir == expdir) { - cp = "."; - } else if (enddir == expdir + 1 && *expdir == '/') { - cp = "/"; - } else { - cp = expdir; - enddir[-1] = '\0'; - } - if ((dirp = opendir(cp)) == NULL) - return; - if (enddir != expdir) - enddir[-1] = '/'; - if (*endname == 0) { - atend = 1; - } else { - atend = 0; - *endname++ = '\0'; - } - matchdot = 0; - p = start; - while (*p == CTLQUOTEMARK) - p++; - if (*p == CTLESC) - p++; - if (*p == '.') - matchdot++; - while (! int_pending() && (dp = readdir(dirp)) != NULL) { - if (dp->d_name[0] == '.' && ! matchdot) - continue; - if (patmatch(start, dp->d_name, 0)) { - if (atend) { - strcpy(enddir, dp->d_name); - addfname(expdir); - } else { - for (p = enddir, cp = dp->d_name; - (*p++ = *cp++) != '\0';) - continue; - p[-1] = '/'; - expmeta(p, endname); - } - } - } - closedir(dirp); - if (! atend) - endname[-1] = '/'; -} -#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */ - - - -#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) -/* - * Sort the results of file name expansion. It calculates the number of - * strings to sort and then calls msort (short for merge sort) to do the - * work. - */ - -static struct strlist * -expsort(str) - struct strlist *str; - { - int len; - struct strlist *sp; - - len = 0; - for (sp = str ; sp ; sp = sp->next) - len++; - return msort(str, len); -} - - -static struct strlist * -msort(list, len) - struct strlist *list; - int len; -{ - struct strlist *p, *q = NULL; - struct strlist **lpp; - int half; - int n; - - if (len <= 1) - return list; - half = len >> 1; - p = list; - for (n = half ; --n >= 0 ; ) { - q = p; - p = p->next; - } - q->next = NULL; /* terminate first half of list */ - q = msort(list, half); /* sort first half of list */ - p = msort(p, len - half); /* sort second half */ - lpp = &list; - for (;;) { - if (strcmp(p->text, q->text) < 0) { - *lpp = p; - lpp = &p->next; - if ((p = *lpp) == NULL) { - *lpp = q; - break; - } - } else { - *lpp = q; - lpp = &q->next; - if ((q = *lpp) == NULL) { - *lpp = p; - break; - } - } - } - return list; -} -#endif - - - -/* - * Returns true if the pattern matches the string. - */ - -#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) -/* squoted: string might have quote chars */ -static int -patmatch(char *pattern, char *string, int squoted) -{ - const char *p; - char *q; - - p = preglob(pattern); - q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string; - - return !fnmatch(p, q, 0); -} - - -static int -patmatch2(char *pattern, char *string, int squoted) -{ - char *p; - int res; - - sstrnleft--; - p = grabstackstr(expdest); - res = patmatch(pattern, string, squoted); - ungrabstackstr(p, expdest); - return res; -} -#else -static int -patmatch(char *pattern, char *string, int squoted) { - return pmatch(pattern, string, squoted); -} - - -static int -pmatch(char *pattern, char *string, int squoted) -{ - char *p, *q; - char c; - - p = pattern; - q = string; - for (;;) { - switch (c = *p++) { - case '\0': - goto breakloop; - case CTLESC: - if (squoted && *q == CTLESC) - q++; - if (*q++ != *p++) - return 0; - break; - case CTLQUOTEMARK: - continue; - case '?': - if (squoted && *q == CTLESC) - q++; - if (*q++ == '\0') - return 0; - break; - case '*': - c = *p; - while (c == CTLQUOTEMARK || c == '*') - c = *++p; - if (c != CTLESC && c != CTLQUOTEMARK && - c != '?' && c != '*' && c != '[') { - while (*q != c) { - if (squoted && *q == CTLESC && - q[1] == c) - break; - if (*q == '\0') - return 0; - if (squoted && *q == CTLESC) - q++; - q++; - } - } - do { - if (pmatch(p, q, squoted)) - return 1; - if (squoted && *q == CTLESC) - q++; - } while (*q++ != '\0'); - return 0; - case '[': { - char *endp; - int invert, found; - char chr; - - endp = p; - if (*endp == '!') - endp++; - for (;;) { - while (*endp == CTLQUOTEMARK) - endp++; - if (*endp == '\0') - goto dft; /* no matching ] */ - if (*endp == CTLESC) - endp++; - if (*++endp == ']') - break; - } - invert = 0; - if (*p == '!') { - invert++; - p++; - } - found = 0; - chr = *q++; - if (squoted && chr == CTLESC) - chr = *q++; - if (chr == '\0') - return 0; - c = *p++; - do { - if (c == CTLQUOTEMARK) - continue; - if (c == CTLESC) - c = *p++; - if (*p == '-' && p[1] != ']') { - p++; - while (*p == CTLQUOTEMARK) - p++; - if (*p == CTLESC) - p++; - if (chr >= c && chr <= *p) - found = 1; - p++; - } else { - if (chr == c) - found = 1; - } - } while ((c = *p++) != ']'); - if (found == invert) - return 0; - break; - } -dft: default: - if (squoted && *q == CTLESC) - q++; - if (*q++ != c) - return 0; - break; - } - } -breakloop: - if (*q != '\0') - return 0; - return 1; -} -#endif - - - -/* - * Remove any CTLESC characters from a string. - */ - -#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) -static char * -_rmescapes(char *str, int flag) -{ - char *p, *q, *r; - static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 }; - - p = strpbrk(str, qchars); - if (!p) { - return str; - } - q = p; - r = str; - if (flag & RMESCAPE_ALLOC) { - size_t len = p - str; - q = r = stalloc(strlen(p) + len + 1); - if (len > 0) { - memcpy(q, str, len); - q += len; - } - } - while (*p) { - if (*p == CTLQUOTEMARK) { - p++; - continue; - } - if (*p == CTLESC) { - p++; - if (flag & RMESCAPE_GLOB && *p != '/') { - *q++ = '\\'; - } - } - *q++ = *p++; - } - *q = '\0'; - return r; -} -#else -static void -rmescapes(str) - char *str; -{ - char *p, *q; - - p = str; - while (*p != CTLESC && *p != CTLQUOTEMARK) { - if (*p++ == '\0') - return; - } - q = p; - while (*p) { - if (*p == CTLQUOTEMARK) { - p++; - continue; - } - if (*p == CTLESC) - p++; - *q++ = *p++; - } - *q = '\0'; -} -#endif - - - -/* - * See if a pattern matches in a case statement. - */ - -static int -casematch(union node *pattern, const char *val) -{ - struct stackmark smark; - int result; - char *p; - - setstackmark(&smark); - argbackq = pattern->narg.backquote; - STARTSTACKSTR(expdest); - ifslastp = NULL; - argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); - STPUTC('\0', expdest); - p = grabstackstr(expdest); - result = patmatch(p, (char *)val, 0); - popstackmark(&smark); - return result; -} - -/* - * Our own itoa(). - */ - -static char * -cvtnum(num, buf) - int num; - char *buf; - { - int len; - - CHECKSTRSPACE(32, buf); - len = sprintf(buf, "%d", num); - STADJUST(len, buf); - return buf; -} -/* - * Editline and history functions (and glue). - */ -static int histcmd(argc, argv) - int argc; - char **argv; -{ - error("not compiled with history support"); - /* NOTREACHED */ -} - - -struct redirtab { - struct redirtab *next; - short renamed[10]; /* Current ash support only 0-9 descriptors */ - /* char on arm (and others) can't be negative */ -}; - -static struct redirtab *redirlist; - -extern char **environ; - - - -/* - * Initialization code. - */ - -static void -init(void) { - - /* from cd.c: */ - { - setpwd(0, 0); - } - - /* from input.c: */ - { - basepf.nextc = basepf.buf = basebuf; - } - - /* from var.c: */ - { - char **envp; - char ppid[32]; - - initvar(); - for (envp = environ ; *envp ; envp++) { - if (strchr(*envp, '=')) { - setvareq(*envp, VEXPORT|VTEXTFIXED); - } - } - - snprintf(ppid, sizeof(ppid), "%d", (int) getppid()); - setvar("PPID", ppid, 0); - } -} - - - -/* - * This routine is called when an error or an interrupt occurs in an - * interactive shell and control is returned to the main command loop. - */ - -/* 1 == check for aliases, 2 == also check for assignments */ -static int checkalias; /* also used in no alias mode for check assignments */ - -static void -reset(void) { - - /* from eval.c: */ - { - evalskip = 0; - loopnest = 0; - funcnest = 0; - } - - /* from input.c: */ - { - if (exception != EXSHELLPROC) - parselleft = parsenleft = 0; /* clear input buffer */ - popallfiles(); - } - - /* from parser.c: */ - { - tokpushback = 0; - checkkwd = 0; - checkalias = 0; - } - - /* from redir.c: */ - { - while (redirlist) - popredir(); - } - -} - - - -/* - * This file implements the input routines used by the parser. - */ - -#ifdef BB_FEATURE_COMMAND_EDITING -static const char * cmdedit_prompt; -static inline void putprompt(const char *s) { - cmdedit_prompt = s; -} -#else -static inline void putprompt(const char *s) { - out2str(s); -} -#endif - -#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ - - - -/* - * Same as pgetc(), but ignores PEOA. - */ - -#ifdef ASH_ALIAS -static int -pgetc2() -{ - int c; - do { - c = pgetc_macro(); - } while (c == PEOA); - return c; -} -#else -static inline int pgetc2() { return pgetc_macro(); } -#endif - -/* - * Read a line from the script. - */ - -static inline char * -pfgets(char *line, int len) -{ - char *p = line; - int nleft = len; - int c; - - while (--nleft > 0) { - c = pgetc2(); - if (c == PEOF) { - if (p == line) - return NULL; - break; - } - *p++ = c; - if (c == '\n') - break; - } - *p = '\0'; - return line; -} - -static inline int -preadfd(void) -{ - int nr; - char *buf = parsefile->buf; - parsenextc = buf; - -retry: -#ifdef BB_FEATURE_COMMAND_EDITING - { - if (!iflag || parsefile->fd) - nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); - else { - nr = cmdedit_read_input((char*)cmdedit_prompt, buf); - } - } -#else - nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); -#endif - - if (nr < 0) { - if (parsefile->fd == 0 && errno == EWOULDBLOCK) { - int flags = fcntl(0, F_GETFL, 0); - if (flags >= 0 && flags & O_NONBLOCK) { - flags &=~ O_NONBLOCK; - if (fcntl(0, F_SETFL, flags) >= 0) { - out2str("sh: turning off NDELAY mode\n"); - goto retry; - } - } - } - } - return nr; -} - -static void -popstring(void) -{ - struct strpush *sp = parsefile->strpush; - - INTOFF; -#ifdef ASH_ALIAS - if (sp->ap) { - if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { - if (!checkalias) { - checkalias = 1; - } - } - if (sp->string != sp->ap->val) { - ckfree(sp->string); - } - - sp->ap->flag &= ~ALIASINUSE; - if (sp->ap->flag & ALIASDEAD) { - unalias(sp->ap->name); - } - } -#endif - parsenextc = sp->prevstring; - parsenleft = sp->prevnleft; -/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ - parsefile->strpush = sp->prev; - if (sp != &(parsefile->basestrpush)) - ckfree(sp); - INTON; -} - - -/* - * Refill the input buffer and return the next input character: - * - * 1) If a string was pushed back on the input, pop it; - * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading - * from a string so we can't refill the buffer, return EOF. - * 3) If the is more stuff in this buffer, use it else call read to fill it. - * 4) Process input up to the next newline, deleting nul characters. - */ - -static int -preadbuffer(void) -{ - char *p, *q; - int more; - char savec; - - while (parsefile->strpush) { -#ifdef ASH_ALIAS - if (parsenleft == -1 && parsefile->strpush->ap && - parsenextc[-1] != ' ' && parsenextc[-1] != '\t') { - return PEOA; - } -#endif - popstring(); - if (--parsenleft >= 0) - return (*parsenextc++); - } - if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) - return PEOF; - flushall(); - -again: - if (parselleft <= 0) { - if ((parselleft = preadfd()) <= 0) { - parselleft = parsenleft = EOF_NLEFT; - return PEOF; - } - } - - q = p = parsenextc; - - /* delete nul characters */ - for (more = 1; more;) { - switch (*p) { - case '\0': - p++; /* Skip nul */ - goto check; - - - case '\n': - parsenleft = q - parsenextc; - more = 0; /* Stop processing here */ - break; - } - - *q++ = *p++; -check: - if (--parselleft <= 0 && more) { - parsenleft = q - parsenextc - 1; - if (parsenleft < 0) - goto again; - more = 0; - } - } - - savec = *q; - *q = '\0'; - - if (vflag) { - out2str(parsenextc); - } - - *q = savec; - - return *parsenextc++; -} - - -/* - * Push a string back onto the input at this current parsefile level. - * We handle aliases this way. - */ -static void -pushstring(char *s, int len, void *ap) -{ - struct strpush *sp; - - INTOFF; -/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ - if (parsefile->strpush) { - sp = ckmalloc(sizeof (struct strpush)); - sp->prev = parsefile->strpush; - parsefile->strpush = sp; - } else - sp = parsefile->strpush = &(parsefile->basestrpush); - sp->prevstring = parsenextc; - sp->prevnleft = parsenleft; -#ifdef ASH_ALIAS - sp->ap = (struct alias *)ap; - if (ap) { - ((struct alias *)ap)->flag |= ALIASINUSE; - sp->string = s; - } -#endif - parsenextc = s; - parsenleft = len; - INTON; -} - - -/* - * Like setinputfile, but takes input from a string. - */ - -static void -setinputstring(char *string) -{ - INTOFF; - pushfile(); - parsenextc = string; - parsenleft = strlen(string); - parsefile->buf = NULL; - plinno = 1; - INTON; -} - - - -/* - * To handle the "." command, a stack of input files is used. Pushfile - * adds a new entry to the stack and popfile restores the previous level. - */ - -static void -pushfile(void) { - struct parsefile *pf; - - parsefile->nleft = parsenleft; - parsefile->lleft = parselleft; - parsefile->nextc = parsenextc; - parsefile->linno = plinno; - pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); - pf->prev = parsefile; - pf->fd = -1; - pf->strpush = NULL; - pf->basestrpush.prev = NULL; - parsefile = pf; -} - -#ifdef JOBS -static void restartjob (struct job *); -#endif -static void freejob (struct job *); -static struct job *getjob (const char *); -static int dowait (int, struct job *); -static void waitonint(int); - - -/* - * We keep track of whether or not fd0 has been redirected. This is for - * background commands, where we want to redirect fd0 to /dev/null only - * if it hasn't already been redirected. -*/ -static int fd0_redirected = 0; - -/* Return true if fd 0 has already been redirected at least once. */ -static inline int -fd0_redirected_p () { - return fd0_redirected != 0; -} - -static void dupredirect (const union node *, int, int fd1dup); - -#ifdef JOBS -/* - * Turn job control on and off. - * - * Note: This code assumes that the third arg to ioctl is a character - * pointer, which is true on Berkeley systems but not System V. Since - * System V doesn't have job control yet, this isn't a problem now. - */ - - - -static void setjobctl(int enable) -{ -#ifdef OLD_TTY_DRIVER - int ldisc; -#endif - - if (enable == jobctl || rootshell == 0) - return; - if (enable) { - do { /* while we are in the background */ -#ifdef OLD_TTY_DRIVER - if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) { -#else - initialpgrp = tcgetpgrp(2); - if (initialpgrp < 0) { -#endif - out2str("sh: can't access tty; job control turned off\n"); - mflag = 0; - return; - } - if (initialpgrp == -1) - initialpgrp = getpgrp(); - else if (initialpgrp != getpgrp()) { - killpg(initialpgrp, SIGTTIN); - continue; - } - } while (0); -#ifdef OLD_TTY_DRIVER - if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) { - out2str("sh: need new tty driver to run job control; job control turned off\n"); - mflag = 0; - return; - } -#endif - setsignal(SIGTSTP); - setsignal(SIGTTOU); - setsignal(SIGTTIN); - setpgid(0, rootpid); -#ifdef OLD_TTY_DRIVER - ioctl(2, TIOCSPGRP, (char *)&rootpid); -#else - tcsetpgrp(2, rootpid); -#endif - } else { /* turning job control off */ - setpgid(0, initialpgrp); -#ifdef OLD_TTY_DRIVER - ioctl(2, TIOCSPGRP, (char *)&initialpgrp); -#else - tcsetpgrp(2, initialpgrp); -#endif - setsignal(SIGTSTP); - setsignal(SIGTTOU); - setsignal(SIGTTIN); - } - jobctl = enable; -} -#endif - - -#ifdef JOBS -static int -killcmd(argc, argv) - int argc; - char **argv; -{ - int signo = -1; - int list = 0; - int i; - pid_t pid; - struct job *jp; - - if (argc <= 1) { -usage: - error( -"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n" -"kill -l [exitstatus]" - ); - } - - if (*argv[1] == '-') { - signo = decode_signal(argv[1] + 1, 1); - if (signo < 0) { - int c; - - while ((c = nextopt("ls:")) != '\0') - switch (c) { - case 'l': - list = 1; - break; - case 's': - signo = decode_signal(optionarg, 1); - if (signo < 0) { - error( - "invalid signal number or name: %s", - optionarg - ); - } - break; -#ifdef DEBUG - default: - error( - "nextopt returned character code 0%o", c); -#endif - } - } else - argptr++; - } - - if (!list && signo < 0) - signo = SIGTERM; - - if ((signo < 0 || !*argptr) ^ list) { - goto usage; - } - - if (list) { - const char *name; - - if (!*argptr) { - out1str("0\n"); - for (i = 1; i < NSIG; i++) { - name = u_signal_names(0, &i, 1); - if(name) - printf(snlfmt, name); - } - return 0; - } - name = u_signal_names(*argptr, &signo, -1); - if (name) - printf(snlfmt, name); - else - error("invalid signal number or exit status: %s", - *argptr); - return 0; - } - - do { - if (**argptr == '%') { - jp = getjob(*argptr); - if (jp->jobctl == 0) - error("job %s not created under job control", - *argptr); - pid = -jp->ps[0].pid; - } else - pid = atoi(*argptr); - if (kill(pid, signo) != 0) - error("%s: %m", *argptr); - } while (*++argptr); - - return 0; -} - -static int -fgcmd(argc, argv) - int argc; - char **argv; -{ - struct job *jp; - int pgrp; - int status; - - jp = getjob(argv[1]); - if (jp->jobctl == 0) - error("job not created under job control"); - pgrp = jp->ps[0].pid; -#ifdef OLD_TTY_DRIVER - ioctl(2, TIOCSPGRP, (char *)&pgrp); -#else - tcsetpgrp(2, pgrp); -#endif - restartjob(jp); - INTOFF; - status = waitforjob(jp); - INTON; - return status; -} - - -static int -bgcmd(argc, argv) - int argc; - char **argv; -{ - struct job *jp; - - do { - jp = getjob(*++argv); - if (jp->jobctl == 0) - error("job not created under job control"); - restartjob(jp); - } while (--argc > 1); - return 0; -} - - -static void -restartjob(jp) - struct job *jp; -{ - struct procstat *ps; - int i; - - if (jp->state == JOBDONE) - return; - INTOFF; - killpg(jp->ps[0].pid, SIGCONT); - for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) { - if (WIFSTOPPED(ps->status)) { - ps->status = -1; - jp->state = 0; - } - } - INTON; -} -#endif - -static void showjobs(int change); - - -static int -jobscmd(argc, argv) - int argc; - char **argv; -{ - showjobs(0); - return 0; -} - - -/* - * Print a list of jobs. If "change" is nonzero, only print jobs whose - * statuses have changed since the last call to showjobs. - * - * If the shell is interrupted in the process of creating a job, the - * result may be a job structure containing zero processes. Such structures - * will be freed here. - */ - -static void -showjobs(change) - int change; -{ - int jobno; - int procno; - int i; - struct job *jp; - struct procstat *ps; - int col; - char s[64]; - - TRACE(("showjobs(%d) called\n", change)); - while (dowait(0, (struct job *)NULL) > 0); - for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) { - if (! jp->used) - continue; - if (jp->nprocs == 0) { - freejob(jp); - continue; - } - if (change && ! jp->changed) - continue; - procno = jp->nprocs; - for (ps = jp->ps ; ; ps++) { /* for each process */ - if (ps == jp->ps) - snprintf(s, 64, "[%d] %ld ", jobno, - (long)ps->pid); - else - snprintf(s, 64, " %ld ", - (long)ps->pid); - out1str(s); - col = strlen(s); - s[0] = '\0'; - if (ps->status == -1) { - /* don't print anything */ - } else if (WIFEXITED(ps->status)) { - snprintf(s, 64, "Exit %d", - WEXITSTATUS(ps->status)); - } else { -#ifdef JOBS - if (WIFSTOPPED(ps->status)) - i = WSTOPSIG(ps->status); - else /* WIFSIGNALED(ps->status) */ -#endif - i = WTERMSIG(ps->status); - if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F]) - strcpy(s, sys_siglist[i & 0x7F]); - else - snprintf(s, 64, "Signal %d", i & 0x7F); - if (WCOREDUMP(ps->status)) - strcat(s, " (core dumped)"); - } - out1str(s); - col += strlen(s); - printf( - "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ', - ps->cmd - ); - if (--procno <= 0) - break; - } - jp->changed = 0; - if (jp->state == JOBDONE) { - freejob(jp); - } - } -} - - -/* - * Mark a job structure as unused. - */ - -static void -freejob(struct job *jp) -{ - const struct procstat *ps; - int i; - - INTOFF; - for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) { - if (ps->cmd != nullstr) - ckfree(ps->cmd); - } - if (jp->ps != &jp->ps0) - ckfree(jp->ps); - jp->used = 0; -#ifdef JOBS - if (curjob == jp - jobtab + 1) - curjob = 0; -#endif - INTON; -} - - - -static int -waitcmd(argc, argv) - int argc; - char **argv; -{ - struct job *job; - int status, retval; - struct job *jp; - - if (--argc > 0) { -start: - job = getjob(*++argv); - } else { - job = NULL; - } - for (;;) { /* loop until process terminated or stopped */ - if (job != NULL) { - if (job->state) { - status = job->ps[job->nprocs - 1].status; - if (! iflag) - freejob(job); - if (--argc) { - goto start; - } - if (WIFEXITED(status)) - retval = WEXITSTATUS(status); -#ifdef JOBS - else if (WIFSTOPPED(status)) - retval = WSTOPSIG(status) + 128; -#endif - else { - /* XXX: limits number of signals */ - retval = WTERMSIG(status) + 128; - } - return retval; - } - } else { - for (jp = jobtab ; ; jp++) { - if (jp >= jobtab + njobs) { /* no running procs */ - return 0; - } - if (jp->used && jp->state == 0) - break; - } - } - if (dowait(2, 0) < 0 && errno == EINTR) { - return 129; - } - } -} - - - -/* - * Convert a job name to a job structure. - */ - -static struct job * -getjob(const char *name) -{ - int jobno; - struct job *jp; - int pid; - int i; - - if (name == NULL) { -#ifdef JOBS -currentjob: - if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0) - error("No current job"); - return &jobtab[jobno - 1]; -#else - error("No current job"); -#endif - } else if (name[0] == '%') { - if (is_digit(name[1])) { - jobno = number(name + 1); - if (jobno > 0 && jobno <= njobs - && jobtab[jobno - 1].used != 0) - return &jobtab[jobno - 1]; -#ifdef JOBS - } else if (name[1] == '%' && name[2] == '\0') { - goto currentjob; -#endif - } else { - struct job *found = NULL; - for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { - if (jp->used && jp->nprocs > 0 - && prefix(name + 1, jp->ps[0].cmd)) { - if (found) - error("%s: ambiguous", name); - found = jp; - } - } - if (found) - return found; - } - } else if (is_number(name, &pid)) { - for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { - if (jp->used && jp->nprocs > 0 - && jp->ps[jp->nprocs - 1].pid == pid) - return jp; - } - } - error("No such job: %s", name); - /* NOTREACHED */ -} - - - -/* - * Return a new job structure, - */ - -static struct job * -makejob(const union node *node, int nprocs) -{ - int i; - struct job *jp; - - for (i = njobs, jp = jobtab ; ; jp++) { - if (--i < 0) { - INTOFF; - if (njobs == 0) { - jobtab = ckmalloc(4 * sizeof jobtab[0]); - } else { - jp = ckmalloc((njobs + 4) * sizeof jobtab[0]); - memcpy(jp, jobtab, njobs * sizeof jp[0]); - /* Relocate `ps' pointers */ - for (i = 0; i < njobs; i++) - if (jp[i].ps == &jobtab[i].ps0) - jp[i].ps = &jp[i].ps0; - ckfree(jobtab); - jobtab = jp; - } - jp = jobtab + njobs; - for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0); - INTON; - break; - } - if (jp->used == 0) - break; - } - INTOFF; - jp->state = 0; - jp->used = 1; - jp->changed = 0; - jp->nprocs = 0; -#ifdef JOBS - jp->jobctl = jobctl; -#endif - if (nprocs > 1) { - jp->ps = ckmalloc(nprocs * sizeof (struct procstat)); - } else { - jp->ps = &jp->ps0; - } - INTON; - TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs, - jp - jobtab + 1)); - return jp; -} - - -/* - * Fork of a subshell. If we are doing job control, give the subshell its - * own process group. Jp is a job structure that the job is to be added to. - * N is the command that will be evaluated by the child. Both jp and n may - * be NULL. The mode parameter can be one of the following: - * FORK_FG - Fork off a foreground process. - * FORK_BG - Fork off a background process. - * FORK_NOJOB - Like FORK_FG, but don't give the process its own - * process group even if job control is on. - * - * When job control is turned off, background processes have their standard - * input redirected to /dev/null (except for the second and later processes - * in a pipeline). - */ - - - -static int -forkshell(struct job *jp, const union node *n, int mode) -{ - int pid; -#ifdef JOBS - int pgrp; -#endif - const char *devnull = _PATH_DEVNULL; - const char *nullerr = "Can't open %s"; - - TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n, - mode)); - INTOFF; - pid = fork(); - if (pid == -1) { - TRACE(("Fork failed, errno=%d\n", errno)); - INTON; - error("Cannot fork"); - } - if (pid == 0) { - struct job *p; - int wasroot; - int i; - - TRACE(("Child shell %d\n", getpid())); - wasroot = rootshell; - rootshell = 0; - closescript(); - INTON; - clear_traps(); -#ifdef JOBS - jobctl = 0; /* do job control only in root shell */ - if (wasroot && mode != FORK_NOJOB && mflag) { - if (jp == NULL || jp->nprocs == 0) - pgrp = getpid(); - else - pgrp = jp->ps[0].pid; - setpgid(0, pgrp); - if (mode == FORK_FG) { - /*** this causes superfluous TIOCSPGRPS ***/ -#ifdef OLD_TTY_DRIVER - if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0) - error("TIOCSPGRP failed, errno=%d", errno); -#else - if (tcsetpgrp(2, pgrp) < 0) - error("tcsetpgrp failed, errno=%d", errno); -#endif - } - setsignal(SIGTSTP); - setsignal(SIGTTOU); - } else if (mode == FORK_BG) { - ignoresig(SIGINT); - ignoresig(SIGQUIT); - if ((jp == NULL || jp->nprocs == 0) && - ! fd0_redirected_p ()) { - close(0); - if (open(devnull, O_RDONLY) != 0) - error(nullerr, devnull); - } - } -#else - if (mode == FORK_BG) { - ignoresig(SIGINT); - ignoresig(SIGQUIT); - if ((jp == NULL || jp->nprocs == 0) && - ! fd0_redirected_p ()) { - close(0); - if (open(devnull, O_RDONLY) != 0) - error(nullerr, devnull); - } - } -#endif - for (i = njobs, p = jobtab ; --i >= 0 ; p++) - if (p->used) - freejob(p); - if (wasroot && iflag) { - setsignal(SIGINT); - setsignal(SIGQUIT); - setsignal(SIGTERM); - } - return pid; - } -#ifdef JOBS - if (rootshell && mode != FORK_NOJOB && mflag) { - if (jp == NULL || jp->nprocs == 0) - pgrp = pid; - else - pgrp = jp->ps[0].pid; - setpgid(pid, pgrp); - } -#endif - if (mode == FORK_BG) - backgndpid = pid; /* set $! */ - if (jp) { - struct procstat *ps = &jp->ps[jp->nprocs++]; - ps->pid = pid; - ps->status = -1; - ps->cmd = nullstr; - if (iflag && rootshell && n) - ps->cmd = commandtext(n); - } - INTON; - TRACE(("In parent shell: child = %d\n", pid)); - return pid; -} - - - -/* - * Wait for job to finish. - * - * Under job control we have the problem that while a child process is - * running interrupts generated by the user are sent to the child but not - * to the shell. This means that an infinite loop started by an inter- - * active user may be hard to kill. With job control turned off, an - * interactive user may place an interactive program inside a loop. If - * the interactive program catches interrupts, the user doesn't want - * these interrupts to also abort the loop. The approach we take here - * is to have the shell ignore interrupt signals while waiting for a - * forground process to terminate, and then send itself an interrupt - * signal if the child process was terminated by an interrupt signal. - * Unfortunately, some programs want to do a bit of cleanup and then - * exit on interrupt; unless these processes terminate themselves by - * sending a signal to themselves (instead of calling exit) they will - * confuse this approach. - */ - -static int -waitforjob(struct job *jp) -{ -#ifdef JOBS - int mypgrp = getpgrp(); -#endif - int status; - int st; - struct sigaction act, oact; - - INTOFF; - intreceived = 0; -#ifdef JOBS - if (!jobctl) { -#else - if (!iflag) { -#endif - sigaction(SIGINT, 0, &act); - act.sa_handler = waitonint; - sigaction(SIGINT, &act, &oact); - } - TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1)); - while (jp->state == 0) { - dowait(1, jp); - } -#ifdef JOBS - if (!jobctl) { -#else - if (!iflag) { -#endif - sigaction(SIGINT, &oact, 0); - if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT); - } -#ifdef JOBS - if (jp->jobctl) { -#ifdef OLD_TTY_DRIVER - if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0) - error("TIOCSPGRP failed, errno=%d\n", errno); -#else - if (tcsetpgrp(2, mypgrp) < 0) - error("tcsetpgrp failed, errno=%d\n", errno); -#endif - } - if (jp->state == JOBSTOPPED) - curjob = jp - jobtab + 1; -#endif - status = jp->ps[jp->nprocs - 1].status; - /* convert to 8 bits */ - if (WIFEXITED(status)) - st = WEXITSTATUS(status); -#ifdef JOBS - else if (WIFSTOPPED(status)) - st = WSTOPSIG(status) + 128; -#endif - else - st = WTERMSIG(status) + 128; -#ifdef JOBS - if (jp->jobctl) { - /* - * This is truly gross. - * If we're doing job control, then we did a TIOCSPGRP which - * caused us (the shell) to no longer be in the controlling - * session -- so we wouldn't have seen any ^C/SIGINT. So, we - * intuit from the subprocess exit status whether a SIGINT - * occured, and if so interrupt ourselves. Yuck. - mycroft - */ - if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) - raise(SIGINT); - } - if (jp->state == JOBDONE) - -#endif - freejob(jp); - INTON; - return st; -} - - - -/* - * Wait for a process to terminate. - */ - -/* - * Do a wait system call. If job control is compiled in, we accept - * stopped processes. If block is zero, we return a value of zero - * rather than blocking. - * - * System V doesn't have a non-blocking wait system call. It does - * have a SIGCLD signal that is sent to a process when one of it's - * children dies. The obvious way to use SIGCLD would be to install - * a handler for SIGCLD which simply bumped a counter when a SIGCLD - * was received, and have waitproc bump another counter when it got - * the status of a process. Waitproc would then know that a wait - * system call would not block if the two counters were different. - * This approach doesn't work because if a process has children that - * have not been waited for, System V will send it a SIGCLD when it - * installs a signal handler for SIGCLD. What this means is that when - * a child exits, the shell will be sent SIGCLD signals continuously - * until is runs out of stack space, unless it does a wait call before - * restoring the signal handler. The code below takes advantage of - * this (mis)feature by installing a signal handler for SIGCLD and - * then checking to see whether it was called. If there are any - * children to be waited for, it will be. - * - */ - -static inline int -waitproc(int block, int *status) -{ - int flags; - - flags = 0; -#ifdef JOBS - if (jobctl) - flags |= WUNTRACED; -#endif - if (block == 0) - flags |= WNOHANG; - return wait3(status, flags, (struct rusage *)NULL); -} - -static int -dowait(int block, struct job *job) -{ - int pid; - int status; - struct procstat *sp; - struct job *jp; - struct job *thisjob; - int done; - int stopped; - int core; - int sig; - - TRACE(("dowait(%d) called\n", block)); - do { - pid = waitproc(block, &status); - TRACE(("wait returns %d, status=%d\n", pid, status)); - } while (!(block & 2) && pid == -1 && errno == EINTR); - if (pid <= 0) - return pid; - INTOFF; - thisjob = NULL; - for (jp = jobtab ; jp < jobtab + njobs ; jp++) { - if (jp->used) { - done = 1; - stopped = 1; - for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) { - if (sp->pid == -1) - continue; - if (sp->pid == pid) { - TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status)); - sp->status = status; - thisjob = jp; - } - if (sp->status == -1) - stopped = 0; - else if (WIFSTOPPED(sp->status)) - done = 0; - } - if (stopped) { /* stopped or done */ - int state = done? JOBDONE : JOBSTOPPED; - if (jp->state != state) { - TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state)); - jp->state = state; -#ifdef JOBS - if (done && curjob == jp - jobtab + 1) - curjob = 0; /* no current job */ -#endif - } - } - } - } - INTON; - if (! rootshell || ! iflag || (job && thisjob == job)) { - core = WCOREDUMP(status); -#ifdef JOBS - if (WIFSTOPPED(status)) sig = WSTOPSIG(status); - else -#endif - if (WIFEXITED(status)) sig = 0; - else sig = WTERMSIG(status); - - if (sig != 0 && sig != SIGINT && sig != SIGPIPE) { - if (thisjob != job) - out2fmt("%d: ", pid); -#ifdef JOBS - if (sig == SIGTSTP && rootshell && iflag) - out2fmt("%%%ld ", - (long)(job - jobtab + 1)); -#endif - if (sig < NSIG && sys_siglist[sig]) - out2str(sys_siglist[sig]); - else - out2fmt("Signal %d", sig); - if (core) - out2str(" - core dumped"); - out2c('\n'); - } else { - TRACE(("Not printing status: status=%d, sig=%d\n", - status, sig)); - } - } else { - TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job)); - if (thisjob) - thisjob->changed = 1; - } - return pid; -} - - - - -/* - * return 1 if there are stopped jobs, otherwise 0 - */ -static int -stoppedjobs(void) -{ - int jobno; - struct job *jp; - - if (job_warning) - return (0); - for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) { - if (jp->used == 0) - continue; - if (jp->state == JOBSTOPPED) { - out2str("You have stopped jobs.\n"); - job_warning = 2; - return (1); - } - } - - return (0); -} - -/* - * Return a string identifying a command (to be printed by the - * jobs command. - */ - -static char *cmdnextc; -static int cmdnleft; -#define MAXCMDTEXT 200 - -static void -cmdputs(const char *s) -{ - const char *p; - char *q; - char c; - int subtype = 0; - - if (cmdnleft <= 0) - return; - p = s; - q = cmdnextc; - while ((c = *p++) != '\0') { - if (c == CTLESC) - *q++ = *p++; - else if (c == CTLVAR) { - *q++ = '$'; - if (--cmdnleft > 0) - *q++ = '{'; - subtype = *p++; - } else if (c == '=' && subtype != 0) { - *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL]; - subtype = 0; - } else if (c == CTLENDVAR) { - *q++ = '}'; - } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) - cmdnleft++; /* ignore it */ - else - *q++ = c; - if (--cmdnleft <= 0) { - *q++ = '.'; - *q++ = '.'; - *q++ = '.'; - break; - } - } - cmdnextc = q; -} - - -static void -cmdtxt(const union node *n) -{ - union node *np; - struct nodelist *lp; - const char *p; - int i; - char s[2]; - - if (n == NULL) - return; - switch (n->type) { - case NSEMI: - cmdtxt(n->nbinary.ch1); - cmdputs("; "); - cmdtxt(n->nbinary.ch2); - break; - case NAND: - cmdtxt(n->nbinary.ch1); - cmdputs(" && "); - cmdtxt(n->nbinary.ch2); - break; - case NOR: - cmdtxt(n->nbinary.ch1); - cmdputs(" || "); - cmdtxt(n->nbinary.ch2); - break; - case NPIPE: - for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { - cmdtxt(lp->n); - if (lp->next) - cmdputs(" | "); - } - break; - case NSUBSHELL: - cmdputs("("); - cmdtxt(n->nredir.n); - cmdputs(")"); - break; - case NREDIR: - case NBACKGND: - cmdtxt(n->nredir.n); - break; - case NIF: - cmdputs("if "); - cmdtxt(n->nif.test); - cmdputs("; then "); - cmdtxt(n->nif.ifpart); - cmdputs("..."); - break; - case NWHILE: - cmdputs("while "); - goto until; - case NUNTIL: - cmdputs("until "); -until: - cmdtxt(n->nbinary.ch1); - cmdputs("; do "); - cmdtxt(n->nbinary.ch2); - cmdputs("; done"); - break; - case NFOR: - cmdputs("for "); - cmdputs(n->nfor.var); - cmdputs(" in ..."); - break; - case NCASE: - cmdputs("case "); - cmdputs(n->ncase.expr->narg.text); - cmdputs(" in ..."); - break; - case NDEFUN: - cmdputs(n->narg.text); - cmdputs("() ..."); - break; - case NCMD: - for (np = n->ncmd.args ; np ; np = np->narg.next) { - cmdtxt(np); - if (np->narg.next) - cmdputs(spcstr); - } - for (np = n->ncmd.redirect ; np ; np = np->nfile.next) { - cmdputs(spcstr); - cmdtxt(np); - } - break; - case NARG: - cmdputs(n->narg.text); - break; - case NTO: - p = ">"; i = 1; goto redir; - case NAPPEND: - p = ">>"; i = 1; goto redir; - case NTOFD: - p = ">&"; i = 1; goto redir; - case NTOOV: - p = ">|"; i = 1; goto redir; - case NFROM: - p = "<"; i = 0; goto redir; - case NFROMFD: - p = "<&"; i = 0; goto redir; - case NFROMTO: - p = "<>"; i = 0; goto redir; -redir: - if (n->nfile.fd != i) { - s[0] = n->nfile.fd + '0'; - s[1] = '\0'; - cmdputs(s); - } - cmdputs(p); - if (n->type == NTOFD || n->type == NFROMFD) { - s[0] = n->ndup.dupfd + '0'; - s[1] = '\0'; - cmdputs(s); - } else { - cmdtxt(n->nfile.fname); - } - break; - case NHERE: - case NXHERE: - cmdputs("<<..."); - break; - default: - cmdputs("???"); - break; - } -} - - -static char * -commandtext(const union node *n) -{ - char *name; - - cmdnextc = name = ckmalloc(MAXCMDTEXT); - cmdnleft = MAXCMDTEXT - 4; - cmdtxt(n); - *cmdnextc = '\0'; - return name; -} - - -static void waitonint(int sig) { - intreceived = 1; - return; -} -/* - * Routines to check for mail. (Perhaps make part of main.c?) - */ - - -#define MAXMBOXES 10 - - -static int nmboxes; /* number of mailboxes */ -static time_t mailtime[MAXMBOXES]; /* times of mailboxes */ - - - -/* - * Print appropriate message(s) if mail has arrived. If the argument is - * nozero, then the value of MAIL has changed, so we just update the - * values. - */ - -static void -chkmail(int silent) -{ - int i; - const char *mpath; - char *p; - char *q; - struct stackmark smark; - struct stat statb; - - if (silent) - nmboxes = 10; - if (nmboxes == 0) - return; - setstackmark(&smark); - mpath = mpathset()? mpathval() : mailval(); - for (i = 0 ; i < nmboxes ; i++) { - p = padvance(&mpath, nullstr); - if (p == NULL) - break; - if (*p == '\0') - continue; - for (q = p ; *q ; q++); -#ifdef DEBUG - if (q[-1] != '/') - abort(); -#endif - q[-1] = '\0'; /* delete trailing '/' */ - if (stat(p, &statb) < 0) - statb.st_size = 0; - if (statb.st_size > mailtime[i] && ! silent) { - out2fmt(snlfmt, - pathopt? pathopt : "you have mail"); - } - mailtime[i] = statb.st_size; - } - nmboxes = i; - popstackmark(&smark); -} - -#define PROFILE 0 - -#if PROFILE -static short profile_buf[16384]; -extern int etext(); -#endif - -static void read_profile (const char *); -static void cmdloop (int); -static void options (int); -static void setoption (int, int); -static void procargs (int, char **); - - -/* - * Main routine. We initialize things, parse the arguments, execute - * profiles if we're a login shell, and then call cmdloop to execute - * commands. The setjmp call sets up the location to jump to when an - * exception occurs. When an exception occurs the variable "state" - * is used to figure out how far we had gotten. - */ - -int -ash_main(argc, argv) - int argc; - char **argv; -{ - struct jmploc jmploc; - struct stackmark smark; - volatile int state; - const char *shinit; - - BLTINCMD = find_builtin("builtin"); - EXECCMD = find_builtin("exec"); - EVALCMD = find_builtin("eval"); - -#ifndef BB_FEATURE_SH_FANCY_PROMPT - unsetenv("PS1"); - unsetenv("PS2"); -#endif - -#if PROFILE - monitor(4, etext, profile_buf, sizeof profile_buf, 50); -#endif -#if defined(linux) || defined(__GNU__) - signal(SIGCHLD, SIG_DFL); -#endif - state = 0; - if (setjmp(jmploc.loc)) { - INTOFF; - /* - * When a shell procedure is executed, we raise the - * exception EXSHELLPROC to clean up before executing - * the shell procedure. - */ - switch (exception) { - case EXSHELLPROC: - rootpid = getpid(); - rootshell = 1; - minusc = NULL; - state = 3; - break; - - case EXEXEC: - exitstatus = exerrno; - break; - - case EXERROR: - exitstatus = 2; - break; - - default: - break; - } - - if (exception != EXSHELLPROC) { - if (state == 0 || iflag == 0 || ! rootshell) - exitshell(exitstatus); - } - reset(); - if (exception == EXINT) { - out2c('\n'); - } - popstackmark(&smark); - FORCEINTON; /* enable interrupts */ - if (state == 1) - goto state1; - else if (state == 2) - goto state2; - else if (state == 3) - goto state3; - else - goto state4; - } - handler = &jmploc; -#ifdef DEBUG - opentrace(); - trputs("Shell args: "); trargs(argv); -#endif - rootpid = getpid(); - rootshell = 1; - init(); - setstackmark(&smark); - procargs(argc, argv); - if (argv[0] && argv[0][0] == '-') { - state = 1; - read_profile("/etc/profile"); -state1: - state = 2; - read_profile(".profile"); - } -state2: - state = 3; -#ifndef linux - if (getuid() == geteuid() && getgid() == getegid()) { -#endif - if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { - state = 3; - read_profile(shinit); - } -#ifndef linux - } -#endif -state3: - state = 4; - if (sflag == 0 || minusc) { - static int sigs[] = { - SIGINT, SIGQUIT, SIGHUP, -#ifdef SIGTSTP - SIGTSTP, -#endif - SIGPIPE - }; -#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0])) - int i; - - for (i = 0; i < SIGSSIZE; i++) - setsignal(sigs[i]); - } - - if (minusc) - evalstring(minusc, 0); - - if (sflag || minusc == NULL) { -state4: /* XXX ??? - why isn't this before the "if" statement */ - cmdloop(1); - } -#if PROFILE - monitor(0); -#endif - exitshell(exitstatus); - /* NOTREACHED */ -} - - -/* - * Read and execute commands. "Top" is nonzero for the top level command - * loop; it turns on prompting if the shell is interactive. - */ - -static void -cmdloop(int top) -{ - union node *n; - struct stackmark smark; - int inter; - int numeof = 0; - - TRACE(("cmdloop(%d) called\n", top)); - setstackmark(&smark); - for (;;) { - if (pendingsigs) - dotrap(); - inter = 0; - if (iflag && top) { - inter++; - showjobs(1); - chkmail(0); - flushall(); - } - n = parsecmd(inter); - /* showtree(n); DEBUG */ - if (n == NEOF) { - if (!top || numeof >= 50) - break; - if (!stoppedjobs()) { - if (!Iflag) - break; - out2str("\nUse \"exit\" to leave shell.\n"); - } - numeof++; - } else if (n != NULL && nflag == 0) { - job_warning = (job_warning == 2) ? 1 : 0; - numeof = 0; - evaltree(n, 0); - } - popstackmark(&smark); - setstackmark(&smark); - if (evalskip == SKIPFILE) { - evalskip = 0; - break; - } - } - popstackmark(&smark); -} - - - -/* - * Read /etc/profile or .profile. Return on error. - */ - -static void -read_profile(name) - const char *name; -{ - int fd; - int xflag_set = 0; - int vflag_set = 0; - - INTOFF; - if ((fd = open(name, O_RDONLY)) >= 0) - setinputfd(fd, 1); - INTON; - if (fd < 0) - return; - /* -q turns off -x and -v just when executing init files */ - if (qflag) { - if (xflag) - xflag = 0, xflag_set = 1; - if (vflag) - vflag = 0, vflag_set = 1; - } - cmdloop(0); - if (qflag) { - if (xflag_set) - xflag = 1; - if (vflag_set) - vflag = 1; - } - popfile(); -} - - - -/* - * Read a file containing shell functions. - */ - -static void -readcmdfile(const char *name) -{ - int fd; - - INTOFF; - if ((fd = open(name, O_RDONLY)) >= 0) - setinputfd(fd, 1); - else - error("Can't open %s", name); - INTON; - cmdloop(0); - popfile(); -} - - - -/* - * Take commands from a file. To be compatable we should do a path - * search for the file, which is necessary to find sub-commands. - */ - - -static inline char * -find_dot_file(mybasename) - char *mybasename; -{ - char *fullname; - const char *path = pathval(); - struct stat statb; - - /* don't try this for absolute or relative paths */ - if (strchr(mybasename, '/')) - return mybasename; - - while ((fullname = padvance(&path, mybasename)) != NULL) { - if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { - /* - * Don't bother freeing here, since it will - * be freed by the caller. - */ - return fullname; - } - stunalloc(fullname); - } - - /* not found in the PATH */ - error("%s: not found", mybasename); - /* NOTREACHED */ -} - -static int -dotcmd(argc, argv) - int argc; - char **argv; -{ - struct strlist *sp; - exitstatus = 0; - - for (sp = cmdenviron; sp ; sp = sp->next) - setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED); - - if (argc >= 2) { /* That's what SVR2 does */ - char *fullname; - struct stackmark smark; - - setstackmark(&smark); - fullname = find_dot_file(argv[1]); - setinputfile(fullname, 1); - commandname = fullname; - cmdloop(0); - popfile(); - popstackmark(&smark); - } - return exitstatus; -} - - -static int -exitcmd(argc, argv) - int argc; - char **argv; -{ - if (stoppedjobs()) - return 0; - if (argc > 1) - exitstatus = number(argv[1]); - else - exitstatus = oexitstatus; - exitshell(exitstatus); - /* NOTREACHED */ -} - -static pointer -stalloc(int nbytes) -{ - char *p; - - nbytes = ALIGN(nbytes); - if (nbytes > stacknleft) { - int blocksize; - struct stack_block *sp; - - blocksize = nbytes; - if (blocksize < MINSIZE) - blocksize = MINSIZE; - INTOFF; - sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize); - sp->prev = stackp; - stacknxt = sp->space; - stacknleft = blocksize; - stackp = sp; - INTON; - } - p = stacknxt; - stacknxt += nbytes; - stacknleft -= nbytes; - return p; -} - - -static void -stunalloc(pointer p) -{ -#ifdef DEBUG - if (p == NULL) { /*DEBUG */ - write(2, "stunalloc\n", 10); - abort(); - } -#endif - if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) { - p = stackp->space; - } - stacknleft += stacknxt - (char *)p; - stacknxt = p; -} - - -static void -setstackmark(struct stackmark *mark) -{ - mark->stackp = stackp; - mark->stacknxt = stacknxt; - mark->stacknleft = stacknleft; - mark->marknext = markp; - markp = mark; -} - - -static void -popstackmark(struct stackmark *mark) -{ - struct stack_block *sp; - - INTOFF; - markp = mark->marknext; - while (stackp != mark->stackp) { - sp = stackp; - stackp = sp->prev; - ckfree(sp); - } - stacknxt = mark->stacknxt; - stacknleft = mark->stacknleft; - INTON; -} - - -/* - * When the parser reads in a string, it wants to stick the string on the - * stack and only adjust the stack pointer when it knows how big the - * string is. Stackblock (defined in stack.h) returns a pointer to a block - * of space on top of the stack and stackblocklen returns the length of - * this block. Growstackblock will grow this space by at least one byte, - * possibly moving it (like realloc). Grabstackblock actually allocates the - * part of the block that has been used. - */ - -static void -growstackblock(void) { - char *p; - int newlen = ALIGN(stacknleft * 2 + 100); - char *oldspace = stacknxt; - int oldlen = stacknleft; - struct stack_block *sp; - struct stack_block *oldstackp; - - if (stacknxt == stackp->space && stackp != &stackbase) { - INTOFF; - oldstackp = stackp; - sp = stackp; - stackp = sp->prev; - sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen); - sp->prev = stackp; - stackp = sp; - stacknxt = sp->space; - stacknleft = newlen; - { - /* Stack marks pointing to the start of the old block - * must be relocated to point to the new block - */ - struct stackmark *xmark; - xmark = markp; - while (xmark != NULL && xmark->stackp == oldstackp) { - xmark->stackp = stackp; - xmark->stacknxt = stacknxt; - xmark->stacknleft = stacknleft; - xmark = xmark->marknext; - } - } - INTON; - } else { - p = stalloc(newlen); - memcpy(p, oldspace, oldlen); - stacknxt = p; /* free the space */ - stacknleft += newlen; /* we just allocated */ - } -} - - - -static inline void -grabstackblock(int len) -{ - len = ALIGN(len); - stacknxt += len; - stacknleft -= len; -} - - - -/* - * The following routines are somewhat easier to use that the above. - * The user declares a variable of type STACKSTR, which may be declared - * to be a register. The macro STARTSTACKSTR initializes things. Then - * the user uses the macro STPUTC to add characters to the string. In - * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is - * grown as necessary. When the user is done, she can just leave the - * string there and refer to it using stackblock(). Or she can allocate - * the space for it using grabstackstr(). If it is necessary to allow - * someone else to use the stack temporarily and then continue to grow - * the string, the user should use grabstack to allocate the space, and - * then call ungrabstr(p) to return to the previous mode of operation. - * - * USTPUTC is like STPUTC except that it doesn't check for overflow. - * CHECKSTACKSPACE can be called before USTPUTC to ensure that there - * is space for at least one character. - */ - - -static char * -growstackstr(void) { - int len = stackblocksize(); - if (herefd >= 0 && len >= 1024) { - xwrite(herefd, stackblock(), len); - sstrnleft = len - 1; - return stackblock(); - } - growstackblock(); - sstrnleft = stackblocksize() - len - 1; - return stackblock() + len; -} - - -/* - * Called from CHECKSTRSPACE. - */ - -static char * -makestrspace(size_t newlen) { - int len = stackblocksize() - sstrnleft; - do { - growstackblock(); - sstrnleft = stackblocksize() - len; - } while (sstrnleft < newlen); - return stackblock() + len; -} - - - -static void -ungrabstackstr(char *s, char *p) -{ - stacknleft += stacknxt - s; - stacknxt = s; - sstrnleft = stacknleft - (p - s); -} -/* - * Miscelaneous builtins. - */ - - -#undef rflag - -//#ifdef __GLIBC__ -static mode_t getmode(const void *, mode_t); -static void *setmode(const char *); -//#endif - -#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 -typedef long rlim_t; -#endif - - - -/* - * The read builtin. The -e option causes backslashes to escape the - * following character. - * - * This uses unbuffered input, which may be avoidable in some cases. - */ - -static int -readcmd(argc, argv) - int argc; - char **argv; -{ - char **ap; - int backslash; - char c; - int rflag; - char *prompt; - const char *ifs; - char *p; - int startword; - int status; - int i; - - rflag = 0; - prompt = NULL; - while ((i = nextopt("p:r")) != '\0') { - if (i == 'p') - prompt = optionarg; - else - rflag = 1; - } - if (prompt && isatty(0)) { - putprompt(prompt); - flushall(); - } - if (*(ap = argptr) == NULL) - error("arg count"); - if ((ifs = bltinlookup("IFS")) == NULL) - ifs = defifs; - status = 0; - startword = 1; - backslash = 0; - STARTSTACKSTR(p); - for (;;) { - if (read(0, &c, 1) != 1) { - status = 1; - break; - } - if (c == '\0') - continue; - if (backslash) { - backslash = 0; - if (c != '\n') - STPUTC(c, p); - continue; - } - if (!rflag && c == '\\') { - backslash++; - continue; - } - if (c == '\n') - break; - if (startword && *ifs == ' ' && strchr(ifs, c)) { - continue; - } - startword = 0; - if (backslash && c == '\\') { - if (read(0, &c, 1) != 1) { - status = 1; - break; - } - STPUTC(c, p); - } else if (ap[1] != NULL && strchr(ifs, c) != NULL) { - STACKSTRNUL(p); - setvar(*ap, stackblock(), 0); - ap++; - startword = 1; - STARTSTACKSTR(p); - } else { - STPUTC(c, p); - } - } - STACKSTRNUL(p); - /* Remove trailing blanks */ - while (stackblock() <= --p && strchr(ifs, *p) != NULL) - *p = '\0'; - setvar(*ap, stackblock(), 0); - while (*++ap != NULL) - setvar(*ap, nullstr, 0); - return status; -} - - - -static int -umaskcmd(argc, argv) - int argc; - char **argv; -{ - char *ap; - int mask; - int i; - int symbolic_mode = 0; - - while (nextopt("S") != '\0') { - symbolic_mode = 1; - } - - INTOFF; - mask = umask(0); - umask(mask); - INTON; - - if ((ap = *argptr) == NULL) { - if (symbolic_mode) { - char u[4], g[4], o[4]; - - i = 0; - if ((mask & S_IRUSR) == 0) - u[i++] = 'r'; - if ((mask & S_IWUSR) == 0) - u[i++] = 'w'; - if ((mask & S_IXUSR) == 0) - u[i++] = 'x'; - u[i] = '\0'; - - i = 0; - if ((mask & S_IRGRP) == 0) - g[i++] = 'r'; - if ((mask & S_IWGRP) == 0) - g[i++] = 'w'; - if ((mask & S_IXGRP) == 0) - g[i++] = 'x'; - g[i] = '\0'; - - i = 0; - if ((mask & S_IROTH) == 0) - o[i++] = 'r'; - if ((mask & S_IWOTH) == 0) - o[i++] = 'w'; - if ((mask & S_IXOTH) == 0) - o[i++] = 'x'; - o[i] = '\0'; - - printf("u=%s,g=%s,o=%s\n", u, g, o); - } else { - printf("%.4o\n", mask); - } - } else { - if (is_digit((unsigned char)*ap)) { - mask = 0; - do { - if (*ap >= '8' || *ap < '0') - error("Illegal number: %s", argv[1]); - mask = (mask << 3) + (*ap - '0'); - } while (*++ap != '\0'); - umask(mask); - } else { - void *set; - - INTOFF; - if ((set = setmode(ap)) != 0) { - mask = getmode(set, ~mask & 0777); - ckfree(set); - } - INTON; - if (!set) - error("Illegal mode: %s", ap); - - umask(~mask & 0777); - } - } - return 0; -} - -/* - * ulimit builtin - * - * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and - * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with - * ash by J.T. Conklin. - * - * Public domain. - */ - -struct limits { - const char *name; - int cmd; - int factor; /* multiply by to get rlim_{cur,max} values */ - char option; -}; - -static const struct limits limits[] = { -#ifdef RLIMIT_CPU - { "time(seconds)", RLIMIT_CPU, 1, 't' }, -#endif -#ifdef RLIMIT_FSIZE - { "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, -#endif -#ifdef RLIMIT_DATA - { "data(kbytes)", RLIMIT_DATA, 1024, 'd' }, -#endif -#ifdef RLIMIT_STACK - { "stack(kbytes)", RLIMIT_STACK, 1024, 's' }, -#endif -#ifdef RLIMIT_CORE - { "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, -#endif -#ifdef RLIMIT_RSS - { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' }, -#endif -#ifdef RLIMIT_MEMLOCK - { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, -#endif -#ifdef RLIMIT_NPROC - { "process(processes)", RLIMIT_NPROC, 1, 'p' }, -#endif -#ifdef RLIMIT_NOFILE - { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' }, -#endif -#ifdef RLIMIT_VMEM - { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' }, -#endif -#ifdef RLIMIT_SWAP - { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' }, -#endif - { (char *) 0, 0, 0, '\0' } -}; - -static int -ulimitcmd(argc, argv) - int argc; - char **argv; -{ - int c; - rlim_t val = 0; - enum { SOFT = 0x1, HARD = 0x2 } - how = SOFT | HARD; - const struct limits *l; - int set, all = 0; - int optc, what; - struct rlimit limit; - - what = 'f'; - while ((optc = nextopt("HSatfdsmcnpl")) != '\0') - switch (optc) { - case 'H': - how = HARD; - break; - case 'S': - how = SOFT; - break; - case 'a': - all = 1; - break; - default: - what = optc; - } - - for (l = limits; l->name && l->option != what; l++) - ; - if (!l->name) - error("internal error (%c)", what); - - set = *argptr ? 1 : 0; - if (set) { - char *p = *argptr; - - if (all || argptr[1]) - error("too many arguments"); - if (strcmp(p, "unlimited") == 0) - val = RLIM_INFINITY; - else { - val = (rlim_t) 0; - - while ((c = *p++) >= '0' && c <= '9') - { - val = (val * 10) + (long)(c - '0'); - if (val < (rlim_t) 0) - break; - } - if (c) - error("bad number"); - val *= l->factor; - } - } - if (all) { - for (l = limits; l->name; l++) { - getrlimit(l->cmd, &limit); - if (how & SOFT) - val = limit.rlim_cur; - else if (how & HARD) - val = limit.rlim_max; - - printf("%-20s ", l->name); - if (val == RLIM_INFINITY) - printf("unlimited\n"); - else - { - val /= l->factor; - printf("%lld\n", (long long) val); - } - } - return 0; - } - - getrlimit(l->cmd, &limit); - if (set) { - if (how & HARD) - limit.rlim_max = val; - if (how & SOFT) - limit.rlim_cur = val; - if (setrlimit(l->cmd, &limit) < 0) - error("error setting limit (%m)"); - } else { - if (how & SOFT) - val = limit.rlim_cur; - else if (how & HARD) - val = limit.rlim_max; - - if (val == RLIM_INFINITY) - printf("unlimited\n"); - else - { - val /= l->factor; - printf("%lld\n", (long long) val); - } - } - return 0; -} -/* - * prefix -- see if pfx is a prefix of string. - */ - -static int -prefix(char const *pfx, char const *string) -{ - while (*pfx) { - if (*pfx++ != *string++) - return 0; - } - return 1; -} - -/* - * Return true if s is a string of digits, and save munber in intptr - * nagative is bad - */ - -static int -is_number(const char *p, int *intptr) -{ - int ret = 0; - - do { - if (! is_digit(*p)) - return 0; - ret *= 10; - ret += digit_val(*p); - p++; - } while (*p != '\0'); - - *intptr = ret; - return 1; -} - -/* - * Convert a string of digits to an integer, printing an error message on - * failure. - */ - -static int -number(const char *s) -{ - int i; - if (! is_number(s, &i)) - error("Illegal number: %s", s); - return i; -} - -/* - * Produce a possibly single quoted string suitable as input to the shell. - * The return string is allocated on the stack. - */ - -static char * -single_quote(const char *s) { - char *p; - - STARTSTACKSTR(p); - - do { - char *q = p; - size_t len1, len1p, len2, len2p; - - len1 = strcspn(s, "'"); - len2 = strspn(s + len1, "'"); - - len1p = len1 ? len1 + 2 : len1; - switch (len2) { - case 0: - len2p = 0; - break; - case 1: - len2p = 2; - break; - default: - len2p = len2 + 2; - } - - CHECKSTRSPACE(len1p + len2p + 1, p); - - if (len1) { - *p = '\''; - q = p + 1 + len1; - memcpy(p + 1, s, len1); - *q++ = '\''; - s += len1; - } - - switch (len2) { - case 0: - break; - case 1: - *q++ = '\\'; - *q = '\''; - s++; - break; - default: - *q = '"'; - q += 1 + len2; - memcpy(q + 1, s, len2); - *q = '"'; - s += len2; - } - - STADJUST(len1p + len2p, p); - } while (*s); - - USTPUTC(0, p); - - return grabstackstr(p); -} - -/* - * Like strdup but works with the ash stack. - */ - -static char * -sstrdup(const char *p) -{ - size_t len = strlen(p) + 1; - return memcpy(stalloc(len), p, len); -} - - -/* - * Routine for dealing with parsed shell commands. - */ - - -static void sizenodelist (const struct nodelist *); -static struct nodelist *copynodelist (const struct nodelist *); -static char *nodesavestr (const char *); - -static void -calcsize(const union node *n) -{ - if (n == NULL) - return; - funcblocksize += nodesize[n->type]; - switch (n->type) { - case NSEMI: - case NAND: - case NOR: - case NWHILE: - case NUNTIL: - calcsize(n->nbinary.ch2); - calcsize(n->nbinary.ch1); - break; - case NCMD: - calcsize(n->ncmd.redirect); - calcsize(n->ncmd.args); - calcsize(n->ncmd.assign); - break; - case NPIPE: - sizenodelist(n->npipe.cmdlist); - break; - case NREDIR: - case NBACKGND: - case NSUBSHELL: - calcsize(n->nredir.redirect); - calcsize(n->nredir.n); - break; - case NIF: - calcsize(n->nif.elsepart); - calcsize(n->nif.ifpart); - calcsize(n->nif.test); - break; - case NFOR: - funcstringsize += strlen(n->nfor.var) + 1; - calcsize(n->nfor.body); - calcsize(n->nfor.args); - break; - case NCASE: - calcsize(n->ncase.cases); - calcsize(n->ncase.expr); - break; - case NCLIST: - calcsize(n->nclist.body); - calcsize(n->nclist.pattern); - calcsize(n->nclist.next); - break; - case NDEFUN: - case NARG: - sizenodelist(n->narg.backquote); - funcstringsize += strlen(n->narg.text) + 1; - calcsize(n->narg.next); - break; - case NTO: - case NFROM: - case NFROMTO: - case NAPPEND: - case NTOOV: - calcsize(n->nfile.fname); - calcsize(n->nfile.next); - break; - case NTOFD: - case NFROMFD: - calcsize(n->ndup.vname); - calcsize(n->ndup.next); - break; - case NHERE: - case NXHERE: - calcsize(n->nhere.doc); - calcsize(n->nhere.next); - break; - case NNOT: - calcsize(n->nnot.com); - break; - }; -} - -static void -sizenodelist(const struct nodelist *lp) -{ - while (lp) { - funcblocksize += ALIGN(sizeof(struct nodelist)); - calcsize(lp->n); - lp = lp->next; - } -} - - -static union node * -copynode(const union node *n) -{ - union node *new; - - if (n == NULL) - return NULL; - new = funcblock; - funcblock = (char *) funcblock + nodesize[n->type]; - switch (n->type) { - case NSEMI: - case NAND: - case NOR: - case NWHILE: - case NUNTIL: - new->nbinary.ch2 = copynode(n->nbinary.ch2); - new->nbinary.ch1 = copynode(n->nbinary.ch1); - break; - case NCMD: - new->ncmd.redirect = copynode(n->ncmd.redirect); - new->ncmd.args = copynode(n->ncmd.args); - new->ncmd.assign = copynode(n->ncmd.assign); - new->ncmd.backgnd = n->ncmd.backgnd; - break; - case NPIPE: - new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); - new->npipe.backgnd = n->npipe.backgnd; - break; - case NREDIR: - case NBACKGND: - case NSUBSHELL: - new->nredir.redirect = copynode(n->nredir.redirect); - new->nredir.n = copynode(n->nredir.n); - break; - case NIF: - new->nif.elsepart = copynode(n->nif.elsepart); - new->nif.ifpart = copynode(n->nif.ifpart); - new->nif.test = copynode(n->nif.test); - break; - case NFOR: - new->nfor.var = nodesavestr(n->nfor.var); - new->nfor.body = copynode(n->nfor.body); - new->nfor.args = copynode(n->nfor.args); - break; - case NCASE: - new->ncase.cases = copynode(n->ncase.cases); - new->ncase.expr = copynode(n->ncase.expr); - break; - case NCLIST: - new->nclist.body = copynode(n->nclist.body); - new->nclist.pattern = copynode(n->nclist.pattern); - new->nclist.next = copynode(n->nclist.next); - break; - case NDEFUN: - case NARG: - new->narg.backquote = copynodelist(n->narg.backquote); - new->narg.text = nodesavestr(n->narg.text); - new->narg.next = copynode(n->narg.next); - break; - case NTO: - case NFROM: - case NFROMTO: - case NAPPEND: - case NTOOV: - new->nfile.fname = copynode(n->nfile.fname); - new->nfile.fd = n->nfile.fd; - new->nfile.next = copynode(n->nfile.next); - break; - case NTOFD: - case NFROMFD: - new->ndup.vname = copynode(n->ndup.vname); - new->ndup.dupfd = n->ndup.dupfd; - new->ndup.fd = n->ndup.fd; - new->ndup.next = copynode(n->ndup.next); - break; - case NHERE: - case NXHERE: - new->nhere.doc = copynode(n->nhere.doc); - new->nhere.fd = n->nhere.fd; - new->nhere.next = copynode(n->nhere.next); - break; - case NNOT: - new->nnot.com = copynode(n->nnot.com); - break; - }; - new->type = n->type; - return new; -} - - -static struct nodelist * -copynodelist(const struct nodelist *lp) -{ - struct nodelist *start; - struct nodelist **lpp; - - lpp = &start; - while (lp) { - *lpp = funcblock; - funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist)); - (*lpp)->n = copynode(lp->n); - lp = lp->next; - lpp = &(*lpp)->next; - } - *lpp = NULL; - return start; -} - - -static char * -nodesavestr(const char *s) -{ - const char *p = s; - char *q = funcstring; - char *rtn = funcstring; - - while ((*q++ = *p++) != '\0') - continue; - funcstring = q; - return rtn; -} - -#ifdef ASH_GETOPTS -static int getopts (char *, char *, char **, int *, int *); -#endif - - -/* - * Process the shell command line arguments. - */ - -static void -procargs(argc, argv) - int argc; - char **argv; -{ - int i; - - argptr = argv; - if (argc > 0) - argptr++; - for (i = 0; i < NOPTS; i++) - optent_val(i) = 2; - options(1); - if (*argptr == NULL && minusc == NULL) - sflag = 1; - if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) - iflag = 1; - if (mflag == 2) - mflag = iflag; - for (i = 0; i < NOPTS; i++) - if (optent_val(i) == 2) - optent_val(i) = 0; - arg0 = argv[0]; - if (sflag == 0 && minusc == NULL) { - commandname = argv[0]; - arg0 = *argptr++; - setinputfile(arg0, 0); - commandname = arg0; - } - /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ - if (argptr && minusc && *argptr) - arg0 = *argptr++; - - shellparam.p = argptr; - shellparam.optind = 1; - shellparam.optoff = -1; - /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ - while (*argptr) { - shellparam.nparam++; - argptr++; - } - optschanged(); -} - - - -/* - * Process shell options. The global variable argptr contains a pointer - * to the argument list; we advance it past the options. - */ - -static inline void -minus_o(const char *name, int val) -{ - int i; - - if (name == NULL) { - out1str("Current option settings\n"); - for (i = 0; i < NOPTS; i++) - printf("%-16s%s\n", optent_name(optlist[i]), - optent_val(i) ? "on" : "off"); - } else { - for (i = 0; i < NOPTS; i++) - if (equal(name, optent_name(optlist[i]))) { - setoption(optent_letter(optlist[i]), val); - return; - } - error("Illegal option -o %s", name); - } -} - - -static void -options(int cmdline) -{ - char *p; - int val; - int c; - - if (cmdline) - minusc = NULL; - while ((p = *argptr) != NULL) { - argptr++; - if ((c = *p++) == '-') { - val = 1; - if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { - if (!cmdline) { - /* "-" means turn off -x and -v */ - if (p[0] == '\0') - xflag = vflag = 0; - /* "--" means reset params */ - else if (*argptr == NULL) - setparam(argptr); - } - break; /* "-" or "--" terminates options */ - } - } else if (c == '+') { - val = 0; - } else { - argptr--; - break; - } - while ((c = *p++) != '\0') { - if (c == 'c' && cmdline) { - char *q; -#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ - if (*p == '\0') -#endif - q = *argptr++; - if (q == NULL || minusc != NULL) - error("Bad -c option"); - minusc = q; -#ifdef NOHACK - break; -#endif - } else if (c == 'o') { - minus_o(*argptr, val); - if (*argptr) - argptr++; - } else { - setoption(c, val); - } - } - } -} - - -static void -setoption(int flag, int val) -{ - int i; - - for (i = 0; i < NOPTS; i++) - if (optent_letter(optlist[i]) == flag) { - optent_val(i) = val; - if (val) { - /* #%$ hack for ksh semantics */ - if (flag == 'V') - Eflag = 0; - else if (flag == 'E') - Vflag = 0; - } - return; - } - error("Illegal option -%c", flag); - /* NOTREACHED */ -} - - - -/* - * Set the shell parameters. - */ - -static void -setparam(char **argv) -{ - char **newparam; - char **ap; - int nparam; - - for (nparam = 0 ; argv[nparam] ; nparam++); - ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); - while (*argv) { - *ap++ = savestr(*argv++); - } - *ap = NULL; - freeparam(&shellparam); - shellparam.malloc = 1; - shellparam.nparam = nparam; - shellparam.p = newparam; - shellparam.optind = 1; - shellparam.optoff = -1; -} - - -/* - * Free the list of positional parameters. - */ - -static void -freeparam(volatile struct shparam *param) -{ - char **ap; - - if (param->malloc) { - for (ap = param->p ; *ap ; ap++) - ckfree(*ap); - ckfree(param->p); - } -} - - - -/* - * The shift builtin command. - */ - -static int -shiftcmd(argc, argv) - int argc; - char **argv; -{ - int n; - char **ap1, **ap2; - - n = 1; - if (argc > 1) - n = number(argv[1]); - if (n > shellparam.nparam) - error("can't shift that many"); - INTOFF; - shellparam.nparam -= n; - for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { - if (shellparam.malloc) - ckfree(*ap1); - } - ap2 = shellparam.p; - while ((*ap2++ = *ap1++) != NULL); - shellparam.optind = 1; - shellparam.optoff = -1; - INTON; - return 0; -} - - - -/* - * The set command builtin. - */ - -static int -setcmd(argc, argv) - int argc; - char **argv; -{ - if (argc == 1) - return showvarscmd(argc, argv); - INTOFF; - options(0); - optschanged(); - if (*argptr != NULL) { - setparam(argptr); - } - INTON; - return 0; -} - - -static void -getoptsreset(const char *value) -{ - shellparam.optind = number(value); - shellparam.optoff = -1; -} - -#ifdef BB_LOCALE_SUPPORT -static void change_lc_all(const char *value) -{ - if(value != 0 && *value != 0) - setlocale(LC_ALL, value); -} - -static void change_lc_ctype(const char *value) -{ - if(value != 0 && *value != 0) - setlocale(LC_CTYPE, value); -} - -#endif - -#ifdef ASH_GETOPTS -/* - * The getopts builtin. Shellparam.optnext points to the next argument - * to be processed. Shellparam.optptr points to the next character to - * be processed in the current argument. If shellparam.optnext is NULL, - * then it's the first time getopts has been called. - */ - -static int -getoptscmd(argc, argv) - int argc; - char **argv; -{ - char **optbase; - - if (argc < 3) - error("Usage: getopts optstring var [arg]"); - else if (argc == 3) { - optbase = shellparam.p; - if (shellparam.optind > shellparam.nparam + 1) { - shellparam.optind = 1; - shellparam.optoff = -1; - } - } - else { - optbase = &argv[3]; - if (shellparam.optind > argc - 2) { - shellparam.optind = 1; - shellparam.optoff = -1; - } - } - - return getopts(argv[1], argv[2], optbase, &shellparam.optind, - &shellparam.optoff); -} - -/* - * Safe version of setvar, returns 1 on success 0 on failure. - */ - -static int -setvarsafe(name, val, flags) - const char *name, *val; - int flags; -{ - struct jmploc jmploc; - struct jmploc *volatile savehandler = handler; - int err = 0; -#ifdef __GNUC__ - (void) &err; -#endif - - if (setjmp(jmploc.loc)) - err = 1; - else { - handler = &jmploc; - setvar(name, val, flags); - } - handler = savehandler; - return err; -} - -static int -getopts(optstr, optvar, optfirst, myoptind, optoff) - char *optstr; - char *optvar; - char **optfirst; - int *myoptind; - int *optoff; -{ - char *p, *q; - char c = '?'; - int done = 0; - int err = 0; - char s[10]; - char **optnext = optfirst + *myoptind - 1; - - if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) || - strlen(*(optnext - 1)) < *optoff) - p = NULL; - else - p = *(optnext - 1) + *optoff; - if (p == NULL || *p == '\0') { - /* Current word is done, advance */ - if (optnext == NULL) - return 1; - p = *optnext; - if (p == NULL || *p != '-' || *++p == '\0') { -atend: - *myoptind = optnext - optfirst + 1; - p = NULL; - done = 1; - goto out; - } - optnext++; - if (p[0] == '-' && p[1] == '\0') /* check for "--" */ - goto atend; - } - - c = *p++; - for (q = optstr; *q != c; ) { - if (*q == '\0') { - if (optstr[0] == ':') { - s[0] = c; - s[1] = '\0'; - err |= setvarsafe("OPTARG", s, 0); - } - else { - out2fmt("Illegal option -%c\n", c); - (void) unsetvar("OPTARG"); - } - c = '?'; - goto bad; - } - if (*++q == ':') - q++; - } - - if (*++q == ':') { - if (*p == '\0' && (p = *optnext) == NULL) { - if (optstr[0] == ':') { - s[0] = c; - s[1] = '\0'; - err |= setvarsafe("OPTARG", s, 0); - c = ':'; - } - else { - out2fmt("No arg for -%c option\n", c); - (void) unsetvar("OPTARG"); - c = '?'; - } - goto bad; - } - - if (p == *optnext) - optnext++; - setvarsafe("OPTARG", p, 0); - p = NULL; - } - else - setvarsafe("OPTARG", "", 0); - *myoptind = optnext - optfirst + 1; - goto out; - -bad: - *myoptind = 1; - p = NULL; -out: - *optoff = p ? p - *(optnext - 1) : -1; - snprintf(s, sizeof(s), "%d", *myoptind); - err |= setvarsafe("OPTIND", s, VNOFUNC); - s[0] = c; - s[1] = '\0'; - err |= setvarsafe(optvar, s, 0); - if (err) { - *myoptind = 1; - *optoff = -1; - exraise(EXERROR); - } - return done; -} -#endif - -/* - * XXX - should get rid of. have all builtins use getopt(3). the - * library getopt must have the BSD extension static variable "optreset" - * otherwise it can't be used within the shell safely. - * - * Standard option processing (a la getopt) for builtin routines. The - * only argument that is passed to nextopt is the option string; the - * other arguments are unnecessary. It return the character, or '\0' on - * end of input. - */ - -static int -nextopt(const char *optstring) -{ - char *p; - const char *q; - char c; - - if ((p = optptr) == NULL || *p == '\0') { - p = *argptr; - if (p == NULL || *p != '-' || *++p == '\0') - return '\0'; - argptr++; - if (p[0] == '-' && p[1] == '\0') /* check for "--" */ - return '\0'; - } - c = *p++; - for (q = optstring ; *q != c ; ) { - if (*q == '\0') - error("Illegal option -%c", c); - if (*++q == ':') - q++; - } - if (*++q == ':') { - if (*p == '\0' && (p = *argptr++) == NULL) - error("No arg for -%c option", c); - optionarg = p; - p = NULL; - } - optptr = p; - return c; -} - -static void -flushall() { - INTOFF; - fflush(stdout); - INTON; -} - - -static void -out2fmt(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); -} - -/* - * Version of write which resumes after a signal is caught. - */ - -static int -xwrite(int fd, const char *buf, int nbytes) -{ - int ntry; - int i; - int n; - - n = nbytes; - ntry = 0; - for (;;) { - i = write(fd, buf, n); - if (i > 0) { - if ((n -= i) <= 0) - return nbytes; - buf += i; - ntry = 0; - } else if (i == 0) { - if (++ntry > 10) - return nbytes - n; - } else if (errno != EINTR) { - return -1; - } - } -} - - -/* - * Shell command parser. - */ - -#define EOFMARKLEN 79 - - - -struct heredoc { - struct heredoc *next; /* next here document in list */ - union node *here; /* redirection node */ - char *eofmark; /* string indicating end of input */ - int striptabs; /* if set, strip leading tabs */ -}; - -static struct heredoc *heredoclist; /* list of here documents to read */ -static int parsebackquote; /* nonzero if we are inside backquotes */ -static int doprompt; /* if set, prompt the user */ -static int needprompt; /* true if interactive and at start of line */ -static int lasttoken; /* last token read */ - -static char *wordtext; /* text of last word returned by readtoken */ - -static struct nodelist *backquotelist; -static union node *redirnode; -static struct heredoc *heredoc; -static int quoteflag; /* set if (part of) last token was quoted */ -static int startlinno; /* line # where last token started */ - - -static union node *list (int); -static union node *andor (void); -static union node *pipeline (void); -static union node *command (void); -static union node *simplecmd (void); -static void parsefname (void); -static void parseheredoc (void); -static int peektoken (void); -static int readtoken (void); -static int xxreadtoken (void); -static int readtoken1 (int, char const *, char *, int); -static int noexpand (char *); -static void synexpect (int) __attribute__((noreturn)); -static void synerror (const char *) __attribute__((noreturn)); -static void setprompt (int); - - -/* - * Read and parse a command. Returns NEOF on end of file. (NULL is a - * valid parse tree indicating a blank line.) - */ - -static union node * -parsecmd(int interact) -{ - int t; - - tokpushback = 0; - doprompt = interact; - if (doprompt) - setprompt(1); - else - setprompt(0); - needprompt = 0; - t = readtoken(); - if (t == TEOF) - return NEOF; - if (t == TNL) - return NULL; - tokpushback++; - return list(1); -} - - -static union node * -list(nlflag) - int nlflag; -{ - union node *n1, *n2, *n3; - int tok; - - checkkwd = 2; - if (nlflag == 0 && tokendlist[peektoken()]) - return NULL; - n1 = NULL; - for (;;) { - n2 = andor(); - tok = readtoken(); - if (tok == TBACKGND) { - if (n2->type == NCMD || n2->type == NPIPE) { - n2->ncmd.backgnd = 1; - } else if (n2->type == NREDIR) { - n2->type = NBACKGND; - } else { - n3 = (union node *)stalloc(sizeof (struct nredir)); - n3->type = NBACKGND; - n3->nredir.n = n2; - n3->nredir.redirect = NULL; - n2 = n3; - } - } - if (n1 == NULL) { - n1 = n2; - } - else { - n3 = (union node *)stalloc(sizeof (struct nbinary)); - n3->type = NSEMI; - n3->nbinary.ch1 = n1; - n3->nbinary.ch2 = n2; - n1 = n3; - } - switch (tok) { - case TBACKGND: - case TSEMI: - tok = readtoken(); - /* fall through */ - case TNL: - if (tok == TNL) { - parseheredoc(); - if (nlflag) - return n1; - } else { - tokpushback++; - } - checkkwd = 2; - if (tokendlist[peektoken()]) - return n1; - break; - case TEOF: - if (heredoclist) - parseheredoc(); - else - pungetc(); /* push back EOF on input */ - return n1; - default: - if (nlflag) - synexpect(-1); - tokpushback++; - return n1; - } - } -} - - - -static union node * -andor() { - union node *n1, *n2, *n3; - int t; - - checkkwd = 1; - n1 = pipeline(); - for (;;) { - if ((t = readtoken()) == TAND) { - t = NAND; - } else if (t == TOR) { - t = NOR; - } else { - tokpushback++; - return n1; - } - checkkwd = 2; - n2 = pipeline(); - n3 = (union node *)stalloc(sizeof (struct nbinary)); - n3->type = t; - n3->nbinary.ch1 = n1; - n3->nbinary.ch2 = n2; - n1 = n3; - } -} - - - -static union node * -pipeline() { - union node *n1, *n2, *pipenode; - struct nodelist *lp, *prev; - int negate; - - negate = 0; - TRACE(("pipeline: entered\n")); - if (readtoken() == TNOT) { - negate = !negate; - checkkwd = 1; - } else - tokpushback++; - n1 = command(); - if (readtoken() == TPIPE) { - pipenode = (union node *)stalloc(sizeof (struct npipe)); - pipenode->type = NPIPE; - pipenode->npipe.backgnd = 0; - lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); - pipenode->npipe.cmdlist = lp; - lp->n = n1; - do { - prev = lp; - lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); - checkkwd = 2; - lp->n = command(); - prev->next = lp; - } while (readtoken() == TPIPE); - lp->next = NULL; - n1 = pipenode; - } - tokpushback++; - if (negate) { - n2 = (union node *)stalloc(sizeof (struct nnot)); - n2->type = NNOT; - n2->nnot.com = n1; - return n2; - } else - return n1; -} - - - -static union node * -command() { - union node *n1, *n2; - union node *ap, **app; - union node *cp, **cpp; - union node *redir, **rpp; - int t; - - redir = NULL; - n1 = NULL; - rpp = &redir; - - /* Check for redirection which may precede command */ - while (readtoken() == TREDIR) { - *rpp = n2 = redirnode; - rpp = &n2->nfile.next; - parsefname(); - } - tokpushback++; - - switch (readtoken()) { - case TIF: - n1 = (union node *)stalloc(sizeof (struct nif)); - n1->type = NIF; - n1->nif.test = list(0); - if (readtoken() != TTHEN) - synexpect(TTHEN); - n1->nif.ifpart = list(0); - n2 = n1; - while (readtoken() == TELIF) { - n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); - n2 = n2->nif.elsepart; - n2->type = NIF; - n2->nif.test = list(0); - if (readtoken() != TTHEN) - synexpect(TTHEN); - n2->nif.ifpart = list(0); - } - if (lasttoken == TELSE) - n2->nif.elsepart = list(0); - else { - n2->nif.elsepart = NULL; - tokpushback++; - } - if (readtoken() != TFI) - synexpect(TFI); - checkkwd = 1; - break; - case TWHILE: - case TUNTIL: { - int got; - n1 = (union node *)stalloc(sizeof (struct nbinary)); - n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; - n1->nbinary.ch1 = list(0); - if ((got=readtoken()) != TDO) { -TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); - synexpect(TDO); - } - n1->nbinary.ch2 = list(0); - if (readtoken() != TDONE) - synexpect(TDONE); - checkkwd = 1; - break; - } - case TFOR: - if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) - synerror("Bad for loop variable"); - n1 = (union node *)stalloc(sizeof (struct nfor)); - n1->type = NFOR; - n1->nfor.var = wordtext; - checkkwd = 1; - if (readtoken() == TIN) { - app = ≈ - while (readtoken() == TWORD) { - n2 = (union node *)stalloc(sizeof (struct narg)); - n2->type = NARG; - n2->narg.text = wordtext; - n2->narg.backquote = backquotelist; - *app = n2; - app = &n2->narg.next; - } - *app = NULL; - n1->nfor.args = ap; - if (lasttoken != TNL && lasttoken != TSEMI) - synexpect(-1); - } else { - static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, - '@', '=', '\0'}; - n2 = (union node *)stalloc(sizeof (struct narg)); - n2->type = NARG; - n2->narg.text = argvars; - n2->narg.backquote = NULL; - n2->narg.next = NULL; - n1->nfor.args = n2; - /* - * Newline or semicolon here is optional (but note - * that the original Bourne shell only allowed NL). - */ - if (lasttoken != TNL && lasttoken != TSEMI) - tokpushback++; - } - checkkwd = 2; - if (readtoken() != TDO) - synexpect(TDO); - n1->nfor.body = list(0); - if (readtoken() != TDONE) - synexpect(TDONE); - checkkwd = 1; - break; - case TCASE: - n1 = (union node *)stalloc(sizeof (struct ncase)); - n1->type = NCASE; - if (readtoken() != TWORD) - synexpect(TWORD); - n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); - n2->type = NARG; - n2->narg.text = wordtext; - n2->narg.backquote = backquotelist; - n2->narg.next = NULL; - do { - checkkwd = 1; - } while (readtoken() == TNL); - if (lasttoken != TIN) - synerror("expecting \"in\""); - cpp = &n1->ncase.cases; - checkkwd = 2, readtoken(); - do { - if (lasttoken == TLP) - readtoken(); - *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); - cp->type = NCLIST; - app = &cp->nclist.pattern; - for (;;) { - *app = ap = (union node *)stalloc(sizeof (struct narg)); - ap->type = NARG; - ap->narg.text = wordtext; - ap->narg.backquote = backquotelist; - if (checkkwd = 2, readtoken() != TPIPE) - break; - app = &ap->narg.next; - readtoken(); - } - ap->narg.next = NULL; - if (lasttoken != TRP) - synexpect(TRP); - cp->nclist.body = list(0); - - checkkwd = 2; - if ((t = readtoken()) != TESAC) { - if (t != TENDCASE) - synexpect(TENDCASE); - else - checkkwd = 2, readtoken(); - } - cpp = &cp->nclist.next; - } while(lasttoken != TESAC); - *cpp = NULL; - checkkwd = 1; - break; - case TLP: - n1 = (union node *)stalloc(sizeof (struct nredir)); - n1->type = NSUBSHELL; - n1->nredir.n = list(0); - n1->nredir.redirect = NULL; - if (readtoken() != TRP) - synexpect(TRP); - checkkwd = 1; - break; - case TBEGIN: - n1 = list(0); - if (readtoken() != TEND) - synexpect(TEND); - checkkwd = 1; - break; - /* Handle an empty command like other simple commands. */ - case TSEMI: - case TAND: - case TOR: - case TNL: - case TEOF: - case TRP: - case TBACKGND: - /* - * An empty command before a ; doesn't make much sense, and - * should certainly be disallowed in the case of `if ;'. - */ - if (!redir) - synexpect(-1); - case TWORD: - tokpushback++; - n1 = simplecmd(); - return n1; - default: - synexpect(-1); - /* NOTREACHED */ - } - - /* Now check for redirection which may follow command */ - while (readtoken() == TREDIR) { - *rpp = n2 = redirnode; - rpp = &n2->nfile.next; - parsefname(); - } - tokpushback++; - *rpp = NULL; - if (redir) { - if (n1->type != NSUBSHELL) { - n2 = (union node *)stalloc(sizeof (struct nredir)); - n2->type = NREDIR; - n2->nredir.n = n1; - n1 = n2; - } - n1->nredir.redirect = redir; - } - - return n1; -} - - -static union node * -simplecmd() { - union node *args, **app; - union node *n = NULL; - union node *vars, **vpp; - union node **rpp, *redir; - - args = NULL; - app = &args; - vars = NULL; - vpp = &vars; - redir = NULL; - rpp = &redir; - - checkalias = 2; - for (;;) { - switch (readtoken()) { - case TWORD: - case TASSIGN: - n = (union node *)stalloc(sizeof (struct narg)); - n->type = NARG; - n->narg.text = wordtext; - n->narg.backquote = backquotelist; - if (lasttoken == TWORD) { - *app = n; - app = &n->narg.next; - } else { - *vpp = n; - vpp = &n->narg.next; - } - break; - case TREDIR: - *rpp = n = redirnode; - rpp = &n->nfile.next; - parsefname(); /* read name of redirection file */ - break; - case TLP: - if ( - args && app == &args->narg.next && - !vars && !redir - ) { - /* We have a function */ - if (readtoken() != TRP) - synexpect(TRP); - n->type = NDEFUN; - checkkwd = 2; - n->narg.next = command(); - return n; - } - /* fall through */ - default: - tokpushback++; - goto out; - } - } -out: - *app = NULL; - *vpp = NULL; - *rpp = NULL; - n = (union node *)stalloc(sizeof (struct ncmd)); - n->type = NCMD; - n->ncmd.backgnd = 0; - n->ncmd.args = args; - n->ncmd.assign = vars; - n->ncmd.redirect = redir; - return n; -} - -static union node * -makename(void) { - union node *n; - - n = (union node *)stalloc(sizeof (struct narg)); - n->type = NARG; - n->narg.next = NULL; - n->narg.text = wordtext; - n->narg.backquote = backquotelist; - return n; -} - -static void fixredir(union node *n, const char *text, int err) -{ - TRACE(("Fix redir %s %d\n", text, err)); - if (!err) - n->ndup.vname = NULL; - - if (is_digit(text[0]) && text[1] == '\0') - n->ndup.dupfd = digit_val(text[0]); - else if (text[0] == '-' && text[1] == '\0') - n->ndup.dupfd = -1; - else { - - if (err) - synerror("Bad fd number"); - else - n->ndup.vname = makename(); - } -} - - -static void -parsefname(void) { - union node *n = redirnode; - - if (readtoken() != TWORD) - synexpect(-1); - if (n->type == NHERE) { - struct heredoc *here = heredoc; - struct heredoc *p; - int i; - - if (quoteflag == 0) - n->type = NXHERE; - TRACE(("Here document %d\n", n->type)); - if (here->striptabs) { - while (*wordtext == '\t') - wordtext++; - } - if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) - synerror("Illegal eof marker for << redirection"); - rmescapes(wordtext); - here->eofmark = wordtext; - here->next = NULL; - if (heredoclist == NULL) - heredoclist = here; - else { - for (p = heredoclist ; p->next ; p = p->next); - p->next = here; - } - } else if (n->type == NTOFD || n->type == NFROMFD) { - fixredir(n, wordtext, 0); - } else { - n->nfile.fname = makename(); - } -} - - -/* - * Input any here documents. - */ - -static void -parseheredoc() { - struct heredoc *here; - union node *n; - - while (heredoclist) { - here = heredoclist; - heredoclist = here->next; - if (needprompt) { - setprompt(2); - needprompt = 0; - } - readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, - here->eofmark, here->striptabs); - n = (union node *)stalloc(sizeof (struct narg)); - n->narg.type = NARG; - n->narg.next = NULL; - n->narg.text = wordtext; - n->narg.backquote = backquotelist; - here->here->nhere.doc = n; - } -} - -static int -peektoken() { - int t; - - t = readtoken(); - tokpushback++; - return (t); -} - -static int -readtoken() { - int t; - -#ifdef ASH_ALIAS - int savecheckalias = checkalias; - int savecheckkwd = checkkwd; - struct alias *ap; -#endif - -#ifdef DEBUG - int alreadyseen = tokpushback; -#endif - -#ifdef ASH_ALIAS -top: -#endif - - t = xxreadtoken(); - -#ifdef ASH_ALIAS - checkalias = savecheckalias; -#endif - - if (checkkwd) { - /* - * eat newlines - */ - if (checkkwd == 2) { - checkkwd = 0; - while (t == TNL) { - parseheredoc(); - t = xxreadtoken(); - } - } - checkkwd = 0; - /* - * check for keywords - */ - if (t == TWORD && !quoteflag) - { - const char *const *pp; - - if ((pp = findkwd(wordtext))) { - lasttoken = t = pp - parsekwd + KWDOFFSET; - TRACE(("keyword %s recognized\n", tokname[t])); - goto out; - } - } - } - - - if (t != TWORD) { - if (t != TREDIR) { - checkalias = 0; - } - } else if (checkalias == 2 && isassignment(wordtext)) { - lasttoken = t = TASSIGN; -#ifdef ASH_ALIAS - } else if (checkalias) { - if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) { - if (*ap->val) { - pushstring(ap->val, strlen(ap->val), ap); - } - checkkwd = savecheckkwd; - goto top; - } - checkalias = 0; -#endif - } -out: -#ifdef DEBUG - if (!alreadyseen) - TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : "")); - else - TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : "")); -#endif - return (t); -} - - -/* - * Read the next input token. - * If the token is a word, we set backquotelist to the list of cmds in - * backquotes. We set quoteflag to true if any part of the word was - * quoted. - * If the token is TREDIR, then we set redirnode to a structure containing - * the redirection. - * In all cases, the variable startlinno is set to the number of the line - * on which the token starts. - * - * [Change comment: here documents and internal procedures] - * [Readtoken shouldn't have any arguments. Perhaps we should make the - * word parsing code into a separate routine. In this case, readtoken - * doesn't need to have any internal procedures, but parseword does. - * We could also make parseoperator in essence the main routine, and - * have parseword (readtoken1?) handle both words and redirection.] - */ - -#define RETURN(token) return lasttoken = token - -static int -xxreadtoken() { - int c; - - if (tokpushback) { - tokpushback = 0; - return lasttoken; - } - if (needprompt) { - setprompt(2); - needprompt = 0; - } - startlinno = plinno; - for (;;) { /* until token or start of word found */ - c = pgetc_macro(); - switch (c) { - case ' ': case '\t': -#ifdef ASH_ALIAS - case PEOA: -#endif - continue; - case '#': - while ((c = pgetc()) != '\n' && c != PEOF); - pungetc(); - continue; - case '\\': - if (pgetc() == '\n') { - startlinno = ++plinno; - if (doprompt) - setprompt(2); - else - setprompt(0); - continue; - } - pungetc(); - goto breakloop; - case '\n': - plinno++; - needprompt = doprompt; - RETURN(TNL); - case PEOF: - RETURN(TEOF); - case '&': - if (pgetc() == '&') - RETURN(TAND); - pungetc(); - RETURN(TBACKGND); - case '|': - if (pgetc() == '|') - RETURN(TOR); - pungetc(); - RETURN(TPIPE); - case ';': - if (pgetc() == ';') - RETURN(TENDCASE); - pungetc(); - RETURN(TSEMI); - case '(': - RETURN(TLP); - case ')': - RETURN(TRP); - default: - goto breakloop; - } - } -breakloop: - return readtoken1(c, BASESYNTAX, (char *)NULL, 0); -#undef RETURN -} - - - -/* - * If eofmark is NULL, read a word or a redirection symbol. If eofmark - * is not NULL, read a here document. In the latter case, eofmark is the - * word which marks the end of the document and striptabs is true if - * leading tabs should be stripped from the document. The argument firstc - * is the first character of the input token or document. - * - * Because C does not have internal subroutines, I have simulated them - * using goto's to implement the subroutine linkage. The following macros - * will run code that appears at the end of readtoken1. - */ - -#define CHECKEND() {goto checkend; checkend_return:;} -#define PARSEREDIR() {goto parseredir; parseredir_return:;} -#define PARSESUB() {goto parsesub; parsesub_return:;} -#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} -#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} -#define PARSEARITH() {goto parsearith; parsearith_return:;} - -static int -readtoken1(firstc, syntax, eofmark, striptabs) - int firstc; - char const *syntax; - char *eofmark; - int striptabs; - { - int c = firstc; - char *out; - int len; - char line[EOFMARKLEN + 1]; - struct nodelist *bqlist; - int quotef; - int dblquote; - int varnest; /* levels of variables expansion */ - int arinest; /* levels of arithmetic expansion */ - int parenlevel; /* levels of parens in arithmetic */ - int dqvarnest; /* levels of variables expansion within double quotes */ - int oldstyle; - char const *prevsyntax; /* syntax before arithmetic */ -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &out; - (void) "ef; - (void) &dblquote; - (void) &varnest; - (void) &arinest; - (void) &parenlevel; - (void) &dqvarnest; - (void) &oldstyle; - (void) &prevsyntax; - (void) &syntax; -#endif - - startlinno = plinno; - dblquote = 0; - if (syntax == DQSYNTAX) - dblquote = 1; - quotef = 0; - bqlist = NULL; - varnest = 0; - arinest = 0; - parenlevel = 0; - dqvarnest = 0; - - STARTSTACKSTR(out); - loop: { /* for each line, until end of word */ - CHECKEND(); /* set c to PEOF if at end of here document */ - for (;;) { /* until end of line or end of word */ - CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ - switch(syntax[c]) { - case CNL: /* '\n' */ - if (syntax == BASESYNTAX) - goto endword; /* exit outer loop */ - USTPUTC(c, out); - plinno++; - if (doprompt) - setprompt(2); - else - setprompt(0); - c = pgetc(); - goto loop; /* continue outer loop */ - case CWORD: - USTPUTC(c, out); - break; - case CCTL: - if ((eofmark == NULL || dblquote) && - dqvarnest == 0) - USTPUTC(CTLESC, out); - USTPUTC(c, out); - break; - case CBACK: /* backslash */ - c = pgetc2(); - if (c == PEOF) { - USTPUTC('\\', out); - pungetc(); - } else if (c == '\n') { - if (doprompt) - setprompt(2); - else - setprompt(0); - } else { - if (dblquote && c != '\\' && c != '`' && c != '$' - && (c != '"' || eofmark != NULL)) - USTPUTC('\\', out); - if (SQSYNTAX[c] == CCTL) - USTPUTC(CTLESC, out); - else if (eofmark == NULL) - USTPUTC(CTLQUOTEMARK, out); - USTPUTC(c, out); - quotef++; - } - break; - case CSQUOTE: - if (eofmark == NULL) - USTPUTC(CTLQUOTEMARK, out); - syntax = SQSYNTAX; - break; - case CDQUOTE: - if (eofmark == NULL) - USTPUTC(CTLQUOTEMARK, out); - syntax = DQSYNTAX; - dblquote = 1; - break; - case CENDQUOTE: - if (eofmark != NULL && arinest == 0 && - varnest == 0) { - USTPUTC(c, out); - } else { - if (arinest) { - syntax = ARISYNTAX; - dblquote = 0; - } else if (eofmark == NULL && - dqvarnest == 0) { - syntax = BASESYNTAX; - dblquote = 0; - } - quotef++; - } - break; - case CVAR: /* '$' */ - PARSESUB(); /* parse substitution */ - break; - case CENDVAR: /* '}' */ - if (varnest > 0) { - varnest--; - if (dqvarnest > 0) { - dqvarnest--; - } - USTPUTC(CTLENDVAR, out); - } else { - USTPUTC(c, out); - } - break; -#ifdef ASH_MATH_SUPPORT - case CLP: /* '(' in arithmetic */ - parenlevel++; - USTPUTC(c, out); - break; - case CRP: /* ')' in arithmetic */ - if (parenlevel > 0) { - USTPUTC(c, out); - --parenlevel; - } else { - if (pgetc() == ')') { - if (--arinest == 0) { - USTPUTC(CTLENDARI, out); - syntax = prevsyntax; - if (syntax == DQSYNTAX) - dblquote = 1; - else - dblquote = 0; - } else - USTPUTC(')', out); - } else { - /* - * unbalanced parens - * (don't 2nd guess - no error) - */ - pungetc(); - USTPUTC(')', out); - } - } - break; -#endif - case CBQUOTE: /* '`' */ - PARSEBACKQOLD(); - break; - case CENDFILE: - goto endword; /* exit outer loop */ - case CIGN: - break; - default: - if (varnest == 0) - goto endword; /* exit outer loop */ -#ifdef ASH_ALIAS - if (c != PEOA) -#endif - USTPUTC(c, out); - - } - c = pgetc_macro(); - } - } -endword: - if (syntax == ARISYNTAX) - synerror("Missing '))'"); - if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) - synerror("Unterminated quoted string"); - if (varnest != 0) { - startlinno = plinno; - synerror("Missing '}'"); - } - USTPUTC('\0', out); - len = out - stackblock(); - out = stackblock(); - if (eofmark == NULL) { - if ((c == '>' || c == '<') - && quotef == 0 - && len <= 2 - && (*out == '\0' || is_digit(*out))) { - PARSEREDIR(); - return lasttoken = TREDIR; - } else { - pungetc(); - } - } - quoteflag = quotef; - backquotelist = bqlist; - grabstackblock(len); - wordtext = out; - return lasttoken = TWORD; -/* end of readtoken routine */ - - - -/* - * Check to see whether we are at the end of the here document. When this - * is called, c is set to the first character of the next input line. If - * we are at the end of the here document, this routine sets the c to PEOF. - */ - -checkend: { - if (eofmark) { -#ifdef ASH_ALIAS - if (c == PEOA) { - c = pgetc2(); - } -#endif - if (striptabs) { - while (c == '\t') { - c = pgetc2(); - } - } - if (c == *eofmark) { - if (pfgets(line, sizeof line) != NULL) { - char *p, *q; - - p = line; - for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); - if (*p == '\n' && *q == '\0') { - c = PEOF; - plinno++; - needprompt = doprompt; - } else { - pushstring(line, strlen(line), NULL); - } - } - } - } - goto checkend_return; -} - - -/* - * Parse a redirection operator. The variable "out" points to a string - * specifying the fd to be redirected. The variable "c" contains the - * first character of the redirection operator. - */ - -parseredir: { - char fd = *out; - union node *np; - - np = (union node *)stalloc(sizeof (struct nfile)); - if (c == '>') { - np->nfile.fd = 1; - c = pgetc(); - if (c == '>') - np->type = NAPPEND; - else if (c == '&') - np->type = NTOFD; - else if (c == '|') - np->type = NTOOV; - else { - np->type = NTO; - pungetc(); - } - } else { /* c == '<' */ - np->nfile.fd = 0; - switch (c = pgetc()) { - case '<': - if (sizeof (struct nfile) != sizeof (struct nhere)) { - np = (union node *)stalloc(sizeof (struct nhere)); - np->nfile.fd = 0; - } - np->type = NHERE; - heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); - heredoc->here = np; - if ((c = pgetc()) == '-') { - heredoc->striptabs = 1; - } else { - heredoc->striptabs = 0; - pungetc(); - } - break; - - case '&': - np->type = NFROMFD; - break; - - case '>': - np->type = NFROMTO; - break; - - default: - np->type = NFROM; - pungetc(); - break; - } - } - if (fd != '\0') - np->nfile.fd = digit_val(fd); - redirnode = np; - goto parseredir_return; -} - - -/* - * Parse a substitution. At this point, we have read the dollar sign - * and nothing else. - */ - -parsesub: { - int subtype; - int typeloc; - int flags; - char *p; - static const char types[] = "}-+?="; - - c = pgetc(); - if ( - c <= PEOA || - (c != '(' && c != '{' && !is_name(c) && !is_special(c)) - ) { - USTPUTC('$', out); - pungetc(); - } else if (c == '(') { /* $(command) or $((arith)) */ - if (pgetc() == '(') { - PARSEARITH(); - } else { - pungetc(); - PARSEBACKQNEW(); - } - } else { - USTPUTC(CTLVAR, out); - typeloc = out - stackblock(); - USTPUTC(VSNORMAL, out); - subtype = VSNORMAL; - if (c == '{') { - c = pgetc(); - if (c == '#') { - if ((c = pgetc()) == '}') - c = '#'; - else - subtype = VSLENGTH; - } - else - subtype = 0; - } - if (c > PEOA && is_name(c)) { - do { - STPUTC(c, out); - c = pgetc(); - } while (c > PEOA && is_in_name(c)); - } else if (is_digit(c)) { - do { - USTPUTC(c, out); - c = pgetc(); - } while (is_digit(c)); - } - else if (is_special(c)) { - USTPUTC(c, out); - c = pgetc(); - } - else -badsub: synerror("Bad substitution"); - - STPUTC('=', out); - flags = 0; - if (subtype == 0) { - switch (c) { - case ':': - flags = VSNUL; - c = pgetc(); - /*FALLTHROUGH*/ - default: - p = strchr(types, c); - if (p == NULL) - goto badsub; - subtype = p - types + VSNORMAL; - break; - case '%': - case '#': - { - int cc = c; - subtype = c == '#' ? VSTRIMLEFT : - VSTRIMRIGHT; - c = pgetc(); - if (c == cc) - subtype++; - else - pungetc(); - break; - } - } - } else { - pungetc(); - } - if (dblquote || arinest) - flags |= VSQUOTE; - *(stackblock() + typeloc) = subtype | flags; - if (subtype != VSNORMAL) { - varnest++; - if (dblquote) { - dqvarnest++; - } - } - } - goto parsesub_return; -} - - -/* - * Called to parse command substitutions. Newstyle is set if the command - * is enclosed inside $(...); nlpp is a pointer to the head of the linked - * list of commands (passed by reference), and savelen is the number of - * characters on the top of the stack which must be preserved. - */ - -parsebackq: { - struct nodelist **nlpp; - int savepbq; - union node *n; - char *volatile str; - struct jmploc jmploc; - struct jmploc *volatile savehandler; - int savelen; - int saveprompt; -#ifdef __GNUC__ - (void) &saveprompt; -#endif - - savepbq = parsebackquote; - if (setjmp(jmploc.loc)) { - if (str) - ckfree(str); - parsebackquote = 0; - handler = savehandler; - longjmp(handler->loc, 1); - } - INTOFF; - str = NULL; - savelen = out - stackblock(); - if (savelen > 0) { - str = ckmalloc(savelen); - memcpy(str, stackblock(), savelen); - } - savehandler = handler; - handler = &jmploc; - INTON; - if (oldstyle) { - /* We must read until the closing backquote, giving special - treatment to some slashes, and then push the string and - reread it as input, interpreting it normally. */ - char *pout; - int pc; - int psavelen; - char *pstr; - - - STARTSTACKSTR(pout); - for (;;) { - if (needprompt) { - setprompt(2); - needprompt = 0; - } - switch (pc = pgetc()) { - case '`': - goto done; - - case '\\': - if ((pc = pgetc()) == '\n') { - plinno++; - if (doprompt) - setprompt(2); - else - setprompt(0); - /* - * If eating a newline, avoid putting - * the newline into the new character - * stream (via the STPUTC after the - * switch). - */ - continue; - } - if (pc != '\\' && pc != '`' && pc != '$' - && (!dblquote || pc != '"')) - STPUTC('\\', pout); - if (pc > PEOA) { - break; - } - /* fall through */ - - case PEOF: -#ifdef ASH_ALIAS - case PEOA: -#endif - startlinno = plinno; - synerror("EOF in backquote substitution"); - - case '\n': - plinno++; - needprompt = doprompt; - break; - - default: - break; - } - STPUTC(pc, pout); - } -done: - STPUTC('\0', pout); - psavelen = pout - stackblock(); - if (psavelen > 0) { - pstr = grabstackstr(pout); - setinputstring(pstr); - } - } - nlpp = &bqlist; - while (*nlpp) - nlpp = &(*nlpp)->next; - *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); - (*nlpp)->next = NULL; - parsebackquote = oldstyle; - - if (oldstyle) { - saveprompt = doprompt; - doprompt = 0; - } - - n = list(0); - - if (oldstyle) - doprompt = saveprompt; - else { - if (readtoken() != TRP) - synexpect(TRP); - } - - (*nlpp)->n = n; - if (oldstyle) { - /* - * Start reading from old file again, ignoring any pushed back - * tokens left from the backquote parsing - */ - popfile(); - tokpushback = 0; - } - while (stackblocksize() <= savelen) - growstackblock(); - STARTSTACKSTR(out); - if (str) { - memcpy(out, str, savelen); - STADJUST(savelen, out); - INTOFF; - ckfree(str); - str = NULL; - INTON; - } - parsebackquote = savepbq; - handler = savehandler; - if (arinest || dblquote) - USTPUTC(CTLBACKQ | CTLQUOTE, out); - else - USTPUTC(CTLBACKQ, out); - if (oldstyle) - goto parsebackq_oldreturn; - else - goto parsebackq_newreturn; -} - -/* - * Parse an arithmetic expansion (indicate start of one and set state) - */ -parsearith: { - - if (++arinest == 1) { - prevsyntax = syntax; - syntax = ARISYNTAX; - USTPUTC(CTLARI, out); - if (dblquote) - USTPUTC('"',out); - else - USTPUTC(' ',out); - } else { - /* - * we collapse embedded arithmetic expansion to - * parenthesis, which should be equivalent - */ - USTPUTC('(', out); - } - goto parsearith_return; -} - -} /* end of readtoken */ - - -/* - * Returns true if the text contains nothing to expand (no dollar signs - * or backquotes). - */ - -static int -noexpand(text) - char *text; - { - char *p; - char c; - - p = text; - while ((c = *p++) != '\0') { - if (c == CTLQUOTEMARK) - continue; - if (c == CTLESC) - p++; - else if (BASESYNTAX[(int)c] == CCTL) - return 0; - } - return 1; -} - - -/* - * Return true if the argument is a legal variable name (a letter or - * underscore followed by zero or more letters, underscores, and digits). - */ - -static int -goodname(const char *name) -{ - const char *p; - - p = name; - if (! is_name(*p)) - return 0; - while (*++p) { - if (! is_in_name(*p)) - return 0; - } - return 1; -} - - -/* - * Called when an unexpected token is read during the parse. The argument - * is the token that is expected, or -1 if more than one type of token can - * occur at this point. - */ - -static void -synexpect(token) - int token; -{ - char msg[64]; - - if (token >= 0) { - snprintf(msg, 64, "%s unexpected (expecting %s)", - tokname[lasttoken], tokname[token]); - } else { - snprintf(msg, 64, "%s unexpected", tokname[lasttoken]); - } - synerror(msg); - /* NOTREACHED */ -} - - -static void -synerror(const char *msg) -{ - if (commandname) - out2fmt("%s: %d: ", commandname, startlinno); - out2fmt("Syntax error: %s\n", msg); - error((char *)NULL); - /* NOTREACHED */ -} - - -/* - * called by editline -- any expansions to the prompt - * should be added here. - */ -static void -setprompt(int whichprompt) -{ - char *prompt; - switch (whichprompt) { - case 1: - prompt = ps1val(); - break; - case 2: - prompt = ps2val(); - break; - default: /* 0 */ - prompt = ""; - } - putprompt(prompt); -} - - -/* - * Code for dealing with input/output redirection. - */ - -#define EMPTY -2 /* marks an unused slot in redirtab */ -#ifndef PIPE_BUF -# define PIPESIZE 4096 /* amount of buffering in a pipe */ -#else -# define PIPESIZE PIPE_BUF -#endif - - -/* - * Open a file in noclobber mode. - * The code was copied from bash. - */ -static inline int -noclobberopen(const char *fname) -{ - int r, fd; - struct stat finfo, finfo2; - - /* - * If the file exists and is a regular file, return an error - * immediately. - */ - r = stat(fname, &finfo); - if (r == 0 && S_ISREG(finfo.st_mode)) { - errno = EEXIST; - return -1; - } - - /* - * If the file was not present (r != 0), make sure we open it - * exclusively so that if it is created before we open it, our open - * will fail. Make sure that we do not truncate an existing file. - * Note that we don't turn on O_EXCL unless the stat failed -- if the - * file was not a regular file, we leave O_EXCL off. - */ - if (r != 0) - return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666); - fd = open(fname, O_WRONLY|O_CREAT, 0666); - - /* If the open failed, return the file descriptor right away. */ - if (fd < 0) - return fd; - - /* - * OK, the open succeeded, but the file may have been changed from a - * non-regular file to a regular file between the stat and the open. - * We are assuming that the O_EXCL open handles the case where FILENAME - * did not exist and is symlinked to an existing file between the stat - * and open. - */ - - /* - * If we can open it and fstat the file descriptor, and neither check - * revealed that it was a regular file, and the file has not been - * replaced, return the file descriptor. - */ - if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) && - finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) - return fd; - - /* The file has been replaced. badness. */ - close(fd); - errno = EEXIST; - return -1; -} - -/* - * Handle here documents. Normally we fork off a process to write the - * data to a pipe. If the document is short, we can stuff the data in - * the pipe without forking. - */ - -static inline int -openhere(const union node *redir) -{ - int pip[2]; - int len = 0; - - if (pipe(pip) < 0) - error("Pipe call failed"); - if (redir->type == NHERE) { - len = strlen(redir->nhere.doc->narg.text); - if (len <= PIPESIZE) { - xwrite(pip[1], redir->nhere.doc->narg.text, len); - goto out; - } - } - if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { - close(pip[0]); - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - signal(SIGHUP, SIG_IGN); -#ifdef SIGTSTP - signal(SIGTSTP, SIG_IGN); -#endif - signal(SIGPIPE, SIG_DFL); - if (redir->type == NHERE) - xwrite(pip[1], redir->nhere.doc->narg.text, len); - else - expandhere(redir->nhere.doc, pip[1]); - _exit(0); - } -out: - close(pip[1]); - return pip[0]; -} - - -static inline int -openredirect(const union node *redir) -{ - char *fname; - int f; - - switch (redir->nfile.type) { - case NFROM: - fname = redir->nfile.expfname; - if ((f = open(fname, O_RDONLY)) < 0) - goto eopen; - break; - case NFROMTO: - fname = redir->nfile.expfname; - if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) - goto ecreate; - break; - case NTO: - /* Take care of noclobber mode. */ - if (Cflag) { - fname = redir->nfile.expfname; - if ((f = noclobberopen(fname)) < 0) - goto ecreate; - break; - } - case NTOOV: - fname = redir->nfile.expfname; -#ifdef O_CREAT - if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) - goto ecreate; -#else - if ((f = creat(fname, 0666)) < 0) - goto ecreate; -#endif - break; - case NAPPEND: - fname = redir->nfile.expfname; -#ifdef O_APPEND - if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) - goto ecreate; -#else - if ((f = open(fname, O_WRONLY)) < 0 - && (f = creat(fname, 0666)) < 0) - goto ecreate; - lseek(f, (off_t)0, 2); -#endif - break; - default: -#ifdef DEBUG - abort(); -#endif - /* Fall through to eliminate warning. */ - case NTOFD: - case NFROMFD: - f = -1; - break; - case NHERE: - case NXHERE: - f = openhere(redir); - break; - } - - return f; -ecreate: - error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); -eopen: - error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); -} - - -/* - * Process a list of redirection commands. If the REDIR_PUSH flag is set, - * old file descriptors are stashed away so that the redirection can be - * undone by calling popredir. If the REDIR_BACKQ flag is set, then the - * standard output, and the standard error if it becomes a duplicate of - * stdout. - */ - -static void -redirect(union node *redir, int flags) -{ - union node *n; - struct redirtab *sv = NULL; - int i; - int fd; - int newfd; - int try; - int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */ - - if (flags & REDIR_PUSH) { - sv = ckmalloc(sizeof (struct redirtab)); - for (i = 0 ; i < 10 ; i++) - sv->renamed[i] = EMPTY; - sv->next = redirlist; - redirlist = sv; - } - for (n = redir ; n ; n = n->nfile.next) { - fd = n->nfile.fd; - try = 0; - if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) && - n->ndup.dupfd == fd) - continue; /* redirect from/to same file descriptor */ - - INTOFF; - newfd = openredirect(n); - if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { - if (newfd == fd) { - try++; - } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) { - switch (errno) { - case EBADF: - if (!try) { - dupredirect(n, newfd, fd1dup); - try++; - break; - } - /* FALLTHROUGH*/ - default: - if (newfd >= 0) { - close(newfd); - } - INTON; - error("%d: %m", fd); - /* NOTREACHED */ - } - } - if (!try) { - close(fd); - if (flags & REDIR_PUSH) { - sv->renamed[fd] = i; - } - } - } else if (fd != newfd) { - close(fd); - } - if (fd == 0) - fd0_redirected++; - if (!try) - dupredirect(n, newfd, fd1dup); - INTON; - } -} - - -static void -dupredirect(const union node *redir, int f, int fd1dup) -{ - int fd = redir->nfile.fd; - - if(fd==1) - fd1dup = 0; - if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { - if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ - if (redir->ndup.dupfd!=1 || fd1dup!=1) - dup_as_newfd(redir->ndup.dupfd, fd); - } - return; - } - - if (f != fd) { - dup_as_newfd(f, fd); - close(f); - } - return; -} - - - -/* - * Undo the effects of the last redirection. - */ - -static void -popredir(void) -{ - struct redirtab *rp = redirlist; - int i; - - INTOFF; - for (i = 0 ; i < 10 ; i++) { - if (rp->renamed[i] != EMPTY) { - if (i == 0) - fd0_redirected--; - close(i); - if (rp->renamed[i] >= 0) { - dup_as_newfd(rp->renamed[i], i); - close(rp->renamed[i]); - } - } - } - redirlist = rp->next; - ckfree(rp); - INTON; -} - -/* - * Discard all saved file descriptors. - */ - -static void -clearredir(void) { - struct redirtab *rp; - int i; - - for (rp = redirlist ; rp ; rp = rp->next) { - for (i = 0 ; i < 10 ; i++) { - if (rp->renamed[i] >= 0) { - close(rp->renamed[i]); - } - rp->renamed[i] = EMPTY; - } - } -} - - -/* - * Copy a file descriptor to be >= to. Returns -1 - * if the source file descriptor is closed, EMPTY if there are no unused - * file descriptors left. - */ - -static int -dup_as_newfd(from, to) - int from; - int to; -{ - int newfd; - - newfd = fcntl(from, F_DUPFD, to); - if (newfd < 0) { - if (errno == EMFILE) - return EMPTY; - else - error("%d: %m", from); - } - return newfd; -} - -/*#ifdef __weak_alias -__weak_alias(getmode,_getmode) -__weak_alias(setmode,_setmode) -#endif*/ - -#ifndef S_ISTXT -#if defined(__GLIBC__) && __GLIBC__ >= 2 -#define S_ISTXT __S_ISVTX -#else -#define S_ISTXT S_ISVTX -#endif -#endif - -#define SET_LEN 6 /* initial # of bitcmd struct to malloc */ -#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */ - -typedef struct bitcmd { - char cmd; - char cmd2; - mode_t bits; -} BITCMD; - -#define CMD2_CLR 0x01 -#define CMD2_SET 0x02 -#define CMD2_GBITS 0x04 -#define CMD2_OBITS 0x08 -#define CMD2_UBITS 0x10 - -static BITCMD *addcmd (BITCMD *, int, int, int, u_int); -static void compress_mode (BITCMD *); -#ifdef SETMODE_DEBUG -static void dumpmode (BITCMD *); -#endif - -/* - * Given the old mode and an array of bitcmd structures, apply the operations - * described in the bitcmd structures to the old mode, and return the new mode. - * Note that there is no '=' command; a strict assignment is just a '-' (clear - * bits) followed by a '+' (set bits). - */ -static mode_t -getmode(bbox, omode) - const void *bbox; - mode_t omode; -{ - const BITCMD *set; - mode_t clrval, newmode, value; - - _DIAGASSERT(bbox != NULL); - - set = (const BITCMD *)bbox; - newmode = omode; - for (value = 0;; set++) - switch(set->cmd) { - /* - * When copying the user, group or other bits around, we "know" - * where the bits are in the mode so that we can do shifts to - * copy them around. If we don't use shifts, it gets real - * grundgy with lots of single bit checks and bit sets. - */ - case 'u': - value = (newmode & S_IRWXU) >> 6; - goto common; - - case 'g': - value = (newmode & S_IRWXG) >> 3; - goto common; - - case 'o': - value = newmode & S_IRWXO; -common: if (set->cmd2 & CMD2_CLR) { - clrval = - (set->cmd2 & CMD2_SET) ? S_IRWXO : value; - if (set->cmd2 & CMD2_UBITS) - newmode &= ~((clrval<<6) & set->bits); - if (set->cmd2 & CMD2_GBITS) - newmode &= ~((clrval<<3) & set->bits); - if (set->cmd2 & CMD2_OBITS) - newmode &= ~(clrval & set->bits); - } - if (set->cmd2 & CMD2_SET) { - if (set->cmd2 & CMD2_UBITS) - newmode |= (value<<6) & set->bits; - if (set->cmd2 & CMD2_GBITS) - newmode |= (value<<3) & set->bits; - if (set->cmd2 & CMD2_OBITS) - newmode |= value & set->bits; - } - break; - - case '+': - newmode |= set->bits; - break; - - case '-': - newmode &= ~set->bits; - break; - - case 'X': - if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH)) - newmode |= set->bits; - break; - - case '\0': - default: -#ifdef SETMODE_DEBUG - (void)printf("getmode:%04o -> %04o\n", omode, newmode); -#endif - return (newmode); - } -} - -#define ADDCMD(a, b, c, d) do { \ - if (set >= endset) { \ - BITCMD *newset; \ - setlen += SET_LEN_INCR; \ - newset = realloc(saveset, sizeof(BITCMD) * setlen); \ - if (newset == NULL) { \ - free(saveset); \ - return (NULL); \ - } \ - set = newset + (set - saveset); \ - saveset = newset; \ - endset = newset + (setlen - 2); \ - } \ - set = addcmd(set, (a), (b), (c), (d)); \ -} while (/*CONSTCOND*/0) - -#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) - -static void * -setmode(p) - const char *p; -{ - int perm, who; - char op, *ep; - BITCMD *set, *saveset, *endset; - sigset_t mysigset, sigoset; - mode_t mask; - int equalopdone = 0; /* pacify gcc */ - int permXbits, setlen; - - if (!*p) - return (NULL); - - /* - * Get a copy of the mask for the permissions that are mask relative. - * Flip the bits, we want what's not set. Since it's possible that - * the caller is opening files inside a signal handler, protect them - * as best we can. - */ - sigfillset(&mysigset); - (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset); - (void)umask(mask = umask(0)); - mask = ~mask; - (void)sigprocmask(SIG_SETMASK, &sigoset, NULL); - - setlen = SET_LEN + 2; - - if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL) - return (NULL); - saveset = set; - endset = set + (setlen - 2); - - /* - * If an absolute number, get it and return; disallow non-octal digits - * or illegal bits. - */ - if (is_digit((unsigned char)*p)) { - perm = (mode_t)strtol(p, &ep, 8); - if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) { - free(saveset); - return (NULL); - } - ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask); - set->cmd = 0; - return (saveset); - } - - /* - * Build list of structures to set/clear/copy bits as described by - * each clause of the symbolic mode. - */ - for (;;) { - /* First, find out which bits might be modified. */ - for (who = 0;; ++p) { - switch (*p) { - case 'a': - who |= STANDARD_BITS; - break; - case 'u': - who |= S_ISUID|S_IRWXU; - break; - case 'g': - who |= S_ISGID|S_IRWXG; - break; - case 'o': - who |= S_IRWXO; - break; - default: - goto getop; - } - } - -getop: if ((op = *p++) != '+' && op != '-' && op != '=') { - free(saveset); - return (NULL); - } - if (op == '=') - equalopdone = 0; - - who &= ~S_ISTXT; - for (perm = 0, permXbits = 0;; ++p) { - switch (*p) { - case 'r': - perm |= S_IRUSR|S_IRGRP|S_IROTH; - break; - case 's': - /* - * If specific bits where requested and - * only "other" bits ignore set-id. - */ - if (who == 0 || (who & ~S_IRWXO)) - perm |= S_ISUID|S_ISGID; - break; - case 't': - /* - * If specific bits where requested and - * only "other" bits ignore set-id. - */ - if (who == 0 || (who & ~S_IRWXO)) { - who |= S_ISTXT; - perm |= S_ISTXT; - } - break; - case 'w': - perm |= S_IWUSR|S_IWGRP|S_IWOTH; - break; - case 'X': - permXbits = S_IXUSR|S_IXGRP|S_IXOTH; - break; - case 'x': - perm |= S_IXUSR|S_IXGRP|S_IXOTH; - break; - case 'u': - case 'g': - case 'o': - /* - * When ever we hit 'u', 'g', or 'o', we have - * to flush out any partial mode that we have, - * and then do the copying of the mode bits. - */ - if (perm) { - ADDCMD(op, who, perm, mask); - perm = 0; - } - if (op == '=') - equalopdone = 1; - if (op == '+' && permXbits) { - ADDCMD('X', who, permXbits, mask); - permXbits = 0; - } - ADDCMD(*p, who, op, mask); - break; - - default: - /* - * Add any permissions that we haven't already - * done. - */ - if (perm || (op == '=' && !equalopdone)) { - if (op == '=') - equalopdone = 1; - ADDCMD(op, who, perm, mask); - perm = 0; - } - if (permXbits) { - ADDCMD('X', who, permXbits, mask); - permXbits = 0; - } - goto apply; - } - } - -apply: if (!*p) - break; - if (*p != ',') - goto getop; - ++p; - } - set->cmd = 0; -#ifdef SETMODE_DEBUG - (void)printf("Before compress_mode()\n"); - dumpmode(saveset); -#endif - compress_mode(saveset); -#ifdef SETMODE_DEBUG - (void)printf("After compress_mode()\n"); - dumpmode(saveset); -#endif - return (saveset); -} - -static BITCMD * -addcmd(set, op, who, oparg, mask) - BITCMD *set; - int oparg, who; - int op; - u_int mask; -{ - - _DIAGASSERT(set != NULL); - - switch (op) { - case '=': - set->cmd = '-'; - set->bits = who ? who : STANDARD_BITS; - set++; - - op = '+'; - /* FALLTHROUGH */ - case '+': - case '-': - case 'X': - set->cmd = op; - set->bits = (who ? who : mask) & oparg; - break; - - case 'u': - case 'g': - case 'o': - set->cmd = op; - if (who) { - set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) | - ((who & S_IRGRP) ? CMD2_GBITS : 0) | - ((who & S_IROTH) ? CMD2_OBITS : 0); - set->bits = (mode_t)~0; - } else { - set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS; - set->bits = mask; - } - - if (oparg == '+') - set->cmd2 |= CMD2_SET; - else if (oparg == '-') - set->cmd2 |= CMD2_CLR; - else if (oparg == '=') - set->cmd2 |= CMD2_SET|CMD2_CLR; - break; - } - return (set + 1); -} - -#ifdef SETMODE_DEBUG -static void -dumpmode(set) - BITCMD *set; -{ - - _DIAGASSERT(set != NULL); - - for (; set->cmd; ++set) - (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n", - set->cmd, set->bits, set->cmd2 ? " cmd2:" : "", - set->cmd2 & CMD2_CLR ? " CLR" : "", - set->cmd2 & CMD2_SET ? " SET" : "", - set->cmd2 & CMD2_UBITS ? " UBITS" : "", - set->cmd2 & CMD2_GBITS ? " GBITS" : "", - set->cmd2 & CMD2_OBITS ? " OBITS" : ""); -} -#endif - -/* - * Given an array of bitcmd structures, compress by compacting consecutive - * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u', - * 'g' and 'o' commands continue to be separate. They could probably be - * compacted, but it's not worth the effort. - */ -static void -compress_mode(set) - BITCMD *set; -{ - BITCMD *nset; - int setbits, clrbits, Xbits, op; - - _DIAGASSERT(set != NULL); - - for (nset = set;;) { - /* Copy over any 'u', 'g' and 'o' commands. */ - while ((op = nset->cmd) != '+' && op != '-' && op != 'X') { - *set++ = *nset++; - if (!op) - return; - } - - for (setbits = clrbits = Xbits = 0;; nset++) { - if ((op = nset->cmd) == '-') { - clrbits |= nset->bits; - setbits &= ~nset->bits; - Xbits &= ~nset->bits; - } else if (op == '+') { - setbits |= nset->bits; - clrbits &= ~nset->bits; - Xbits &= ~nset->bits; - } else if (op == 'X') - Xbits |= nset->bits & ~setbits; - else - break; - } - if (clrbits) { - set->cmd = '-'; - set->cmd2 = 0; - set->bits = clrbits; - set++; - } - if (setbits) { - set->cmd = '+'; - set->cmd2 = 0; - set->bits = setbits; - set++; - } - if (Xbits) { - set->cmd = 'X'; - set->cmd2 = 0; - set->bits = Xbits; - set++; - } - } -} -#ifdef DEBUG -static void shtree (union node *, int, char *, FILE*); -static void shcmd (union node *, FILE *); -static void sharg (union node *, FILE *); -static void indent (int, char *, FILE *); -static void trstring (char *); - - -static void -showtree(n) - union node *n; -{ - trputs("showtree called\n"); - shtree(n, 1, NULL, stdout); -} - - -static void -shtree(n, ind, pfx, fp) - union node *n; - int ind; - char *pfx; - FILE *fp; -{ - struct nodelist *lp; - const char *s; - - if (n == NULL) - return; - - indent(ind, pfx, fp); - switch(n->type) { - case NSEMI: - s = "; "; - goto binop; - case NAND: - s = " && "; - goto binop; - case NOR: - s = " || "; -binop: - shtree(n->nbinary.ch1, ind, NULL, fp); - /* if (ind < 0) */ - fputs(s, fp); - shtree(n->nbinary.ch2, ind, NULL, fp); - break; - case NCMD: - shcmd(n, fp); - if (ind >= 0) - putc('\n', fp); - break; - case NPIPE: - for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { - shcmd(lp->n, fp); - if (lp->next) - fputs(" | ", fp); - } - if (n->npipe.backgnd) - fputs(" &", fp); - if (ind >= 0) - putc('\n', fp); - break; - default: - fprintf(fp, "", n->type); - if (ind >= 0) - putc('\n', fp); - break; - } -} - - - -static void -shcmd(cmd, fp) - union node *cmd; - FILE *fp; -{ - union node *np; - int first; - const char *s; - int dftfd; - - first = 1; - for (np = cmd->ncmd.args ; np ; np = np->narg.next) { - if (! first) - putchar(' '); - sharg(np, fp); - first = 0; - } - for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) { - if (! first) - putchar(' '); - switch (np->nfile.type) { - case NTO: s = ">"; dftfd = 1; break; - case NAPPEND: s = ">>"; dftfd = 1; break; - case NTOFD: s = ">&"; dftfd = 1; break; - case NTOOV: s = ">|"; dftfd = 1; break; - case NFROM: s = "<"; dftfd = 0; break; - case NFROMFD: s = "<&"; dftfd = 0; break; - case NFROMTO: s = "<>"; dftfd = 0; break; - default: s = "*error*"; dftfd = 0; break; - } - if (np->nfile.fd != dftfd) - fprintf(fp, "%d", np->nfile.fd); - fputs(s, fp); - if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { - fprintf(fp, "%d", np->ndup.dupfd); - } else { - sharg(np->nfile.fname, fp); - } - first = 0; - } -} - - - -static void -sharg(arg, fp) - union node *arg; - FILE *fp; - { - char *p; - struct nodelist *bqlist; - int subtype; - - if (arg->type != NARG) { - printf("\n", arg->type); - fflush(stdout); - abort(); - } - bqlist = arg->narg.backquote; - for (p = arg->narg.text ; *p ; p++) { - switch (*p) { - case CTLESC: - putc(*++p, fp); - break; - case CTLVAR: - putc('$', fp); - putc('{', fp); - subtype = *++p; - if (subtype == VSLENGTH) - putc('#', fp); - - while (*p != '=') - putc(*p++, fp); - - if (subtype & VSNUL) - putc(':', fp); - - switch (subtype & VSTYPE) { - case VSNORMAL: - putc('}', fp); - break; - case VSMINUS: - putc('-', fp); - break; - case VSPLUS: - putc('+', fp); - break; - case VSQUESTION: - putc('?', fp); - break; - case VSASSIGN: - putc('=', fp); - break; - case VSTRIMLEFT: - putc('#', fp); - break; - case VSTRIMLEFTMAX: - putc('#', fp); - putc('#', fp); - break; - case VSTRIMRIGHT: - putc('%', fp); - break; - case VSTRIMRIGHTMAX: - putc('%', fp); - putc('%', fp); - break; - case VSLENGTH: - break; - default: - printf("", subtype); - } - break; - case CTLENDVAR: - putc('}', fp); - break; - case CTLBACKQ: - case CTLBACKQ|CTLQUOTE: - putc('$', fp); - putc('(', fp); - shtree(bqlist->n, -1, NULL, fp); - putc(')', fp); - break; - default: - putc(*p, fp); - break; - } - } -} - - -static void -indent(amount, pfx, fp) - int amount; - char *pfx; - FILE *fp; -{ - int i; - - for (i = 0 ; i < amount ; i++) { - if (pfx && i == amount - 1) - fputs(pfx, fp); - putc('\t', fp); - } -} -#endif - - - -/* - * Debugging stuff. - */ - - -#ifdef DEBUG -FILE *tracefile; - -#if DEBUG == 2 -static int debug = 1; -#else -static int debug = 0; -#endif - - -static void -trputc(c) - int c; -{ - if (tracefile == NULL) - return; - putc(c, tracefile); - if (c == '\n') - fflush(tracefile); -} - -static void -trace(const char *fmt, ...) -{ - va_list va; - va_start(va, fmt); - if (tracefile != NULL) { - (void) vfprintf(tracefile, fmt, va); - if (strchr(fmt, '\n')) - (void) fflush(tracefile); - } - va_end(va); -} - - -static void -trputs(s) - const char *s; -{ - if (tracefile == NULL) - return; - fputs(s, tracefile); - if (strchr(s, '\n')) - fflush(tracefile); -} - - -static void -trstring(s) - char *s; -{ - char *p; - char c; - - if (tracefile == NULL) - return; - putc('"', tracefile); - for (p = s ; *p ; p++) { - switch (*p) { - case '\n': c = 'n'; goto backslash; - case '\t': c = 't'; goto backslash; - case '\r': c = 'r'; goto backslash; - case '"': c = '"'; goto backslash; - case '\\': c = '\\'; goto backslash; - case CTLESC: c = 'e'; goto backslash; - case CTLVAR: c = 'v'; goto backslash; - case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; - case CTLBACKQ: c = 'q'; goto backslash; - case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; -backslash: putc('\\', tracefile); - putc(c, tracefile); - break; - default: - if (*p >= ' ' && *p <= '~') - putc(*p, tracefile); - else { - putc('\\', tracefile); - putc(*p >> 6 & 03, tracefile); - putc(*p >> 3 & 07, tracefile); - putc(*p & 07, tracefile); - } - break; - } - } - putc('"', tracefile); -} - - -static void -trargs(ap) - char **ap; -{ - if (tracefile == NULL) - return; - while (*ap) { - trstring(*ap++); - if (*ap) - putc(' ', tracefile); - else - putc('\n', tracefile); - } - fflush(tracefile); -} - - -static void -opentrace() { - char s[100]; -#ifdef O_APPEND - int flags; -#endif - - if (!debug) - return; -#ifdef not_this_way - { - char *p; - if ((p = getenv("HOME")) == NULL) { - if (geteuid() == 0) - p = "/"; - else - p = "/tmp"; - } - strcpy(s, p); - strcat(s, "/trace"); - } -#else - strcpy(s, "./trace"); -#endif /* not_this_way */ - if ((tracefile = fopen(s, "a")) == NULL) { - fprintf(stderr, "Can't open %s\n", s); - return; - } -#ifdef O_APPEND - if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) - fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); -#endif - fputs("\nTracing started.\n", tracefile); - fflush(tracefile); -} -#endif /* DEBUG */ - - -/* - * The trap builtin. - */ - -static int -trapcmd(argc, argv) - int argc; - char **argv; -{ - char *action; - char **ap; - int signo; - - if (argc <= 1) { - for (signo = 0 ; signo < NSIG ; signo++) { - if (trap[signo] != NULL) { - char *p; - const char *sn; - - p = single_quote(trap[signo]); - sn = sys_siglist[signo]; - if(sn==NULL) - sn = u_signal_names(0, &signo, 0); - if(sn==NULL) - sn = "???"; - printf("trap -- %s %s\n", p, sn); - stunalloc(p); - } - } - return 0; - } - ap = argv + 1; - if (argc == 2) - action = NULL; - else - action = *ap++; - while (*ap) { - if ((signo = decode_signal(*ap, 0)) < 0) - error("%s: bad trap", *ap); - INTOFF; - if (action) { - if (action[0] == '-' && action[1] == '\0') - action = NULL; - else - action = savestr(action); - } - if (trap[signo]) - ckfree(trap[signo]); - trap[signo] = action; - if (signo != 0) - setsignal(signo); - INTON; - ap++; - } - return 0; -} - - - - - - -/* - * Set the signal handler for the specified signal. The routine figures - * out what it should be set to. - */ - -static void -setsignal(int signo) -{ - int action; - char *t; - struct sigaction act; - - if ((t = trap[signo]) == NULL) - action = S_DFL; - else if (*t != '\0') - action = S_CATCH; - else - action = S_IGN; - if (rootshell && action == S_DFL) { - switch (signo) { - case SIGINT: - if (iflag || minusc || sflag == 0) - action = S_CATCH; - break; - case SIGQUIT: -#ifdef DEBUG - { - - if (debug) - break; - } -#endif - /* FALLTHROUGH */ - case SIGTERM: - if (iflag) - action = S_IGN; - break; -#ifdef JOBS - case SIGTSTP: - case SIGTTOU: - if (mflag) - action = S_IGN; - break; -#endif - } - } - - t = &sigmode[signo - 1]; - if (*t == 0) { - /* - * current setting unknown - */ - if (sigaction(signo, 0, &act) == -1) { - /* - * Pretend it worked; maybe we should give a warning - * here, but other shells don't. We don't alter - * sigmode, so that we retry every time. - */ - return; - } - if (act.sa_handler == SIG_IGN) { - if (mflag && (signo == SIGTSTP || - signo == SIGTTIN || signo == SIGTTOU)) { - *t = S_IGN; /* don't hard ignore these */ - } else - *t = S_HARD_IGN; - } else { - *t = S_RESET; /* force to be set */ - } - } - if (*t == S_HARD_IGN || *t == action) - return; - switch (action) { - case S_CATCH: - act.sa_handler = onsig; - break; - case S_IGN: - act.sa_handler = SIG_IGN; - break; - default: - act.sa_handler = SIG_DFL; - } - *t = action; - act.sa_flags = 0; - sigemptyset(&act.sa_mask); - sigaction(signo, &act, 0); -} - -/* - * Ignore a signal. - */ - -static void -ignoresig(signo) - int signo; -{ - if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { - signal(signo, SIG_IGN); - } - sigmode[signo - 1] = S_HARD_IGN; -} - - -/* - * Signal handler. - */ - -static void -onsig(int signo) -{ - if (signo == SIGINT && trap[SIGINT] == NULL) { - onint(); - return; - } - gotsig[signo - 1] = 1; - pendingsigs++; -} - - -/* - * Called to execute a trap. Perhaps we should avoid entering new trap - * handlers while we are executing a trap handler. - */ - -static void -dotrap(void) -{ - int i; - int savestatus; - - for (;;) { - for (i = 1 ; ; i++) { - if (gotsig[i - 1]) - break; - if (i >= NSIG - 1) - goto done; - } - gotsig[i - 1] = 0; - savestatus=exitstatus; - evalstring(trap[i], 0); - exitstatus=savestatus; - } -done: - pendingsigs = 0; -} - -/* - * Called to exit the shell. - */ - -static void -exitshell(int status) -{ - struct jmploc loc1, loc2; - char *p; - - TRACE(("exitshell(%d) pid=%d\n", status, getpid())); - if (setjmp(loc1.loc)) { - goto l1; - } - if (setjmp(loc2.loc)) { - goto l2; - } - handler = &loc1; - if ((p = trap[0]) != NULL && *p != '\0') { - trap[0] = NULL; - evalstring(p, 0); - } -l1: handler = &loc2; /* probably unnecessary */ - flushall(); -#ifdef JOBS - setjobctl(0); -#endif -l2: _exit(status); - /* NOTREACHED */ -} - -static int decode_signal(const char *string, int minsig) -{ - int signo; - const char *name = u_signal_names(string, &signo, minsig); - - return name ? signo : -1; -} - -static struct var **hashvar (const char *); -static void showvars (const char *, int, int); -static struct var **findvar (struct var **, const char *); - -/* - * Initialize the varable symbol tables and import the environment - */ - -/* - * This routine initializes the builtin variables. It is called when the - * shell is initialized and again when a shell procedure is spawned. - */ - -static void -initvar() { - const struct varinit *ip; - struct var *vp; - struct var **vpp; - - for (ip = varinit ; (vp = ip->var) != NULL ; ip++) { - if ((vp->flags & VEXPORT) == 0) { - vpp = hashvar(ip->text); - vp->next = *vpp; - *vpp = vp; - vp->text = strdup(ip->text); - vp->flags = ip->flags; - vp->func = ip->func; - } - } - /* - * PS1 depends on uid - */ - if ((vps1.flags & VEXPORT) == 0) { - vpp = hashvar("PS1="); - vps1.next = *vpp; - *vpp = &vps1; - vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# "); - vps1.flags = VSTRFIXED|VTEXTFIXED; - } -} - -/* - * Set the value of a variable. The flags argument is ored with the - * flags of the variable. If val is NULL, the variable is unset. - */ - -static void -setvar(name, val, flags) - const char *name, *val; - int flags; -{ - const char *p; - int len; - int namelen; - char *nameeq; - int isbad; - int vallen = 0; - - isbad = 0; - p = name; - if (! is_name(*p)) - isbad = 1; - p++; - for (;;) { - if (! is_in_name(*p)) { - if (*p == '\0' || *p == '=') - break; - isbad = 1; - } - p++; - } - namelen = p - name; - if (isbad) - error("%.*s: bad variable name", namelen, name); - len = namelen + 2; /* 2 is space for '=' and '\0' */ - if (val == NULL) { - flags |= VUNSET; - } else { - len += vallen = strlen(val); - } - INTOFF; - nameeq = ckmalloc(len); - memcpy(nameeq, name, namelen); - nameeq[namelen] = '='; - if (val) { - memcpy(nameeq + namelen + 1, val, vallen + 1); - } else { - nameeq[namelen + 1] = '\0'; - } - setvareq(nameeq, flags); - INTON; -} - - - -/* - * Same as setvar except that the variable and value are passed in - * the first argument as name=value. Since the first argument will - * be actually stored in the table, it should not be a string that - * will go away. - */ - -static void -setvareq(s, flags) - char *s; - int flags; -{ - struct var *vp, **vpp; - - vpp = hashvar(s); - flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); - if ((vp = *findvar(vpp, s))) { - if (vp->flags & VREADONLY) { - size_t len = strchr(s, '=') - s; - error("%.*s: is read only", len, s); - } - INTOFF; - - if (vp->func && (flags & VNOFUNC) == 0) - (*vp->func)(strchr(s, '=') + 1); - - if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) - ckfree(vp->text); - - vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET); - vp->flags |= flags; - vp->text = s; - - /* - * We could roll this to a function, to handle it as - * a regular variable function callback, but why bother? - */ - if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset()))) - chkmail(1); - INTON; - return; - } - /* not found */ - vp = ckmalloc(sizeof (*vp)); - vp->flags = flags; - vp->text = s; - vp->next = *vpp; - vp->func = NULL; - *vpp = vp; -} - - - -/* - * Process a linked list of variable assignments. - */ - -static void -listsetvar(mylist) - struct strlist *mylist; - { - struct strlist *lp; - - INTOFF; - for (lp = mylist ; lp ; lp = lp->next) { - setvareq(savestr(lp->text), 0); - } - INTON; -} - - - -/* - * Find the value of a variable. Returns NULL if not set. - */ - -static const char * -lookupvar(name) - const char *name; - { - struct var *v; - - if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) { - return strchr(v->text, '=') + 1; - } - return NULL; -} - - - -/* - * Search the environment of a builtin command. - */ - -static const char * -bltinlookup(const char *name) -{ - const struct strlist *sp; - - for (sp = cmdenviron ; sp ; sp = sp->next) { - if (varequal(sp->text, name)) - return strchr(sp->text, '=') + 1; - } - return lookupvar(name); -} - - - -/* - * Generate a list of exported variables. This routine is used to construct - * the third argument to execve when executing a program. - */ - -static char ** -environment() { - int nenv; - struct var **vpp; - struct var *vp; - char **env; - char **ep; - - nenv = 0; - for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { - for (vp = *vpp ; vp ; vp = vp->next) - if (vp->flags & VEXPORT) - nenv++; - } - ep = env = stalloc((nenv + 1) * sizeof *env); - for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { - for (vp = *vpp ; vp ; vp = vp->next) - if (vp->flags & VEXPORT) - *ep++ = vp->text; - } - *ep = NULL; - return env; -} - - -/* - * Called when a shell procedure is invoked to clear out nonexported - * variables. It is also necessary to reallocate variables of with - * VSTACK set since these are currently allocated on the stack. - */ - -static void -shprocvar(void) { - struct var **vpp; - struct var *vp, **prev; - - for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { - for (prev = vpp ; (vp = *prev) != NULL ; ) { - if ((vp->flags & VEXPORT) == 0) { - *prev = vp->next; - if ((vp->flags & VTEXTFIXED) == 0) - ckfree(vp->text); - if ((vp->flags & VSTRFIXED) == 0) - ckfree(vp); - } else { - if (vp->flags & VSTACK) { - vp->text = savestr(vp->text); - vp->flags &=~ VSTACK; - } - prev = &vp->next; - } - } - } - initvar(); -} - - - -/* - * Command to list all variables which are set. Currently this command - * is invoked from the set command when the set command is called without - * any variables. - */ - -static int -showvarscmd(argc, argv) - int argc; - char **argv; -{ - showvars(nullstr, VUNSET, VUNSET); - return 0; -} - - - -/* - * The export and readonly commands. - */ - -static int -exportcmd(argc, argv) - int argc; - char **argv; -{ - struct var *vp; - char *name; - const char *p; - int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; - int pflag; - - listsetvar(cmdenviron); - pflag = (nextopt("p") == 'p'); - if (argc > 1 && !pflag) { - while ((name = *argptr++) != NULL) { - if ((p = strchr(name, '=')) != NULL) { - p++; - } else { - if ((vp = *findvar(hashvar(name), name))) { - vp->flags |= flag; - goto found; - } - } - setvar(name, p, flag); -found:; - } - } else { - showvars(argv[0], flag, 0); - } - return 0; -} - - -/* - * The "local" command. - */ - -/* funcnest nonzero if we are currently evaluating a function */ - -static int -localcmd(argc, argv) - int argc; - char **argv; -{ - char *name; - - if (! funcnest) - error("Not in a function"); - while ((name = *argptr++) != NULL) { - mklocal(name); - } - return 0; -} - - -/* - * Make a variable a local variable. When a variable is made local, it's - * value and flags are saved in a localvar structure. The saved values - * will be restored when the shell function returns. We handle the name - * "-" as a special case. - */ - -static void -mklocal(name) - char *name; - { - struct localvar *lvp; - struct var **vpp; - struct var *vp; - - INTOFF; - lvp = ckmalloc(sizeof (struct localvar)); - if (name[0] == '-' && name[1] == '\0') { - char *p; - p = ckmalloc(sizeof optet_vals); - lvp->text = memcpy(p, optet_vals, sizeof optet_vals); - vp = NULL; - } else { - vpp = hashvar(name); - vp = *findvar(vpp, name); - if (vp == NULL) { - if (strchr(name, '=')) - setvareq(savestr(name), VSTRFIXED); - else - setvar(name, NULL, VSTRFIXED); - vp = *vpp; /* the new variable */ - lvp->text = NULL; - lvp->flags = VUNSET; - } else { - lvp->text = vp->text; - lvp->flags = vp->flags; - vp->flags |= VSTRFIXED|VTEXTFIXED; - if (strchr(name, '=')) - setvareq(savestr(name), 0); - } - } - lvp->vp = vp; - lvp->next = localvars; - localvars = lvp; - INTON; -} - - -/* - * Called after a function returns. - */ - -static void -poplocalvars() { - struct localvar *lvp; - struct var *vp; - - while ((lvp = localvars) != NULL) { - localvars = lvp->next; - vp = lvp->vp; - if (vp == NULL) { /* $- saved */ - memcpy(optet_vals, lvp->text, sizeof optet_vals); - ckfree(lvp->text); - } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { - (void)unsetvar(vp->text); - } else { - if ((vp->flags & VTEXTFIXED) == 0) - ckfree(vp->text); - vp->flags = lvp->flags; - vp->text = lvp->text; - } - ckfree(lvp); - } -} - - -static int -setvarcmd(argc, argv) - int argc; - char **argv; -{ - if (argc <= 2) - return unsetcmd(argc, argv); - else if (argc == 3) - setvar(argv[1], argv[2], 0); - else - error("List assignment not implemented"); - return 0; -} - - -/* - * The unset builtin command. We unset the function before we unset the - * variable to allow a function to be unset when there is a readonly variable - * with the same name. - */ - -static int -unsetcmd(argc, argv) - int argc; - char **argv; -{ - char **ap; - int i; - int flg_func = 0; - int flg_var = 0; - int ret = 0; - - while ((i = nextopt("vf")) != '\0') { - if (i == 'f') - flg_func = 1; - else - flg_var = 1; - } - if (flg_func == 0 && flg_var == 0) - flg_var = 1; - - for (ap = argptr; *ap ; ap++) { - if (flg_func) - unsetfunc(*ap); - if (flg_var) - ret |= unsetvar(*ap); - } - return ret; -} - - -/* - * Unset the specified variable. - */ - -static int -unsetvar(const char *s) -{ - struct var **vpp; - struct var *vp; - - vpp = findvar(hashvar(s), s); - vp = *vpp; - if (vp) { - if (vp->flags & VREADONLY) - return (1); - INTOFF; - if (*(strchr(vp->text, '=') + 1) != '\0') - setvar(s, nullstr, 0); - vp->flags &= ~VEXPORT; - vp->flags |= VUNSET; - if ((vp->flags & VSTRFIXED) == 0) { - if ((vp->flags & VTEXTFIXED) == 0) - ckfree(vp->text); - *vpp = vp->next; - ckfree(vp); - } - INTON; - return (0); - } - - return (0); -} - - - -/* - * Find the appropriate entry in the hash table from the name. - */ - -static struct var ** -hashvar(const char *p) -{ - unsigned int hashval; - - hashval = ((unsigned char) *p) << 4; - while (*p && *p != '=') - hashval += (unsigned char) *p++; - return &vartab[hashval % VTABSIZE]; -} - - - -/* - * Returns true if the two strings specify the same varable. The first - * variable name is terminated by '='; the second may be terminated by - * either '=' or '\0'. - */ - -static int -varequal(const char *p, const char *q) -{ - while (*p == *q++) { - if (*p++ == '=') - return 1; - } - if (*p == '=' && *(q - 1) == '\0') - return 1; - return 0; -} - -static void -showvars(const char *myprefix, int mask, int xor) -{ - struct var **vpp; - struct var *vp; - const char *sep = myprefix == nullstr ? myprefix : spcstr; - - for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { - for (vp = *vpp ; vp ; vp = vp->next) { - if ((vp->flags & mask) ^ xor) { - char *p; - int len; - - p = strchr(vp->text, '=') + 1; - len = p - vp->text; - p = single_quote(p); - - printf("%s%s%.*s%s\n", myprefix, sep, len, - vp->text, p); - stunalloc(p); - } - } - } -} - -static struct var ** -findvar(struct var **vpp, const char *name) -{ - for (; *vpp; vpp = &(*vpp)->next) { - if (varequal((*vpp)->text, name)) { - break; - } - } - return vpp; -} - -/* - * Copyright (c) 1999 Herbert Xu - * This file contains code for the times builtin. - * $Id: ash.c,v 1.17.2.3 2001/09/06 17:59:36 andersen Exp $ - */ -static int timescmd (int argc, char **argv) -{ - struct tms buf; - long int clk_tck = sysconf(_SC_CLK_TCK); - - times(&buf); - printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", - (int) (buf.tms_utime / clk_tck / 60), - ((double) buf.tms_utime) / clk_tck, - (int) (buf.tms_stime / clk_tck / 60), - ((double) buf.tms_stime) / clk_tck, - (int) (buf.tms_cutime / clk_tck / 60), - ((double) buf.tms_cutime) / clk_tck, - (int) (buf.tms_cstime / clk_tck / 60), - ((double) buf.tms_cstime) / clk_tck); - return 0; -} - -#ifdef ASH_MATH_SUPPORT -/* The let builtin. */ -int letcmd(int argc, char **argv) -{ - int errcode; - long result=0; - if (argc == 2) { - char *tmp, *expression, p[13]; - expression = strchr(argv[1], '='); - if (!expression) { - /* Cannot use 'error()' here, or the return code - * will be incorrect */ - out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]); - return 0; - } - *expression = '\0'; - tmp = ++expression; - result = arith(tmp, &errcode); - if (errcode < 0) { - /* Cannot use 'error()' here, or the return code - * will be incorrect */ - out2fmt("sh: let: "); - if(errcode == -2) - out2fmt("divide by zero"); - else - out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression); - return 0; - } - snprintf(p, 12, "%ld", result); - setvar(argv[1], savestr(p), 0); - } else if (argc >= 3) - synerror("invalid operand"); - return !result; -} -#endif - - - -/*- - * Copyright (c) 1989, 1991, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * 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. - */ diff --git a/busybox/basename.c b/busybox/basename.c deleted file mode 100644 index c15afd533..000000000 --- a/busybox/basename.c +++ /dev/null @@ -1,52 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini basename implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -/* getopt not needed */ - -#include -#include "busybox.h" -#include - -extern int basename_main(int argc, char **argv) -{ - int m, n; - char *s; - - if ((argc < 2) || (**(argv + 1) == '-')) { - show_usage(); - } - - argv++; - - s = get_last_path_component(*argv); - - if (argc>2) { - argv++; - n = strlen(*argv); - m = strlen(s); - if (m>n && strncmp(s+m-n, *argv, n)==0) - s[m-n] = '\0'; - } - puts(s); - return EXIT_SUCCESS; -} diff --git a/busybox/busybox.c b/busybox/busybox.c deleted file mode 100644 index 33efb5d84..000000000 --- a/busybox/busybox.c +++ /dev/null @@ -1,181 +0,0 @@ -/* vi: set sw=4 ts=4: */ -#include -#include -#include -#include -#include -#include "busybox.h" -#ifdef BB_LOCALE_SUPPORT -#include -#endif - -int been_there_done_that = 0; /* Also used in applets.c */ -const char *applet_name; - -#ifdef BB_FEATURE_INSTALLER -/* - * directory table - * this should be consistent w/ the enum, busybox.h::Location, - * or else... - */ -static char* install_dir[] = { - "/", - "/bin", - "/sbin", - "/usr/bin", - "/usr/sbin", -}; - -/* abstract link() */ -typedef int (*__link_f)(const char *, const char *); - -/* - * Where in the filesystem is this busybox? - * [return] - * malloc'd string w/ full pathname of busybox's location - * NULL on failure - */ -static char *busybox_fullpath() -{ - return xreadlink("/proc/self/exe"); -} - -/* create (sym)links for each applet */ -static void install_links(const char *busybox, int use_symbolic_links) -{ - __link_f Link = link; - - char *fpc; - int i; - int rc; - - if (use_symbolic_links) - Link = symlink; - - for (i = 0; applets[i].name != NULL; i++) { - fpc = concat_path_file( - install_dir[applets[i].location], applets[i].name); - rc = Link(busybox, fpc); - if (rc!=0 && errno!=EEXIST) { - perror_msg("%s", fpc); - } - free(fpc); - } -} - -#endif /* BB_FEATURE_INSTALLER */ - -int main(int argc, char **argv) -{ - const char *s; - - applet_name = argv[0]; - - if (applet_name[0] == '-') - applet_name++; - - for (s = applet_name; *s != '\0';) { - if (*s++ == '/') - applet_name = s; - } - -#ifdef BB_LOCALE_SUPPORT -#ifdef BB_INIT - if(getpid()!=1) /* Do not set locale for `init' */ -#endif - { - setlocale(LC_ALL, ""); - } -#endif - - run_applet_by_name(applet_name, argc, argv); - error_msg_and_die("applet not found"); -} - - -int busybox_main(int argc, char **argv) -{ - int col = 0, len, i; - -#ifdef BB_FEATURE_INSTALLER - /* - * This style of argument parsing doesn't scale well - * in the event that busybox starts wanting more --options. - * If someone has a cleaner approach, by all means implement it. - */ - if (argc > 1 && (strcmp(argv[1], "--install") == 0)) { - int use_symbolic_links = 0; - int rc = 0; - char *busybox; - - /* to use symlinks, or not to use symlinks... */ - if (argc > 2) { - if ((strcmp(argv[2], "-s") == 0)) { - use_symbolic_links = 1; - } - } - - /* link */ - busybox = busybox_fullpath(); - if (busybox) { - install_links(busybox, use_symbolic_links); - free(busybox); - } else { - rc = 1; - } - return rc; - } -#endif /* BB_FEATURE_INSTALLER */ - - argc--; - - /* If we've already been here once, exit now */ - if (been_there_done_that == 1 || argc < 1) { - const struct BB_applet *a = applets; - - fprintf(stderr, "%s\n\n" - "Usage: busybox [function] [arguments]...\n" - " or: [function] [arguments]...\n\n" - "\tBusyBox is a multi-call binary that combines many common Unix\n" - "\tutilities into a single executable. Most people will create a\n" - "\tlink to busybox for each function they wish to use, and BusyBox\n" - "\twill act like whatever it was invoked as.\n" - "\nCurrently defined functions:\n", full_version); - - while (a->name != 0) { - col += - fprintf(stderr, "%s%s", ((col == 0) ? "\t" : ", "), - (a++)->name); - if (col > 60 && a->name != 0) { - fprintf(stderr, ",\n"); - col = 0; - } - } - fprintf(stderr, "\n\n"); - exit(0); - } - - /* Flag that we've been here already */ - been_there_done_that = 1; - - /* Move the command line down a notch */ - len = argv[argc] + strlen(argv[argc]) - argv[1]; - memmove(argv[0], argv[1], len); - memset(argv[0] + len, 0, argv[1] - argv[0]); - - /* Fix up the argv pointers */ - len = argv[1] - argv[0]; - memmove(argv, argv + 1, sizeof(char *) * (argc + 1)); - for (i = 0; i < argc; i++) - argv[i] -= len; - - return (main(argc, argv)); -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/busybox.h b/busybox/busybox.h deleted file mode 100644 index f79dac8c8..000000000 --- a/busybox/busybox.h +++ /dev/null @@ -1,106 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Busybox main internal header 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ -#ifndef _BB_INTERNAL_H_ -#define _BB_INTERNAL_H_ 1 - -#include "Config.h" - -#include -#include -#include -#include - -#define BB_BANNER "BusyBox v" BB_VER " (" BB_BT ")" - -#ifdef DMALLOC -#include "dmalloc.h" -#endif - -#include - - -enum Location { - _BB_DIR_ROOT = 0, - _BB_DIR_BIN, - _BB_DIR_SBIN, - _BB_DIR_USR_BIN, - _BB_DIR_USR_SBIN -}; - -struct BB_applet { - const char* name; - int (*main)(int argc, char** argv); - enum Location location; -}; -/* From busybox.c */ -extern const struct BB_applet applets[]; - -/* Automagically pull in all the applet function prototypes and - * applet usage strings. These are all of the form: - * extern int foo_main(int argc, char **argv); - * extern const char foo_usage[]; - * These are all autogenerated from the set of currently defined applets. - */ -#define PROTOTYPES -#include "applets.h" -#undef PROTOTYPES - -#ifdef BB_FEATURE_BUFFERS_GO_ON_STACK -#define RESERVE_BB_BUFFER(buffer,len) char buffer[len] -#define RESERVE_BB_UBUFFER(buffer,len) unsigned char buffer[len] -#define RELEASE_BB_BUFFER(buffer) ((void)0) -#else -#ifdef BB_FEATURE_BUFFERS_GO_IN_BSS -#define RESERVE_BB_BUFFER(buffer,len) static char buffer[len] -#define RESERVE_BB_UBUFFER(buffer,len) static unsigned char buffer[len] -#define RELEASE_BB_BUFFER(buffer) ((void)0) -#else -#define RESERVE_BB_BUFFER(buffer,len) char *buffer=xmalloc(len) -#define RESERVE_BB_UBUFFER(buffer,len) unsigned char *buffer=xmalloc(len) -#define RELEASE_BB_BUFFER(buffer) free (buffer) -#endif -#endif - - -/* Bit map related macros -- libc5 doens't provide these... sigh. */ -#ifndef setbit -#define NBBY CHAR_BIT -#define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY)) -#define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY))) -#define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY))) -#define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0) -#endif - -#ifndef RB_POWER_OFF -/* Stop system and switch power off if possible. */ -#define RB_POWER_OFF 0x4321fedc -#endif - - -/* Pull in the utility routines from libbb */ -#include "libbb/libbb.h" - - - -#endif /* _BB_INTERNAL_H_ */ diff --git a/busybox/busybox.mkll b/busybox/busybox.mkll deleted file mode 100755 index 4e15e1611..000000000 --- a/busybox/busybox.mkll +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# Make busybox links list file. - -# input $1: full path to Config.h -# input $2: full path to applets.h -# output (stdout): list of pathnames that should be linked to busybox - -# Maintainer: Larry Doolittle - -export LC_ALL=POSIX -export LC_CTYPE=POSIX - -CONFIG_H=${1:-Config.h} -APPLETS_H=${2:-applets.h} -gcc -E -DMAKE_LINKS -include $CONFIG_H $APPLETS_H | - awk '/^[ \t]*LINK/{ - dir=substr($2,8) - gsub("_","/",dir) - if(dir=="/ROOT") dir="" - file=$3 - gsub("\"","",file) - if (file=="busybox") next - print tolower(dir) "/" file - }' diff --git a/busybox/busybox.sh b/busybox/busybox.sh deleted file mode 100755 index 9ab0f4bdb..000000000 --- a/busybox/busybox.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -export LC_ALL=POSIX -export LC_CTYPE=POSIX - -RAW=` \ - $CC -E -dM ${1:-Config.h} | \ - sed -n -e '/^.*BB_FEATURE.*$/d;s/^#define.*\/\1.c/gp;' \ - | tr A-Z a-z | sort -` -test "${RAW}" != "" || exit -if [ -d "$BB_SRC_DIR" ]; then cd $BB_SRC_DIR; fi -# By running $RAW through "ls", we avoid listing -# source files that don't exist. -ls $RAW 2>/dev/null | tr '\n' ' ' - diff --git a/busybox/busybox.spec b/busybox/busybox.spec deleted file mode 100644 index 5cf13ca37..000000000 --- a/busybox/busybox.spec +++ /dev/null @@ -1,44 +0,0 @@ -%define name busybox -%define epoch 0 -%define version 0.60.2.pre -%define release %(date -I | sed -e 's/-/_/g') -%define serial 1 - -Name: %{name} -#Epoch: %{epoch} -Version: %{version} -Release: %{release} -Serial: %{serial} -Copyright: GPL -Group: System/Utilities -Summary: BusyBox is a tiny suite of Unix utilities in a multi-call binary. -URL: http://busybox.lineo.com/ -Source: ftp://oss.lineo.com/busybox/%{name}-%{version}.tar.gz -Buildroot: /var/tmp/%{name}-%{version} -Packager : Erik Andersen - -%Description -BusyBox combines tiny versions of many common UNIX utilities into a single -small executable. It provides minimalist replacements for most of the utilities -you usually find in fileutils, shellutils, findutils, textutils, grep, gzip, -tar, etc. BusyBox provides a fairly complete POSIX environment for any small -or emdedded system. The utilities in BusyBox generally have fewer options then -their full featured GNU cousins; however, the options that are provided behave -very much like their GNU counterparts. - -%Prep -%setup -q -n %{name}-%{version} - -%Build -make - -%Install -rm -rf $RPM_BUILD_ROOT -make PREFIX=$RPM_BUILD_ROOT install - -%Clean -rm -rf $RPM_BUILD_ROOT - -%Files -%defattr(-,root,root) -/ diff --git a/busybox/cat.c b/busybox/cat.c deleted file mode 100644 index aa8528d6a..000000000 --- a/busybox/cat.c +++ /dev/null @@ -1,53 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini Cat implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include "busybox.h" - -extern int cat_main(int argc, char **argv) -{ - int status = EXIT_SUCCESS; - - if (argc == 1) { - print_file(stdin); - return status; - } - - while (--argc > 0) { - if(!(strcmp(*++argv, "-"))) { - print_file(stdin); - } else if (print_file_by_name(*argv) == FALSE) { - status = EXIT_FAILURE; - } - } - return status; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/chgrp.c b/busybox/chgrp.c deleted file mode 100644 index fbc1036a8..000000000 --- a/busybox/chgrp.c +++ /dev/null @@ -1,91 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini chown/chmod/chgrp implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include "busybox.h" - -/* Don't use lchown for libc5 or glibc older then 2.1.x */ -#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1) -#define lchown chown -#endif - - -static long gid; - -static int fileAction(const char *fileName, struct stat *statbuf, void* junk) -{ - if (lchown(fileName, statbuf->st_uid, (gid == -1) ? statbuf->st_gid : gid) == 0) { - return (TRUE); - } - perror(fileName); - return (FALSE); -} - -int chgrp_main(int argc, char **argv) -{ - int opt; - int recursiveFlag = FALSE; - char *p=NULL; - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "R")) > 0) { - switch (opt) { - case 'R': - recursiveFlag = TRUE; - break; - default: - show_usage(); - } - } - - if (argc > optind && argc > 2 && argv[optind]) { - /* Find the selected group */ - gid = strtoul(argv[optind], &p, 10); /* maybe it's already numeric */ - if (argv[optind] == p) - gid = my_getgrnam(argv[optind]); - } else { - error_msg_and_die(too_few_args); - } - - /* Ok, ready to do the deed now */ - while (++optind < argc) { - if (recursive_action (argv[optind], recursiveFlag, FALSE, FALSE, - fileAction, fileAction, NULL) == FALSE) { - return EXIT_FAILURE; - } - } - return EXIT_SUCCESS; - -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/chmod.c b/busybox/chmod.c deleted file mode 100644 index 9139b3f4d..000000000 --- a/busybox/chmod.c +++ /dev/null @@ -1,85 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini chown/chmod/chgrp implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -static int fileAction(const char *fileName, struct stat *statbuf, void* junk) -{ - if (!parse_mode((char *)junk, &(statbuf->st_mode))) - error_msg_and_die("internal error"); - if (chmod(fileName, statbuf->st_mode) == 0) - return (TRUE); - perror(fileName); - return (FALSE); -} - -int chmod_main(int argc, char **argv) -{ - int i; - int opt; - int recursiveFlag = FALSE; - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "R")) > 0) { - switch (opt) { - case 'R': - recursiveFlag = TRUE; - break; - default: - show_usage(); - } - } - - if (argc > optind && argc > 2 && argv[optind]) { - /* Parse the specified mode */ - mode_t mode; - if (parse_mode(argv[optind], &mode) == FALSE) { - error_msg_and_die( "unknown mode: %s", argv[optind]); - } - } else { - error_msg_and_die(too_few_args); - } - - /* Ok, ready to do the deed now */ - for (i = optind + 1; i < argc; i++) { - if (recursive_action (argv[i], recursiveFlag, FALSE, FALSE, fileAction, - fileAction, argv[optind]) == FALSE) { - return EXIT_FAILURE; - } - } - return EXIT_SUCCESS; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/chown.c b/busybox/chown.c deleted file mode 100644 index d1e52deda..000000000 --- a/busybox/chown.c +++ /dev/null @@ -1,113 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini chown/chmod/chgrp implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include "busybox.h" - -/* Don't use lchown for libc5 or 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); - } - perror(fileName); - return (FALSE); -} - -int chown_main(int argc, char **argv) -{ - int opt; - int recursiveFlag = FALSE, - noderefFlag = FALSE; - char *groupName=NULL; - char *p=NULL; - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "Rh")) > 0) { - switch (opt) { - case 'R': - recursiveFlag = TRUE; - break; - case 'h': - noderefFlag = TRUE; - break; - default: - show_usage(); - } - } - - if (noderefFlag) chown_func = lchown; - - if (argc > optind && argc > 2 && argv[optind]) { - /* First, check if there is a group name here */ - groupName = strchr(argv[optind], '.'); - if (groupName == NULL) - groupName = strchr(argv[optind], ':'); - if (groupName) { - *groupName++ = '\0'; - gid = strtoul(groupName, &p, 10); - if (groupName == p) - gid = my_getgrnam(groupName); - } else { - gid = -1; - } - /* Now check for the username */ - uid = strtoul(argv[optind], &p, 10); /* Is is numeric? */ - if (argv[optind] == p) { - uid = my_getpwnam(argv[optind]); - } - } else { - error_msg_and_die(too_few_args); - } - - /* Ok, ready to do the deed now */ - while (++optind < argc) { - if (recursive_action (argv[optind], recursiveFlag, FALSE, FALSE, - fileAction, fileAction, NULL) == FALSE) { - return EXIT_FAILURE; - } - } - return EXIT_SUCCESS; - -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/chroot.c b/busybox/chroot.c deleted file mode 100644 index de6a2ea50..000000000 --- a/busybox/chroot.c +++ /dev/null @@ -1,75 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini chroot implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include "busybox.h" - -int chroot_main(int argc, char **argv) -{ - char *prog; - - if ((argc < 2) || (**(argv + 1) == '-')) { - show_usage(); - } - argc--; - argv++; - - if (chroot(*argv) || (chdir("/"))) { - perror_msg_and_die("cannot change root directory to %s", *argv); - } - - argc--; - argv++; - if (argc >= 1) { - prog = *argv; - execvp(*argv, argv); - } else { -#if defined shell_main && defined BB_FEATURE_SH_STANDALONE_SHELL - char shell[] = "/bin/sh"; - char *shell_argv[2] = { shell, NULL }; - applet_name = shell; - shell_main(1, shell_argv); - return EXIT_SUCCESS; -#else - prog = getenv("SHELL"); - if (!prog) - prog = "/bin/sh"; - execlp(prog, prog, NULL); -#endif - } - perror_msg_and_die("cannot execute %s", prog); - -} - - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/chvt.c b/busybox/chvt.c deleted file mode 100644 index c76e9c780..000000000 --- a/busybox/chvt.c +++ /dev/null @@ -1,43 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * chvt.c - aeb - 940227 - Change virtual terminal - * - * busyboxed by Erik Andersen - */ - -/* getopt not needed */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -/* From */ -static const int VT_ACTIVATE = 0x5606; /* make vt active */ -static const int VT_WAITACTIVE = 0x5607; /* wait for vt active */ - -int chvt_main(int argc, char **argv) -{ - int fd, num; - - if ((argc != 2) || (**(argv + 1) == '-')) - show_usage(); - fd = get_console_fd("/dev/console"); - num = atoi(argv[1]); - if (ioctl(fd, VT_ACTIVATE, num)) - perror_msg_and_die("VT_ACTIVATE"); - if (ioctl(fd, VT_WAITACTIVE, num)) - perror_msg_and_die("VT_WAITACTIVE"); - return EXIT_SUCCESS; -} - - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/clear.c b/busybox/clear.c deleted file mode 100644 index 503bafa16..000000000 --- a/busybox/clear.c +++ /dev/null @@ -1,34 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini clear implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include "busybox.h" - - -extern int clear_main(int argc, char **argv) -{ - printf("\033[H\033[J"); - return EXIT_SUCCESS; -} diff --git a/busybox/cmdedit.c b/busybox/cmdedit.c deleted file mode 100644 index 16ec2f823..000000000 --- a/busybox/cmdedit.c +++ /dev/null @@ -1,1521 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Termios command line History and Editting. - * - * Copyright (c) 1986-2001 may safely be consumed by a BSD or GPL license. - * Written by: Vladimir Oleynik - * - * Used ideas: - * Adam Rogoyski - * Dave Cinege - * Jakub Jelinek (c) 1995 - * Erik Andersen (Majorly adjusted for busybox) - * - * This code is 'as is' with no warranty. - * - * - */ - -/* - Usage and Known bugs: - Terminal key codes are not extensive, and more will probably - need to be added. This version was created on Debian GNU/Linux 2.x. - Delete, Backspace, Home, End, and the arrow keys were tested - to work in an Xterm and console. Ctrl-A also works as Home. - Ctrl-E also works as End. - - Small bugs (simple effect): - - not true viewing if terminal size (x*y symbols) less - size (prompt + editor`s line + 2 symbols) - - not true viewing if length prompt less terminal width - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "busybox.h" - -#ifdef BB_LOCALE_SUPPORT -#define Isprint(c) isprint((c)) -#else -#define Isprint(c) ( (c) >= ' ' && (c) != ((unsigned char)'\233') ) -#endif - -#ifndef TEST - -#define D(x) - -#else - -#define BB_FEATURE_COMMAND_EDITING -#define BB_FEATURE_COMMAND_TAB_COMPLETION -#define BB_FEATURE_COMMAND_USERNAME_COMPLETION -#define BB_FEATURE_NONPRINTABLE_INVERSE_PUT -#define BB_FEATURE_CLEAN_UP - -#define D(x) x - -#endif /* TEST */ - -#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION -#include -#include -#endif - -#ifdef BB_FEATURE_COMMAND_EDITING - -#ifndef BB_FEATURE_COMMAND_TAB_COMPLETION -#undef BB_FEATURE_COMMAND_USERNAME_COMPLETION -#endif - -#if defined(BB_FEATURE_COMMAND_USERNAME_COMPLETION) || defined(BB_FEATURE_SH_FANCY_PROMPT) -#define BB_FEATURE_GETUSERNAME_AND_HOMEDIR -#endif - -#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR -# ifndef TEST -# include "pwd_grp/pwd.h" -# else -# include -# endif /* TEST */ -#endif /* advanced FEATURES */ - - - -struct history { - char *s; - struct history *p; - struct history *n; -}; - -/* Maximum length of the linked list for the command line history */ -static const int MAX_HISTORY = 15; - -/* First element in command line list */ -static struct history *his_front = NULL; - -/* Last element in command line list */ -static struct history *his_end = NULL; - - -#include -#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp) -#define getTermSettings(fd,argp) tcgetattr(fd, argp); - -/* Current termio and the previous termio before starting sh */ -static struct termios initial_settings, new_settings; - - -static -volatile int cmdedit_termw = 80; /* actual terminal width */ -static int history_counter = 0; /* Number of commands in history list */ -static -volatile int handlers_sets = 0; /* Set next bites: */ - -enum { - SET_ATEXIT = 1, /* when atexit() has been called - and get euid,uid,gid to fast compare */ - SET_WCHG_HANDLERS = 2, /* winchg signal handler */ - SET_RESET_TERM = 4, /* if the terminal needs to be reset upon exit */ -}; - - -static int cmdedit_x; /* real x terminal position */ -static int cmdedit_y; /* pseudoreal y terminal position */ -static int cmdedit_prmt_len; /* lenght prompt without colores string */ - -static int cursor; /* required global for signal handler */ -static int len; /* --- "" - - "" - -"- --""-- --""--- */ -static char *command_ps; /* --- "" - - "" - -"- --""-- --""--- */ -static -#ifndef BB_FEATURE_SH_FANCY_PROMPT - const -#endif -char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */ - -#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR -static char *user_buf = ""; -static char *home_pwd_buf = ""; -static int my_euid; -#endif - -#ifdef BB_FEATURE_SH_FANCY_PROMPT -static char *hostname_buf = ""; -static int num_ok_lines = 1; -#endif - - -#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION - -#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR -static int my_euid; -#endif - -static int my_uid; -static int my_gid; - -#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ - -/* It seems that libc5 doesn't know what a sighandler_t is... */ -#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1) -typedef void (*sighandler_t) (int); -#endif - -static void cmdedit_setwidth(int w, int redraw_flg); - -static void win_changed(int nsig) -{ - struct winsize win = { 0, 0, 0, 0 }; - static sighandler_t previous_SIGWINCH_handler; /* for reset */ - - /* emulate || signal call */ - if (nsig == -SIGWINCH || nsig == SIGWINCH) { - ioctl(0, TIOCGWINSZ, &win); - if (win.ws_col > 0) { - cmdedit_setwidth(win.ws_col, nsig == SIGWINCH); - } - } - /* Unix not all standart in recall signal */ - - if (nsig == -SIGWINCH) /* save previous handler */ - previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); - else if (nsig == SIGWINCH) /* signaled called handler */ - signal(SIGWINCH, win_changed); /* set for next call */ - else /* nsig == 0 */ - /* set previous handler */ - signal(SIGWINCH, previous_SIGWINCH_handler); /* reset */ -} - -static void cmdedit_reset_term(void) -{ - if ((handlers_sets & SET_RESET_TERM) != 0) { -/* sparc and other have broken termios support: use old termio handling. */ - setTermSettings(fileno(stdin), (void *) &initial_settings); - handlers_sets &= ~SET_RESET_TERM; - } - if ((handlers_sets & SET_WCHG_HANDLERS) != 0) { - /* reset SIGWINCH handler to previous (default) */ - win_changed(0); - handlers_sets &= ~SET_WCHG_HANDLERS; - } - fflush(stdout); -#ifdef BB_FEATURE_CLEAN_UP - if (his_front) { - struct history *n; - - while (his_front != his_end) { - n = his_front->n; - free(his_front->s); - free(his_front); - his_front = n; - } - } -#endif -} - - -/* special for recount position for scroll and remove terminal margin effect */ -static void cmdedit_set_out_char(int next_char) -{ - - int c = (int)((unsigned char) command_ps[cursor]); - - if (c == 0) - c = ' '; /* destroy end char? */ -#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT - if (!Isprint(c)) { /* Inverse put non-printable characters */ - if (c >= 128) - c -= 128; - if (c < ' ') - c += '@'; - if (c == 127) - c = '?'; - printf("\033[7m%c\033[0m", c); - } else -#endif - putchar(c); - if (++cmdedit_x >= cmdedit_termw) { - /* terminal is scrolled down */ - cmdedit_y++; - cmdedit_x = 0; - - if (!next_char) - next_char = ' '; - /* destroy "(auto)margin" */ - putchar(next_char); - putchar('\b'); - } - cursor++; -} - -/* Move to end line. Bonus: rewrite line from cursor */ -static void input_end(void) -{ - while (cursor < len) - cmdedit_set_out_char(0); -} - -/* Go to the next line */ -static void goto_new_line(void) -{ - input_end(); - if (cmdedit_x) - putchar('\n'); -} - - -static inline void out1str(const char *s) -{ - fputs(s, stdout); -} -static inline void beep(void) -{ - putchar('\007'); -} - -/* Move back one charactor */ -/* special for slow terminal */ -static void input_backward(int num) -{ - if (num > cursor) - num = cursor; - cursor -= num; /* new cursor (in command, not terminal) */ - - if (cmdedit_x >= num) { /* no to up line */ - cmdedit_x -= num; - if (num < 4) - while (num-- > 0) - putchar('\b'); - - else - printf("\033[%dD", num); - } else { - int count_y; - - if (cmdedit_x) { - putchar('\r'); /* back to first terminal pos. */ - num -= cmdedit_x; /* set previous backward */ - } - count_y = 1 + num / cmdedit_termw; - printf("\033[%dA", count_y); - cmdedit_y -= count_y; - /* require forward after uping */ - cmdedit_x = cmdedit_termw * count_y - num; - printf("\033[%dC", cmdedit_x); /* set term cursor */ - } -} - -static void put_prompt(void) -{ - out1str(cmdedit_prompt); - cmdedit_x = cmdedit_prmt_len; /* count real x terminal position */ - cursor = 0; - cmdedit_y = 0; /* new quasireal y */ -} - -#ifndef BB_FEATURE_SH_FANCY_PROMPT -static void parse_prompt(const char *prmt_ptr) -{ - cmdedit_prompt = prmt_ptr; - cmdedit_prmt_len = strlen(prmt_ptr); - put_prompt(); -} -#else -static void parse_prompt(const char *prmt_ptr) -{ - int prmt_len = 0; - int sub_len = 0; - char flg_not_length = '['; - char *prmt_mem_ptr = xcalloc(1, 1); - char *pwd_buf = xgetcwd(0); - char buf2[PATH_MAX + 1]; - char buf[2]; - char c; - char *pbuf; - - if (!pwd_buf) { - pwd_buf=(char *)unknown; - } - - while (*prmt_ptr) { - pbuf = buf; - pbuf[1] = 0; - c = *prmt_ptr++; - if (c == '\\') { - const char *cp = prmt_ptr; - int l; - - c = process_escape_sequence(&prmt_ptr); - if(prmt_ptr==cp) { - if (*cp == 0) - break; - c = *prmt_ptr++; - switch (c) { -#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR - case 'u': - pbuf = user_buf; - break; -#endif - case 'h': - pbuf = hostname_buf; - if (*pbuf == 0) { - pbuf = xcalloc(256, 1); - if (gethostname(pbuf, 255) < 0) { - strcpy(pbuf, "?"); - } else { - char *s = strchr(pbuf, '.'); - - if (s) - *s = 0; - } - hostname_buf = pbuf; - } - break; - case '$': - c = my_euid == 0 ? '#' : '$'; - break; -#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR - case 'w': - pbuf = pwd_buf; - l = strlen(home_pwd_buf); - if (home_pwd_buf[0] != 0 && - strncmp(home_pwd_buf, pbuf, l) == 0 && - (pbuf[l]=='/' || pbuf[l]=='\0') && - strlen(pwd_buf+l) UCHAR_MAX || (pbuf - buf2) < l) { - l--; - break; - } - prmt_ptr++; - } - buf2[l] = 0; - c = (char)strtol(buf2, 0, 16); - if(c==0) - c = '?'; - pbuf = buf; - break; - case '[': case ']': - if (c == flg_not_length) { - flg_not_length = flg_not_length == '[' ? ']' : '['; - continue; - } - break; - } - } - } - if(pbuf == buf) - *pbuf = c; - prmt_len += strlen(pbuf); - prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf); - if (flg_not_length == ']') - sub_len++; - } - if(pwd_buf!=(char *)unknown) - free(pwd_buf); - cmdedit_prompt = prmt_mem_ptr; - cmdedit_prmt_len = prmt_len - sub_len; - put_prompt(); -} -#endif - - -/* draw promt, editor line, and clear tail */ -static void redraw(int y, int back_cursor) -{ - if (y > 0) /* up to start y */ - printf("\033[%dA", y); - putchar('\r'); - put_prompt(); - input_end(); /* rewrite */ - printf("\033[J"); /* destroy tail after cursor */ - input_backward(back_cursor); -} - -/* Delete the char in front of the cursor */ -static void input_delete(void) -{ - int j = cursor; - - if (j == len) - return; - - strcpy(command_ps + j, command_ps + j + 1); - len--; - input_end(); /* rewtite new line */ - cmdedit_set_out_char(0); /* destroy end char */ - input_backward(cursor - j); /* back to old pos cursor */ -} - -/* Delete the char in back of the cursor */ -static void input_backspace(void) -{ - if (cursor > 0) { - input_backward(1); - input_delete(); - } -} - - -/* Move forward one charactor */ -static void input_forward(void) -{ - if (cursor < len) - cmdedit_set_out_char(command_ps[cursor + 1]); -} - - -static void cmdedit_setwidth(int w, int redraw_flg) -{ - cmdedit_termw = cmdedit_prmt_len + 2; - if (w <= cmdedit_termw) { - cmdedit_termw = cmdedit_termw % w; - } - if (w > cmdedit_termw) { - cmdedit_termw = w; - - if (redraw_flg) { - /* new y for current cursor */ - int new_y = (cursor + cmdedit_prmt_len) / w; - - /* redraw */ - redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor); - fflush(stdout); - } - } -} - -static void cmdedit_init(void) -{ - cmdedit_prmt_len = 0; - if ((handlers_sets & SET_WCHG_HANDLERS) == 0) { - /* emulate usage handler to set handler and call yours work */ - win_changed(-SIGWINCH); - handlers_sets |= SET_WCHG_HANDLERS; - } - - if ((handlers_sets & SET_ATEXIT) == 0) { -#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR - struct passwd *entry; - - my_euid = geteuid(); - entry = getpwuid(my_euid); - if (entry) { - user_buf = xstrdup(entry->pw_name); - home_pwd_buf = xstrdup(entry->pw_dir); - } -#endif - -#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION - -#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR - my_euid = geteuid(); -#endif - my_uid = getuid(); - my_gid = getgid(); -#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ - handlers_sets |= SET_ATEXIT; - atexit(cmdedit_reset_term); /* be sure to do this only once */ - } -} - -#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION - -static int is_execute(const struct stat *st) -{ - if ((!my_euid && (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) || - (my_uid == st->st_uid && (st->st_mode & S_IXUSR)) || - (my_gid == st->st_gid && (st->st_mode & S_IXGRP)) || - (st->st_mode & S_IXOTH)) return TRUE; - return FALSE; -} - -#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION - -static char **username_tab_completion(char *ud, int *num_matches) -{ - struct passwd *entry; - int userlen; - char *temp; - - - ud++; /* ~user/... to user/... */ - userlen = strlen(ud); - - if (num_matches == 0) { /* "~/..." or "~user/..." */ - char *sav_ud = ud - 1; - char *home = 0; - - if (*ud == '/') { /* "~/..." */ - home = home_pwd_buf; - } else { - /* "~user/..." */ - temp = strchr(ud, '/'); - *temp = 0; /* ~user\0 */ - entry = getpwnam(ud); - *temp = '/'; /* restore ~user/... */ - ud = temp; - if (entry) - home = entry->pw_dir; - } - if (home) { - if ((userlen + strlen(home) + 1) < BUFSIZ) { - char temp2[BUFSIZ]; /* argument size */ - - /* /home/user/... */ - sprintf(temp2, "%s%s", home, ud); - strcpy(sav_ud, temp2); - } - } - return 0; /* void, result save to argument :-) */ - } else { - /* "~[^/]*" */ - char **matches = (char **) NULL; - int nm = 0; - - setpwent(); - - while ((entry = getpwent()) != NULL) { - /* Null usernames should result in all users as possible completions. */ - if ( /*!userlen || */ !strncmp(ud, entry->pw_name, userlen)) { - - temp = xmalloc(3 + strlen(entry->pw_name)); - sprintf(temp, "~%s/", entry->pw_name); - matches = xrealloc(matches, (nm + 1) * sizeof(char *)); - - matches[nm++] = temp; - } - } - - endpwent(); - (*num_matches) = nm; - return (matches); - } -} -#endif /* BB_FEATURE_COMMAND_USERNAME_COMPLETION */ - -enum { - FIND_EXE_ONLY = 0, - FIND_DIR_ONLY = 1, - FIND_FILE_ONLY = 2, -}; - -static int path_parse(char ***p, int flags) -{ - int npth; - char *tmp; - char *pth; - - /* if not setenv PATH variable, to search cur dir "." */ - if (flags != FIND_EXE_ONLY || (pth = getenv("PATH")) == 0 || - /* PATH= or PATH=: */ - *pth == 0 || (*pth == ':' && *(pth + 1) == 0)) { - return 1; - } - - tmp = pth; - npth = 0; - - for (;;) { - npth++; /* count words is + 1 count ':' */ - tmp = strchr(tmp, ':'); - if (tmp) { - if (*++tmp == 0) - break; /* : */ - } else - break; - } - - *p = xmalloc(npth * sizeof(char *)); - - tmp = pth; - (*p)[0] = xstrdup(tmp); - npth = 1; /* count words is + 1 count ':' */ - - for (;;) { - tmp = strchr(tmp, ':'); - if (tmp) { - (*p)[0][(tmp - pth)] = 0; /* ':' -> '\0' */ - if (*++tmp == 0) - break; /* : */ - } else - break; - (*p)[npth++] = &(*p)[0][(tmp - pth)]; /* p[next]=p[0][&'\0'+1] */ - } - - return npth; -} - -static char *add_quote_for_spec_chars(char *found) -{ - int l = 0; - char *s = xmalloc((strlen(found) + 1) * 2); - - while (*found) { - if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found)) - s[l++] = '\\'; - s[l++] = *found++; - } - s[l] = 0; - return s; -} - -static char **exe_n_cwd_tab_completion(char *command, int *num_matches, - int type) -{ - - char **matches = 0; - DIR *dir; - struct dirent *next; - char dirbuf[BUFSIZ]; - int nm = *num_matches; - struct stat st; - char *path1[1]; - char **paths = path1; - int npaths; - int i; - char *found; - char *pfind = strrchr(command, '/'); - - path1[0] = "."; - - if (pfind == NULL) { - /* no dir, if flags==EXE_ONLY - get paths, else "." */ - npaths = path_parse(&paths, type); - pfind = command; - } else { - /* with dir */ - /* save for change */ - strcpy(dirbuf, command); - /* set dir only */ - dirbuf[(pfind - command) + 1] = 0; -#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION - if (dirbuf[0] == '~') /* ~/... or ~user/... */ - username_tab_completion(dirbuf, 0); -#endif - /* "strip" dirname in command */ - pfind++; - - paths[0] = dirbuf; - npaths = 1; /* only 1 dir */ - } - - for (i = 0; i < npaths; i++) { - - dir = opendir(paths[i]); - if (!dir) /* Don't print an error */ - continue; - - while ((next = readdir(dir)) != NULL) { - char *str_found = next->d_name; - - /* matched ? */ - if (strncmp(str_found, pfind, strlen(pfind))) - continue; - /* not see .name without .match */ - if (*str_found == '.' && *pfind == 0) { - if (*paths[i] == '/' && paths[i][1] == 0 - && str_found[1] == 0) str_found = ""; /* only "/" */ - else - continue; - } - found = concat_path_file(paths[i], str_found); - /* hmm, remover in progress? */ - if (stat(found, &st) < 0) - goto cont; - /* find with dirs ? */ - if (paths[i] != dirbuf) - strcpy(found, next->d_name); /* only name */ - if (S_ISDIR(st.st_mode)) { - /* name is directory */ - str_found = found; - found = concat_path_file(found, ""); - free(str_found); - str_found = add_quote_for_spec_chars(found); - } else { - /* not put found file if search only dirs for cd */ - if (type == FIND_DIR_ONLY) - goto cont; - str_found = add_quote_for_spec_chars(found); - if (type == FIND_FILE_ONLY || - (type == FIND_EXE_ONLY && is_execute(&st) == TRUE)) - strcat(str_found, " "); - } - /* Add it to the list */ - matches = xrealloc(matches, (nm + 1) * sizeof(char *)); - - matches[nm++] = str_found; -cont: - free(found); - } - closedir(dir); - } - if (paths != path1) { - free(paths[0]); /* allocated memory only in first member */ - free(paths); - } - *num_matches = nm; - return (matches); -} - -static int match_compare(const void *a, const void *b) -{ - return strcmp(*(char **) a, *(char **) b); -} - - - -#define QUOT (UCHAR_MAX+1) - -#define collapse_pos(is, in) { \ - memcpy(int_buf+is, int_buf+in, (BUFSIZ+1-is-in)*sizeof(int)); \ - memcpy(pos_buf+is, pos_buf+in, (BUFSIZ+1-is-in)*sizeof(int)); } - -static int find_match(char *matchBuf, int *len_with_quotes) -{ - int i, j; - int command_mode; - int c, c2; - int int_buf[BUFSIZ + 1]; - int pos_buf[BUFSIZ + 1]; - - /* set to integer dimension characters and own positions */ - for (i = 0;; i++) { - int_buf[i] = (int) ((unsigned char) matchBuf[i]); - if (int_buf[i] == 0) { - pos_buf[i] = -1; /* indicator end line */ - break; - } else - pos_buf[i] = i; - } - - /* mask \+symbol and convert '\t' to ' ' */ - for (i = j = 0; matchBuf[i]; i++, j++) - if (matchBuf[i] == '\\') { - collapse_pos(j, j + 1); - int_buf[j] |= QUOT; - i++; -#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT - if (matchBuf[i] == '\t') /* algorithm equivalent */ - int_buf[j] = ' ' | QUOT; -#endif - } -#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT - else if (matchBuf[i] == '\t') - int_buf[j] = ' '; -#endif - - /* mask "symbols" or 'symbols' */ - c2 = 0; - for (i = 0; int_buf[i]; i++) { - c = int_buf[i]; - if (c == '\'' || c == '"') { - if (c2 == 0) - c2 = c; - else { - if (c == c2) - c2 = 0; - else - int_buf[i] |= QUOT; - } - } else if (c2 != 0 && c != '$') - int_buf[i] |= QUOT; - } - - /* skip commands with arguments if line have commands delimiters */ - /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */ - for (i = 0; int_buf[i]; i++) { - c = int_buf[i]; - c2 = int_buf[i + 1]; - j = i ? int_buf[i - 1] : -1; - command_mode = 0; - if (c == ';' || c == '&' || c == '|') { - command_mode = 1 + (c == c2); - if (c == '&') { - if (j == '>' || j == '<') - command_mode = 0; - } else if (c == '|' && j == '>') - command_mode = 0; - } - if (command_mode) { - collapse_pos(0, i + command_mode); - i = -1; /* hack incremet */ - } - } - /* collapse `command...` */ - for (i = 0; int_buf[i]; i++) - if (int_buf[i] == '`') { - for (j = i + 1; int_buf[j]; j++) - if (int_buf[j] == '`') { - collapse_pos(i, j + 1); - j = 0; - break; - } - if (j) { - /* not found close ` - command mode, collapse all previous */ - collapse_pos(0, i + 1); - break; - } else - i--; /* hack incremet */ - } - - /* collapse (command...(command...)...) or {command...{command...}...} */ - c = 0; /* "recursive" level */ - c2 = 0; - for (i = 0; int_buf[i]; i++) - if (int_buf[i] == '(' || int_buf[i] == '{') { - if (int_buf[i] == '(') - c++; - else - c2++; - collapse_pos(0, i + 1); - i = -1; /* hack incremet */ - } - for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++) - if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) { - if (int_buf[i] == ')') - c--; - else - c2--; - collapse_pos(0, i + 1); - i = -1; /* hack incremet */ - } - - /* skip first not quote space */ - for (i = 0; int_buf[i]; i++) - if (int_buf[i] != ' ') - break; - if (i) - collapse_pos(0, i); - - /* set find mode for completion */ - command_mode = FIND_EXE_ONLY; - for (i = 0; int_buf[i]; i++) - if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') { - if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY - && matchBuf[pos_buf[0]]=='c' - && matchBuf[pos_buf[1]]=='d' ) - command_mode = FIND_DIR_ONLY; - else { - command_mode = FIND_FILE_ONLY; - break; - } - } - /* "strlen" */ - for (i = 0; int_buf[i]; i++); - /* find last word */ - for (--i; i >= 0; i--) { - c = int_buf[i]; - if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') { - collapse_pos(0, i + 1); - break; - } - } - /* skip first not quoted '\'' or '"' */ - for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++); - /* collapse quote or unquote // or /~ */ - while ((int_buf[i] & ~QUOT) == '/' && - ((int_buf[i + 1] & ~QUOT) == '/' - || (int_buf[i + 1] & ~QUOT) == '~')) { - i++; - } - - /* set only match and destroy quotes */ - j = 0; - for (c = 0; pos_buf[i] >= 0; i++) { - matchBuf[c++] = matchBuf[pos_buf[i]]; - j = pos_buf[i] + 1; - } - matchBuf[c] = 0; - /* old lenght matchBuf with quotes symbols */ - *len_with_quotes = j ? j - pos_buf[0] : 0; - - return command_mode; -} - - -static void input_tab(int *lastWasTab) -{ - /* Do TAB completion */ - static int num_matches; - static char **matches; - - if (lastWasTab == 0) { /* free all memory */ - if (matches) { - while (num_matches > 0) - free(matches[--num_matches]); - free(matches); - matches = (char **) NULL; - } - return; - } - if (*lastWasTab == FALSE) { - - char *tmp; - int len_found; - char matchBuf[BUFSIZ]; - int find_type; - int recalc_pos; - - *lastWasTab = TRUE; /* flop trigger */ - - /* Make a local copy of the string -- up - * to the position of the cursor */ - tmp = strncpy(matchBuf, command_ps, cursor); - tmp[cursor] = 0; - - find_type = find_match(matchBuf, &recalc_pos); - - /* Free up any memory already allocated */ - input_tab(0); - -#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION - /* If the word starts with `~' and there is no slash in the word, - * then try completing this word as a username. */ - - if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0) - matches = username_tab_completion(matchBuf, &num_matches); -#endif - /* Try to match any executable in our path and everything - * in the current working directory that matches. */ - if (!matches) - matches = - exe_n_cwd_tab_completion(matchBuf, - &num_matches, find_type); - /* Remove duplicate found */ - if(matches) { - int i, j; - /* bubble */ - for(i=0; i<(num_matches-1); i++) - for(j=i+1; j 1) { - char *tmp1; - - beep(); - if (!matches) - return; /* not found */ - /* sort */ - qsort(matches, num_matches, sizeof(char *), match_compare); - - /* find minimal match */ - tmp = xstrdup(matches[0]); - for (tmp1 = tmp; *tmp1; tmp1++) - for (len_found = 1; len_found < num_matches; len_found++) - if (matches[len_found][(tmp1 - tmp)] != *tmp1) { - *tmp1 = 0; - break; - } - if (*tmp == 0) { /* have unique */ - free(tmp); - return; - } - } else { /* one match */ - tmp = matches[0]; - /* for next completion current found */ - *lastWasTab = FALSE; - } - - len_found = strlen(tmp); - /* have space to placed match? */ - if ((len_found - strlen(matchBuf) + len) < BUFSIZ) { - - /* before word for match */ - command_ps[cursor - recalc_pos] = 0; - /* save tail line */ - strcpy(matchBuf, command_ps + cursor); - /* add match */ - strcat(command_ps, tmp); - /* add tail */ - strcat(command_ps, matchBuf); - /* back to begin word for match */ - input_backward(recalc_pos); - /* new pos */ - recalc_pos = cursor + len_found; - /* new len */ - len = strlen(command_ps); - /* write out the matched command */ - redraw(cmdedit_y, len - recalc_pos); - } - if (tmp != matches[0]) - free(tmp); - } else { - /* Ok -- the last char was a TAB. Since they - * just hit TAB again, print a list of all the - * available choices... */ - if (matches && num_matches > 0) { - int i, col, l; - int sav_cursor = cursor; /* change goto_new_line() */ - - /* Go to the next line */ - goto_new_line(); - for (i = 0, col = 0; i < num_matches; i++) { - l = strlen(matches[i]); - if (l < 14) - l = 14; - printf("%-14s ", matches[i]); - if ((l += 2) > 16) - while (l % 16) { - putchar(' '); - l++; - } - col += l; - col -= (col / cmdedit_termw) * cmdedit_termw; - if (col > 60 && matches[i + 1] != NULL) { - putchar('\n'); - col = 0; - } - } - /* Go to the next line and rewrite */ - putchar('\n'); - redraw(0, len - sav_cursor); - } - } -} -#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ - -static void get_previous_history(struct history **hp, struct history *p) -{ - if ((*hp)->s) - free((*hp)->s); - (*hp)->s = xstrdup(command_ps); - *hp = p; -} - -static inline void get_next_history(struct history **hp) -{ - get_previous_history(hp, (*hp)->n); -} - -enum { - ESC = 27, - DEL = 127, -}; - - -/* - * This function is used to grab a character buffer - * from the input file descriptor and allows you to - * a string with full command editing (sortof like - * a mini readline). - * - * The following standard commands are not implemented: - * ESC-b -- Move back one word - * ESC-f -- Move forward one word - * ESC-d -- Delete back one word - * ESC-h -- Delete forward one word - * CTL-t -- Transpose two characters - * - * Furthermore, the "vi" command editing keys are not implemented. - * - */ - - -int cmdedit_read_input(char *prompt, char command[BUFSIZ]) -{ - - int break_out = 0; - int lastWasTab = FALSE; - unsigned char c = 0; - struct history *hp = his_end; - - /* prepare before init handlers */ - cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ - len = 0; - command_ps = command; - - getTermSettings(0, (void *) &initial_settings); - memcpy(&new_settings, &initial_settings, sizeof(struct termios)); - new_settings.c_lflag &= ~ICANON; /* unbuffered input */ - /* Turn off echoing and CTRL-C, so we can trap it */ - new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG); -#ifndef linux - /* Hmm, in linux c_cc[] not parsed if set ~ICANON */ - new_settings.c_cc[VMIN] = 1; - new_settings.c_cc[VTIME] = 0; - /* Turn off CTRL-C, so we can trap it */ -# ifndef _POSIX_VDISABLE -# define _POSIX_VDISABLE '\0' -# endif - new_settings.c_cc[VINTR] = _POSIX_VDISABLE; -#endif - command[0] = 0; - - setTermSettings(0, (void *) &new_settings); - handlers_sets |= SET_RESET_TERM; - - /* Now initialize things */ - cmdedit_init(); - /* Print out the command prompt */ - parse_prompt(prompt); - - while (1) { - - fflush(stdout); /* buffered out to fast */ - - if (safe_read(0, &c, 1) < 1) - /* if we can't read input then exit */ - goto prepare_to_die; - - switch (c) { - case '\n': - case '\r': - /* Enter */ - goto_new_line(); - break_out = 1; - break; - case 1: - /* Control-a -- Beginning of line */ - input_backward(cursor); - break; - case 2: - /* Control-b -- Move back one character */ - input_backward(1); - break; - case 3: - /* Control-c -- stop gathering input */ - goto_new_line(); - command[0] = 0; - len = 0; - lastWasTab = FALSE; - put_prompt(); - break; - case 4: - /* Control-d -- Delete one character, or exit - * if the len=0 and no chars to delete */ - if (len == 0) { -prepare_to_die: -#if !defined(BB_ASH) - printf("exit"); - goto_new_line(); - /* cmdedit_reset_term() called in atexit */ - exit(EXIT_SUCCESS); -#else - break_out = -1; /* for control stoped jobs */ - break; -#endif - } else { - input_delete(); - } - break; - case 5: - /* Control-e -- End of line */ - input_end(); - break; - case 6: - /* Control-f -- Move forward one character */ - input_forward(); - break; - case '\b': - case DEL: - /* Control-h and DEL */ - input_backspace(); - break; - case '\t': -#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION - input_tab(&lastWasTab); -#endif - break; - case 14: - /* Control-n -- Get next command in history */ - if (hp && hp->n && hp->n->s) { - get_next_history(&hp); - goto rewrite_line; - } else { - beep(); - } - break; - case 16: - /* Control-p -- Get previous command from history */ - if (hp && hp->p) { - get_previous_history(&hp, hp->p); - goto rewrite_line; - } else { - beep(); - } - break; - case 21: - /* Control-U -- Clear line before cursor */ - if (cursor) { - strcpy(command, command + cursor); - redraw(cmdedit_y, len -= cursor); - } - break; - - case ESC:{ - /* escape sequence follows */ - if (safe_read(0, &c, 1) < 1) - goto prepare_to_die; - /* different vt100 emulations */ - if (c == '[' || c == 'O') { - if (safe_read(0, &c, 1) < 1) - goto prepare_to_die; - } - switch (c) { -#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION - case '\t': /* Alt-Tab */ - - input_tab(&lastWasTab); - break; -#endif - case 'A': - /* Up Arrow -- Get previous command from history */ - if (hp && hp->p) { - get_previous_history(&hp, hp->p); - goto rewrite_line; - } else { - beep(); - } - break; - case 'B': - /* Down Arrow -- Get next command in history */ - if (hp && hp->n && hp->n->s) { - get_next_history(&hp); - goto rewrite_line; - } else { - beep(); - } - break; - - /* Rewrite the line with the selected history item */ - rewrite_line: - /* change command */ - len = strlen(strcpy(command, hp->s)); - /* redraw and go to end line */ - redraw(cmdedit_y, 0); - break; - case 'C': - /* Right Arrow -- Move forward one character */ - input_forward(); - break; - case 'D': - /* Left Arrow -- Move back one character */ - input_backward(1); - break; - case '3': - /* Delete */ - input_delete(); - break; - case '1': - case 'H': - /* Home (Ctrl-A) */ - input_backward(cursor); - break; - case '4': - case 'F': - /* End (Ctrl-E) */ - input_end(); - break; - default: - if (!(c >= '1' && c <= '9')) - c = 0; - beep(); - } - if (c >= '1' && c <= '9') - do - if (safe_read(0, &c, 1) < 1) - goto prepare_to_die; - while (c != '~'); - break; - } - - default: /* If it's regular input, do the normal thing */ -#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT - /* Control-V -- Add non-printable symbol */ - if (c == 22) { - if (safe_read(0, &c, 1) < 1) - goto prepare_to_die; - if (c == 0) { - beep(); - break; - } - } else -#endif - if (!Isprint(c)) /* Skip non-printable characters */ - break; - - if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ - break; - - len++; - - if (cursor == (len - 1)) { /* Append if at the end of the line */ - *(command + cursor) = c; - *(command + cursor + 1) = 0; - cmdedit_set_out_char(0); - } else { /* Insert otherwise */ - int sc = cursor; - - memmove(command + sc + 1, command + sc, len - sc); - *(command + sc) = c; - sc++; - /* rewrite from cursor */ - input_end(); - /* to prev x pos + 1 */ - input_backward(cursor - sc); - } - - break; - } - if (break_out) /* Enter is the command terminator, no more input. */ - break; - - if (c != '\t') - lastWasTab = FALSE; - } - - setTermSettings(0, (void *) &initial_settings); - handlers_sets &= ~SET_RESET_TERM; - - /* Handle command history log */ - if (len) { /* no put empty line */ - - struct history *h = his_end; - char *ss; - - ss = xstrdup(command); /* duplicate */ - - if (h == 0) { - /* No previous history -- this memory is never freed */ - h = his_front = xmalloc(sizeof(struct history)); - h->n = xmalloc(sizeof(struct history)); - - h->p = NULL; - h->s = ss; - h->n->p = h; - h->n->n = NULL; - h->n->s = NULL; - his_end = h->n; - history_counter++; - } else { - /* Add a new history command -- this memory is never freed */ - h->n = xmalloc(sizeof(struct history)); - - h->n->p = h; - h->n->n = NULL; - h->n->s = NULL; - h->s = ss; - his_end = h->n; - - /* After max history, remove the oldest command */ - if (history_counter >= MAX_HISTORY) { - - struct history *p = his_front->n; - - p->p = NULL; - free(his_front->s); - free(his_front); - his_front = p; - } else { - history_counter++; - } - } -#if defined(BB_FEATURE_SH_FANCY_PROMPT) - num_ok_lines++; -#endif - } - if(break_out>0) { - command[len++] = '\n'; /* set '\n' */ - command[len] = 0; - } -#if defined(BB_FEATURE_CLEAN_UP) && defined(BB_FEATURE_COMMAND_TAB_COMPLETION) - input_tab(0); /* strong free */ -#endif -#if defined(BB_FEATURE_SH_FANCY_PROMPT) - free(cmdedit_prompt); -#endif - cmdedit_reset_term(); - return len; -} - - - -#endif /* BB_FEATURE_COMMAND_EDITING */ - - -#ifdef TEST - -const char *applet_name = "debug stuff usage"; -const char *memory_exhausted = "Memory exhausted"; - -#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT -#include -#endif - -int main(int argc, char **argv) -{ - char buff[BUFSIZ]; - char *prompt = -#if defined(BB_FEATURE_SH_FANCY_PROMPT) - "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:\ -\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \ -\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]"; -#else - "% "; -#endif - -#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT - setlocale(LC_ALL, ""); -#endif - while(1) { - int l; - cmdedit_read_input(prompt, buff); - l = strlen(buff); - if(l==0) - break; - if(l > 0 && buff[l-1] == '\n') - buff[l-1] = 0; - printf("*** cmdedit_read_input() returned line =%s=\n", buff); - } - printf("*** cmdedit_read_input() detect ^C\n"); - return 0; -} - -#endif /* TEST */ diff --git a/busybox/cmdedit.h b/busybox/cmdedit.h deleted file mode 100644 index 83893572a..000000000 --- a/busybox/cmdedit.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef CMDEDIT_H -#define CMDEDIT_H - -int cmdedit_read_input(char* promptStr, char* command); - -#endif /* CMDEDIT_H */ diff --git a/busybox/cmp.c b/busybox/cmp.c deleted file mode 100644 index 6d579461d..000000000 --- a/busybox/cmp.c +++ /dev/null @@ -1,80 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini cmp implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -int cmp_main(int argc, char **argv) -{ - FILE *fp1 = NULL, *fp2 = stdin; - char *filename1, *filename2 = "-"; - int c, c1, c2, char_pos = 1, line_pos = 1, silent = FALSE; - - while ((c = getopt(argc, argv, "s")) != EOF) { - switch (c) { - case 's': - silent = TRUE; - break; - default: - show_usage(); - } - } - - filename1 = argv[optind]; - switch (argc - optind) { - case 2: - fp2 = xfopen(filename2 = argv[optind + 1], "r"); - case 1: - fp1 = xfopen(filename1, "r"); - break; - default: - show_usage(); - } - - do { - c1 = fgetc(fp1); - c2 = fgetc(fp2); - if (c1 != c2) { - if (silent) - return EXIT_FAILURE; - if (c1 == EOF) - printf("EOF on %s\n", filename1); - else if (c2 == EOF) - printf("EOF on %s\n", filename2); - else - printf("%s %s differ: char %d, line %d\n", filename1, filename2, - char_pos, line_pos); - return EXIT_FAILURE; - } - char_pos++; - if (c1 == '\n') - line_pos++; - } while (c1 != EOF); - - return EXIT_SUCCESS; -} diff --git a/busybox/console-tools/chvt.c b/busybox/console-tools/chvt.c deleted file mode 100644 index c76e9c780..000000000 --- a/busybox/console-tools/chvt.c +++ /dev/null @@ -1,43 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * chvt.c - aeb - 940227 - Change virtual terminal - * - * busyboxed by Erik Andersen - */ - -/* getopt not needed */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -/* From */ -static const int VT_ACTIVATE = 0x5606; /* make vt active */ -static const int VT_WAITACTIVE = 0x5607; /* wait for vt active */ - -int chvt_main(int argc, char **argv) -{ - int fd, num; - - if ((argc != 2) || (**(argv + 1) == '-')) - show_usage(); - fd = get_console_fd("/dev/console"); - num = atoi(argv[1]); - if (ioctl(fd, VT_ACTIVATE, num)) - perror_msg_and_die("VT_ACTIVATE"); - if (ioctl(fd, VT_WAITACTIVE, num)) - perror_msg_and_die("VT_WAITACTIVE"); - return EXIT_SUCCESS; -} - - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/console-tools/clear.c b/busybox/console-tools/clear.c deleted file mode 100644 index 503bafa16..000000000 --- a/busybox/console-tools/clear.c +++ /dev/null @@ -1,34 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini clear implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include "busybox.h" - - -extern int clear_main(int argc, char **argv) -{ - printf("\033[H\033[J"); - return EXIT_SUCCESS; -} diff --git a/busybox/console-tools/deallocvt.c b/busybox/console-tools/deallocvt.c deleted file mode 100644 index 15cd0c9b9..000000000 --- a/busybox/console-tools/deallocvt.c +++ /dev/null @@ -1,43 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * disalloc.c - aeb - 940501 - Disallocate virtual terminal(s) - * Renamed deallocvt. - */ -#include -#include -#include -#include -#include -#include "busybox.h" - -/* From */ -static const int VT_DISALLOCATE = 0x5608; /* free memory associated to vt */ - -int deallocvt_main(int argc, char *argv[]) -{ - int fd, num, i; - - //if ((argc > 2) || ((argv == 2) && (**(argv + 1) == '-'))) - if (argc > 2) - show_usage(); - - fd = get_console_fd("/dev/console"); - - if (argc == 1) { - /* deallocate all unused consoles */ - if (ioctl(fd, VT_DISALLOCATE, 0)) - perror_msg_and_die("VT_DISALLOCATE"); - } else { - for (i = 1; i < argc; i++) { - num = atoi(argv[i]); - if (num == 0) - error_msg("0: illegal VT number"); - else if (num == 1) - error_msg("VT 1 cannot be deallocated"); - else if (ioctl(fd, VT_DISALLOCATE, num)) - perror_msg_and_die("VT_DISALLOCATE"); - } - } - - return EXIT_SUCCESS; -} diff --git a/busybox/console-tools/dumpkmap.c b/busybox/console-tools/dumpkmap.c deleted file mode 100644 index 22652a5e2..000000000 --- a/busybox/console-tools/dumpkmap.c +++ /dev/null @@ -1,95 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini dumpkmap implementation for busybox - * - * Copyright (C) Arne Bernin - * - * 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 "busybox.h" - -/* From */ -struct kbentry { - unsigned char kb_table; - unsigned char kb_index; - unsigned short kb_value; -}; -static const int KDGKBENT = 0x4B46; /* gets one entry in translation table */ - -/* From */ -static const int NR_KEYS = 128; -static const int MAX_NR_KEYMAPS = 256; - -int dumpkmap_main(int argc, char **argv) -{ - struct kbentry ke; - int i, j, fd; - char flags[MAX_NR_KEYMAPS], magic[] = "bkeymap"; - - if (argc>=2 && *argv[1]=='-') { - show_usage(); - } - - fd = open(CURRENT_VC, O_RDWR); - if (fd < 0) { - perror_msg("Error opening " CURRENT_VC); - return EXIT_FAILURE; - } - - write(1, magic, 7); - - for (i=0; i < MAX_NR_KEYMAPS; i++) flags[i]=0; - flags[0]=1; - flags[1]=1; - flags[2]=1; - flags[4]=1; - flags[5]=1; - flags[6]=1; - flags[8]=1; - flags[9]=1; - flags[10]=1; - flags[12]=1; - - /* dump flags */ - for (i=0; i < MAX_NR_KEYMAPS; i++) write(1,&flags[i],1); - - for (i = 0; i < MAX_NR_KEYMAPS; i++) { - if (flags[i] == 1) { - for (j = 0; j < NR_KEYS; j++) { - ke.kb_index = j; - ke.kb_table = i; - if (ioctl(fd, KDGKBENT, &ke) < 0) { - - error_msg("ioctl returned: %s, %s, %s, %xqq", strerror(errno),(char *)&ke.kb_index,(char *)&ke.kb_table,(int)&ke.kb_value); - } - else { - write(1,(void*)&ke.kb_value,2); - } - - } - } - } - close(fd); - return EXIT_SUCCESS; -} diff --git a/busybox/console-tools/loadacm.c b/busybox/console-tools/loadacm.c deleted file mode 100644 index 3fb4e7665..000000000 --- a/busybox/console-tools/loadacm.c +++ /dev/null @@ -1,357 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Derived from - * mapscrn.c - version 0.92 - * - * Was taken from console-tools and adapted by - * Peter Novodvorsky - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -typedef unsigned short unicode; - -static long int ctoi(unsigned char *s, int *is_unicode); -static int old_screen_map_read_ascii(FILE * fp, unsigned char buf[]); -static int uni_screen_map_read_ascii(FILE * fp, unicode buf[], int *is_unicode); -static unicode utf8_to_ucs2(char *buf); -static int screen_map_load(int fd, FILE * fp); - -int loadacm_main(int argc, char **argv) -{ - int fd; - - if (argc>=2 && *argv[1]=='-') { - show_usage(); - } - - fd = open(CURRENT_VC, O_RDWR); - if (fd < 0) { - perror_msg_and_die("Error opening " CURRENT_VC); - } - - if (screen_map_load(fd, stdin)) { - perror_msg_and_die("Error loading acm"); - } - - write(fd, "\033(K", 3); - - return EXIT_SUCCESS; -} - -static int screen_map_load(int fd, FILE * fp) -{ - struct stat stbuf; - unicode wbuf[E_TABSZ]; - unsigned char buf[E_TABSZ]; - int parse_failed = 0; - int is_unicode; - - if (fstat(fileno(fp), &stbuf)) - perror_msg_and_die("Cannot stat map file"); - - /* first try a UTF screen-map: either ASCII (no restriction) or binary (regular file) */ - if (! - (parse_failed = - (-1 == uni_screen_map_read_ascii(fp, wbuf, &is_unicode))) -|| (S_ISREG(stbuf.st_mode) && (stbuf.st_size == (sizeof(unicode) * E_TABSZ)))) { /* test for binary UTF map by size */ - if (parse_failed) { - if (-1 == fseek(fp, 0, SEEK_SET)) { - if (errno == ESPIPE) - error_msg_and_die("16bit screen-map MUST be a regular file."); - else - perror_msg_and_die("fseek failed reading binary 16bit screen-map"); - } - - if (fread(wbuf, sizeof(unicode) * E_TABSZ, 1, fp) != 1) - perror_msg_and_die("Cannot read [new] map from file"); -#if 0 - else - error_msg("Input screen-map is binary."); -#endif - } - - /* if it was effectively a 16-bit ASCII, OK, else try to read as 8-bit map */ - /* same if it was binary, ie. if parse_failed */ - if (parse_failed || is_unicode) { - if (ioctl(fd, PIO_UNISCRNMAP, wbuf)) - perror_msg_and_die("PIO_UNISCRNMAP ioctl"); - else - return 0; - } - } - - /* rewind... */ - if (-1 == fseek(fp, 0, SEEK_SET)) { - if (errno == ESPIPE) - error_msg("Assuming 8bit screen-map - MUST be a regular file."), - exit(1); - else - perror_msg_and_die("fseek failed assuming 8bit screen-map"); - } - - /* ... and try an old 8-bit screen-map */ - if (!(parse_failed = (-1 == old_screen_map_read_ascii(fp, buf))) || - (S_ISREG(stbuf.st_mode) && (stbuf.st_size == E_TABSZ))) { /* test for binary old 8-bit map by size */ - if (parse_failed) { - if (-1 == fseek(fp, 0, SEEK_SET)) { - if (errno == ESPIPE) - /* should not - it succedeed above */ - error_msg_and_die("fseek() returned ESPIPE !"); - else - perror_msg_and_die("fseek for binary 8bit screen-map"); - } - - if (fread(buf, E_TABSZ, 1, fp) != 1) - perror_msg_and_die("Cannot read [old] map from file"); -#if 0 - else - error_msg("Input screen-map is binary."); -#endif - } - - if (ioctl(fd, PIO_SCRNMAP, buf)) - perror_msg_and_die("PIO_SCRNMAP ioctl"); - else - return 0; - } - error_msg("Error parsing symbolic map"); - return(1); -} - - -/* - * - reads `fp' as a 16-bit ASCII SFM file. - * - returns -1 on error. - * - returns it in `unicode' in an E_TABSZ-elements array. - * - sets `*is_unicode' flagiff there were any non-8-bit - * (ie. real 16-bit) mapping. - * - * FIXME: ignores everything after second word - */ -static int uni_screen_map_read_ascii(FILE * fp, unicode buf[], int *is_unicode) -{ - char buffer[256]; /* line buffer reading file */ - char *p, *q; /* 1st + 2nd words in line */ - int in, on; /* the same, as numbers */ - int tmp_is_unicode; /* tmp for is_unicode calculation */ - int i; /* loop index - result holder */ - int ret_code = 0; /* return code */ - sigset_t acmsigset, old_sigset; - - assert(is_unicode); - - *is_unicode = 0; - - /* first 128 codes defaults to ASCII */ - for (i = 0; i < 128; i++) - buf[i] = i; - /* remaining defaults to replacement char (usually E_TABSZ = 256) */ - for (; i < E_TABSZ; i++) - buf[i] = 0xfffd; - - /* block SIGCHLD */ - sigemptyset(&acmsigset); - sigaddset(&acmsigset, SIGCHLD); - sigprocmask(SIG_BLOCK, &acmsigset, &old_sigset); - - do { - if (NULL == fgets(buffer, sizeof(buffer), fp)) { - if (feof(fp)) - break; - else - perror_msg_and_die("uni_screen_map_read_ascii() can't read line"); - } - - /* get "charset-relative charcode", stripping leading spaces */ - p = strtok(buffer, " \t\n"); - - /* skip empty lines and comments */ - if (!p || *p == '#') - continue; - - /* get unicode mapping */ - q = strtok(NULL, " \t\n"); - if (q) { - in = ctoi(p, NULL); - if (in < 0 || in > 255) { - ret_code = -1; - break; - } - - on = ctoi(q, &tmp_is_unicode); - if (in < 0 && on > 65535) { - ret_code = -1; - break; - } - - *is_unicode |= tmp_is_unicode; - buf[in] = on; - } else { - ret_code = -1; - break; - } - } - while (1); /* terminated by break on feof() */ - - /* restore sig mask */ - sigprocmask(SIG_SETMASK, &old_sigset, NULL); - - return ret_code; -} - - -static int old_screen_map_read_ascii(FILE * fp, unsigned char buf[]) -{ - char buffer[256]; - int in, on; - char *p, *q; - - for (in = 0; in < 256; in++) - buf[in] = in; - - while (fgets(buffer, sizeof(buffer) - 1, fp)) { - p = strtok(buffer, " \t\n"); - - if (!p || *p == '#') - continue; - - q = strtok(NULL, " \t\n#"); - if (q) { - in = ctoi(p, NULL); - if (in < 0 || in > 255) - return -1; - - on = ctoi(q, NULL); - if (in < 0 && on > 255) - return -1; - - buf[in] = on; - } else - return -1; - } - - return (0); -} - - -/* - * - converts a string into an int. - * - supports dec and hex bytes, hex UCS2, single-quoted byte and UTF8 chars. - * - returns the converted value - * - if `is_unicode != NULL', use it to tell whether it was unicode - * - * CAVEAT: will report valid UTF mappings using only 1 byte as 8-bit ones. - */ -static long int ctoi(unsigned char *s, int *is_unicode) -{ - int i; - size_t ls; - - ls = strlen(s); - if (is_unicode) - *is_unicode = 0; - - /* hex-specified UCS2 */ - if ((strncmp(s, "U+", 2) == 0) && - (strspn(s + 2, "0123456789abcdefABCDEF") == ls - 2)) { - sscanf(s + 2, "%x", &i); - if (is_unicode) - *is_unicode = 1; - } - - /* hex-specified byte */ - else if ((ls <= 4) && (strncmp(s, "0x", 2) == 0) && - (strspn(s + 2, "0123456789abcdefABCDEF") == ls - 2)) - sscanf(s + 2, "%x", &i); - - /* oct-specified number (byte) */ - else if ((*s == '0') && (strspn(s, "01234567") == ls)) - sscanf(s, "%o", &i); - - /* dec-specified number (byte) */ - else if (strspn(s, "0123456789") == ls) - sscanf(s, "%d", &i); - - /* single-byte quoted char */ - else if ((strlen(s) == 3) && (s[0] == '\'') && (s[2] == '\'')) - i = s[1]; - - /* multi-byte UTF8 quoted char */ - else if ((s[0] == '\'') && (s[ls - 1] == '\'')) { - s[ls - 1] = 0; /* ensure we'll not "parse UTF too far" */ - i = utf8_to_ucs2(s + 1); - if (is_unicode) - *is_unicode = 1; - } else - return (-1); - - return (i); -} - - -static unicode utf8_to_ucs2(char *buf) -{ - int utf_count = 0; - long utf_char = 0; - unicode tc = 0; - unsigned char c; - - do { - c = *buf; - buf++; - - /* if byte should be part of multi-byte sequence */ - if (c & 0x80) { - /* if we have already started to parse a UTF8 sequence */ - if (utf_count > 0 && (c & 0xc0) == 0x80) { - utf_char = (utf_char << 6) | (c & 0x3f); - utf_count--; - if (utf_count == 0) - tc = utf_char; - else - continue; - } else { /* Possibly 1st char of a UTF8 sequence */ - - if ((c & 0xe0) == 0xc0) { - utf_count = 1; - utf_char = (c & 0x1f); - } else if ((c & 0xf0) == 0xe0) { - utf_count = 2; - utf_char = (c & 0x0f); - } else if ((c & 0xf8) == 0xf0) { - utf_count = 3; - utf_char = (c & 0x07); - } else if ((c & 0xfc) == 0xf8) { - utf_count = 4; - utf_char = (c & 0x03); - } else if ((c & 0xfe) == 0xfc) { - utf_count = 5; - utf_char = (c & 0x01); - } else - utf_count = 0; - continue; - } - } else { /* not part of multi-byte sequence - treat as ASCII - * this makes incomplete sequences to be ignored - */ - tc = c; - utf_count = 0; - } - } - while (utf_count); - - return tc; -} diff --git a/busybox/console-tools/loadfont.c b/busybox/console-tools/loadfont.c deleted file mode 100644 index d66500195..000000000 --- a/busybox/console-tools/loadfont.c +++ /dev/null @@ -1,209 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * loadfont.c - Eugene Crosser & Andries Brouwer - * - * Version 0.96bb - * - * Loads the console font, and possibly the corresponding screen map(s). - * (Adapted for busybox by Matej Vela.) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -static const int PSF_MAGIC1 = 0x36; -static const int PSF_MAGIC2 = 0x04; - -static const int PSF_MODE512 = 0x01; -static const int PSF_MODEHASTAB = 0x02; -static const int PSF_MAXMODE = 0x03; -static const int PSF_SEPARATOR = 0xFFFF; - -struct psf_header { - unsigned char magic1, magic2; /* Magic number */ - unsigned char mode; /* PSF font mode */ - unsigned char charsize; /* Character size */ -}; - -#define PSF_MAGIC_OK(x) ((x).magic1 == PSF_MAGIC1 && (x).magic2 == PSF_MAGIC2) - -static void loadnewfont(int fd); - -extern int loadfont_main(int argc, char **argv) -{ - int fd; - - if (argc != 1) - show_usage(); - - fd = open(CURRENT_VC, O_RDWR); - if (fd < 0) - perror_msg_and_die("Error opening " CURRENT_VC); - loadnewfont(fd); - - return EXIT_SUCCESS; -} - -static void do_loadfont(int fd, char *inbuf, int unit, int fontsize) -{ - char buf[16384]; - int i; - - memset(buf, 0, sizeof(buf)); - - if (unit < 1 || unit > 32) - error_msg_and_die("Bad character size %d", unit); - - for (i = 0; i < fontsize; i++) - memcpy(buf + (32 * i), inbuf + (unit * i), unit); - -#if defined( PIO_FONTX ) && !defined( __sparc__ ) - { - struct consolefontdesc cfd; - - cfd.charcount = fontsize; - cfd.charheight = unit; - cfd.chardata = buf; - - if (ioctl(fd, PIO_FONTX, &cfd) == 0) - return; /* success */ - perror_msg("PIO_FONTX ioctl error (trying PIO_FONT)"); - } -#endif - if (ioctl(fd, PIO_FONT, buf)) - perror_msg_and_die("PIO_FONT ioctl error"); -} - -static void -do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize) -{ - struct unimapinit advice; - struct unimapdesc ud; - struct unipair *up; - int ct = 0, maxct; - int glyph; - u_short unicode; - - maxct = tailsz; /* more than enough */ - up = (struct unipair *) xmalloc(maxct * sizeof(struct unipair)); - - for (glyph = 0; glyph < fontsize; glyph++) { - while (tailsz >= 2) { - unicode = (((u_short) inbuf[1]) << 8) + inbuf[0]; - tailsz -= 2; - inbuf += 2; - if (unicode == PSF_SEPARATOR) - break; - up[ct].unicode = unicode; - up[ct].fontpos = glyph; - ct++; - } - } - - /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP - this printf did not work on many kernels */ - - advice.advised_hashsize = 0; - advice.advised_hashstep = 0; - advice.advised_hashlevel = 0; - if (ioctl(fd, PIO_UNIMAPCLR, &advice)) { -#ifdef ENOIOCTLCMD - if (errno == ENOIOCTLCMD) { - error_msg("It seems this kernel is older than 1.1.92"); - error_msg_and_die("No Unicode mapping table loaded."); - } else -#endif - perror_msg_and_die("PIO_UNIMAPCLR"); - } - ud.entry_ct = ct; - ud.entries = up; - if (ioctl(fd, PIO_UNIMAP, &ud)) { -#if 0 - if (errno == ENOMEM) { - /* change advice parameters */ - } -#endif - perror_msg_and_die("PIO_UNIMAP"); - } -} - -static void loadnewfont(int fd) -{ - int unit; - char inbuf[32768]; /* primitive */ - unsigned int inputlth, offset; - - /* - * We used to look at the length of the input file - * with stat(); now that we accept compressed files, - * just read the entire file. - */ - inputlth = fread(inbuf, 1, sizeof(inbuf), stdin); - if (ferror(stdin)) - perror_msg_and_die("Error reading input font"); - /* use malloc/realloc in case of giant files; - maybe these do not occur: 16kB for the font, - and 16kB for the map leaves 32 unicode values - for each font position */ - if (!feof(stdin)) - perror_msg_and_die("Font too large"); - - /* test for psf first */ - { - struct psf_header psfhdr; - int fontsize; - int hastable; - unsigned int head0, head; - - if (inputlth < sizeof(struct psf_header)) - goto no_psf; - - psfhdr = *(struct psf_header *) &inbuf[0]; - - if (!PSF_MAGIC_OK(psfhdr)) - goto no_psf; - - if (psfhdr.mode > PSF_MAXMODE) - error_msg_and_die("Unsupported psf file mode"); - fontsize = ((psfhdr.mode & PSF_MODE512) ? 512 : 256); -#if !defined( PIO_FONTX ) || defined( __sparc__ ) - if (fontsize != 256) - error_msg_and_die("Only fontsize 256 supported"); -#endif - hastable = (psfhdr.mode & PSF_MODEHASTAB); - unit = psfhdr.charsize; - head0 = sizeof(struct psf_header); - - head = head0 + fontsize * unit; - if (head > inputlth || (!hastable && head != inputlth)) - error_msg_and_die("Input file: bad length"); - do_loadfont(fd, inbuf + head0, unit, fontsize); - if (hastable) - do_loadtable(fd, inbuf + head, inputlth - head, fontsize); - return; - } - no_psf: - - /* file with three code pages? */ - if (inputlth == 9780) { - offset = 40; - unit = 16; - } else { - /* bare font */ - if (inputlth & 0377) - error_msg_and_die("Bad input file size"); - offset = 0; - unit = inputlth / 256; - } - do_loadfont(fd, inbuf + offset, unit, 256); -} diff --git a/busybox/console-tools/loadkmap.c b/busybox/console-tools/loadkmap.c deleted file mode 100644 index 4f217d630..000000000 --- a/busybox/console-tools/loadkmap.c +++ /dev/null @@ -1,89 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini loadkmap implementation for busybox - * - * Copyright (C) 1998 Enrique Zanardi - * - * 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 "busybox.h" - -#define BINARY_KEYMAP_MAGIC "bkeymap" - -/* From */ -struct kbentry { - unsigned char kb_table; - unsigned char kb_index; - unsigned short kb_value; -}; -static const int KDSKBENT = 0x4B47; /* sets one entry in translation table */ - -/* From */ -static const int NR_KEYS = 128; -static const int MAX_NR_KEYMAPS = 256; - -int loadkmap_main(int argc, char **argv) -{ - struct kbentry ke; - u_short *ibuff; - int i, j, fd, readsz, pos, ibuffsz = NR_KEYS * sizeof(u_short); - char flags[MAX_NR_KEYMAPS], buff[7]; - - if (argc != 1) - show_usage(); - - fd = open(CURRENT_VC, O_RDWR); - if (fd < 0) - perror_msg_and_die("Error opening " CURRENT_VC); - - read(0, buff, 7); - if (0 != strncmp(buff, BINARY_KEYMAP_MAGIC, 7)) - error_msg_and_die("This is not a valid binary keymap."); - - if (MAX_NR_KEYMAPS != read(0, flags, MAX_NR_KEYMAPS)) - perror_msg_and_die("Error reading keymap flags"); - - ibuff = (u_short *) xmalloc(ibuffsz); - - for (i = 0; i < MAX_NR_KEYMAPS; i++) { - if (flags[i] == 1) { - pos = 0; - while (pos < ibuffsz) { - if ((readsz = read(0, (char *) ibuff + pos, ibuffsz - pos)) < 0) - perror_msg_and_die("Error reading keymap"); - pos += readsz; - } - for (j = 0; j < NR_KEYS; j++) { - ke.kb_index = j; - ke.kb_table = i; - ke.kb_value = ibuff[j]; - ioctl(fd, KDSKBENT, &ke); - } - } - } - /* Don't bother to close files. Exit does that - * automagically, so we can save a few bytes */ - /* close(fd); */ - return EXIT_SUCCESS; -} diff --git a/busybox/console-tools/reset.c b/busybox/console-tools/reset.c deleted file mode 100644 index 755c4c335..000000000 --- a/busybox/console-tools/reset.c +++ /dev/null @@ -1,35 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini reset implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * and Kent Robotti - * - * 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 "busybox.h" - -extern int reset_main(int argc, char **argv) -{ - printf("\033c"); - return EXIT_SUCCESS; -} - diff --git a/busybox/console-tools/setkeycodes.c b/busybox/console-tools/setkeycodes.c deleted file mode 100644 index c3c7e09aa..000000000 --- a/busybox/console-tools/setkeycodes.c +++ /dev/null @@ -1,72 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * setkeycodes - * - * Copyright (C) 1994-1998 Andries E. Brouwer - * - * Adjusted for BusyBox 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 - * - */ - -#include -#include -#include -#include -#include "busybox.h" - - -/* From */ -struct kbkeycode { - unsigned int scancode, keycode; -}; -static const int KDSETKEYCODE = 0x4B4D; /* write kernel keycode table entry */ - -extern int -setkeycodes_main(int argc, char** argv) -{ - char *ep; - int fd, sc; - struct kbkeycode a; - - if (argc % 2 != 1 || argc < 2) { - show_usage(); - } - - fd = get_console_fd("/dev/console"); - - while (argc > 2) { - a.keycode = atoi(argv[2]); - a.scancode = sc = strtol(argv[1], &ep, 16); - if (*ep) { - error_msg_and_die("error reading SCANCODE: '%s'", argv[1]); - } - if (a.scancode > 127) { - a.scancode -= 0xe000; - a.scancode += 128; - } - if (a.scancode > 255 || a.keycode > 127) { - error_msg_and_die("SCANCODE or KEYCODE outside bounds"); - } - if (ioctl(fd,KDSETKEYCODE,&a)) { - perror("KDSETKEYCODE"); - error_msg_and_die("failed to set SCANCODE %x to KEYCODE %d", sc, a.keycode); - } - argc -= 2; - argv += 2; - } - return EXIT_SUCCESS; -} diff --git a/busybox/coreutils/basename.c b/busybox/coreutils/basename.c deleted file mode 100644 index c15afd533..000000000 --- a/busybox/coreutils/basename.c +++ /dev/null @@ -1,52 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini basename implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -/* getopt not needed */ - -#include -#include "busybox.h" -#include - -extern int basename_main(int argc, char **argv) -{ - int m, n; - char *s; - - if ((argc < 2) || (**(argv + 1) == '-')) { - show_usage(); - } - - argv++; - - s = get_last_path_component(*argv); - - if (argc>2) { - argv++; - n = strlen(*argv); - m = strlen(s); - if (m>n && strncmp(s+m-n, *argv, n)==0) - s[m-n] = '\0'; - } - puts(s); - return EXIT_SUCCESS; -} diff --git a/busybox/coreutils/cat.c b/busybox/coreutils/cat.c deleted file mode 100644 index aa8528d6a..000000000 --- a/busybox/coreutils/cat.c +++ /dev/null @@ -1,53 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini Cat implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include "busybox.h" - -extern int cat_main(int argc, char **argv) -{ - int status = EXIT_SUCCESS; - - if (argc == 1) { - print_file(stdin); - return status; - } - - while (--argc > 0) { - if(!(strcmp(*++argv, "-"))) { - print_file(stdin); - } else if (print_file_by_name(*argv) == FALSE) { - status = EXIT_FAILURE; - } - } - return status; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/coreutils/chgrp.c b/busybox/coreutils/chgrp.c deleted file mode 100644 index fbc1036a8..000000000 --- a/busybox/coreutils/chgrp.c +++ /dev/null @@ -1,91 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini chown/chmod/chgrp implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include "busybox.h" - -/* Don't use lchown for libc5 or glibc older then 2.1.x */ -#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1) -#define lchown chown -#endif - - -static long gid; - -static int fileAction(const char *fileName, struct stat *statbuf, void* junk) -{ - if (lchown(fileName, statbuf->st_uid, (gid == -1) ? statbuf->st_gid : gid) == 0) { - return (TRUE); - } - perror(fileName); - return (FALSE); -} - -int chgrp_main(int argc, char **argv) -{ - int opt; - int recursiveFlag = FALSE; - char *p=NULL; - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "R")) > 0) { - switch (opt) { - case 'R': - recursiveFlag = TRUE; - break; - default: - show_usage(); - } - } - - if (argc > optind && argc > 2 && argv[optind]) { - /* Find the selected group */ - gid = strtoul(argv[optind], &p, 10); /* maybe it's already numeric */ - if (argv[optind] == p) - gid = my_getgrnam(argv[optind]); - } else { - error_msg_and_die(too_few_args); - } - - /* Ok, ready to do the deed now */ - while (++optind < argc) { - if (recursive_action (argv[optind], recursiveFlag, FALSE, FALSE, - fileAction, fileAction, NULL) == FALSE) { - return EXIT_FAILURE; - } - } - return EXIT_SUCCESS; - -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/coreutils/chmod.c b/busybox/coreutils/chmod.c deleted file mode 100644 index 9139b3f4d..000000000 --- a/busybox/coreutils/chmod.c +++ /dev/null @@ -1,85 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini chown/chmod/chgrp implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -static int fileAction(const char *fileName, struct stat *statbuf, void* junk) -{ - if (!parse_mode((char *)junk, &(statbuf->st_mode))) - error_msg_and_die("internal error"); - if (chmod(fileName, statbuf->st_mode) == 0) - return (TRUE); - perror(fileName); - return (FALSE); -} - -int chmod_main(int argc, char **argv) -{ - int i; - int opt; - int recursiveFlag = FALSE; - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "R")) > 0) { - switch (opt) { - case 'R': - recursiveFlag = TRUE; - break; - default: - show_usage(); - } - } - - if (argc > optind && argc > 2 && argv[optind]) { - /* Parse the specified mode */ - mode_t mode; - if (parse_mode(argv[optind], &mode) == FALSE) { - error_msg_and_die( "unknown mode: %s", argv[optind]); - } - } else { - error_msg_and_die(too_few_args); - } - - /* Ok, ready to do the deed now */ - for (i = optind + 1; i < argc; i++) { - if (recursive_action (argv[i], recursiveFlag, FALSE, FALSE, fileAction, - fileAction, argv[optind]) == FALSE) { - return EXIT_FAILURE; - } - } - return EXIT_SUCCESS; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/coreutils/chown.c b/busybox/coreutils/chown.c deleted file mode 100644 index d1e52deda..000000000 --- a/busybox/coreutils/chown.c +++ /dev/null @@ -1,113 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini chown/chmod/chgrp implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include "busybox.h" - -/* Don't use lchown for libc5 or 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); - } - perror(fileName); - return (FALSE); -} - -int chown_main(int argc, char **argv) -{ - int opt; - int recursiveFlag = FALSE, - noderefFlag = FALSE; - char *groupName=NULL; - char *p=NULL; - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "Rh")) > 0) { - switch (opt) { - case 'R': - recursiveFlag = TRUE; - break; - case 'h': - noderefFlag = TRUE; - break; - default: - show_usage(); - } - } - - if (noderefFlag) chown_func = lchown; - - if (argc > optind && argc > 2 && argv[optind]) { - /* First, check if there is a group name here */ - groupName = strchr(argv[optind], '.'); - if (groupName == NULL) - groupName = strchr(argv[optind], ':'); - if (groupName) { - *groupName++ = '\0'; - gid = strtoul(groupName, &p, 10); - if (groupName == p) - gid = my_getgrnam(groupName); - } else { - gid = -1; - } - /* Now check for the username */ - uid = strtoul(argv[optind], &p, 10); /* Is is numeric? */ - if (argv[optind] == p) { - uid = my_getpwnam(argv[optind]); - } - } else { - error_msg_and_die(too_few_args); - } - - /* Ok, ready to do the deed now */ - while (++optind < argc) { - if (recursive_action (argv[optind], recursiveFlag, FALSE, FALSE, - fileAction, fileAction, NULL) == FALSE) { - return EXIT_FAILURE; - } - } - return EXIT_SUCCESS; - -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/coreutils/chroot.c b/busybox/coreutils/chroot.c deleted file mode 100644 index de6a2ea50..000000000 --- a/busybox/coreutils/chroot.c +++ /dev/null @@ -1,75 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini chroot implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include "busybox.h" - -int chroot_main(int argc, char **argv) -{ - char *prog; - - if ((argc < 2) || (**(argv + 1) == '-')) { - show_usage(); - } - argc--; - argv++; - - if (chroot(*argv) || (chdir("/"))) { - perror_msg_and_die("cannot change root directory to %s", *argv); - } - - argc--; - argv++; - if (argc >= 1) { - prog = *argv; - execvp(*argv, argv); - } else { -#if defined shell_main && defined BB_FEATURE_SH_STANDALONE_SHELL - char shell[] = "/bin/sh"; - char *shell_argv[2] = { shell, NULL }; - applet_name = shell; - shell_main(1, shell_argv); - return EXIT_SUCCESS; -#else - prog = getenv("SHELL"); - if (!prog) - prog = "/bin/sh"; - execlp(prog, prog, NULL); -#endif - } - perror_msg_and_die("cannot execute %s", prog); - -} - - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/coreutils/cmp.c b/busybox/coreutils/cmp.c deleted file mode 100644 index 6d579461d..000000000 --- a/busybox/coreutils/cmp.c +++ /dev/null @@ -1,80 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini cmp implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -int cmp_main(int argc, char **argv) -{ - FILE *fp1 = NULL, *fp2 = stdin; - char *filename1, *filename2 = "-"; - int c, c1, c2, char_pos = 1, line_pos = 1, silent = FALSE; - - while ((c = getopt(argc, argv, "s")) != EOF) { - switch (c) { - case 's': - silent = TRUE; - break; - default: - show_usage(); - } - } - - filename1 = argv[optind]; - switch (argc - optind) { - case 2: - fp2 = xfopen(filename2 = argv[optind + 1], "r"); - case 1: - fp1 = xfopen(filename1, "r"); - break; - default: - show_usage(); - } - - do { - c1 = fgetc(fp1); - c2 = fgetc(fp2); - if (c1 != c2) { - if (silent) - return EXIT_FAILURE; - if (c1 == EOF) - printf("EOF on %s\n", filename1); - else if (c2 == EOF) - printf("EOF on %s\n", filename2); - else - printf("%s %s differ: char %d, line %d\n", filename1, filename2, - char_pos, line_pos); - return EXIT_FAILURE; - } - char_pos++; - if (c1 == '\n') - line_pos++; - } while (c1 != EOF); - - return EXIT_SUCCESS; -} diff --git a/busybox/coreutils/cp.c b/busybox/coreutils/cp.c deleted file mode 100644 index 82d43adff..000000000 --- a/busybox/coreutils/cp.c +++ /dev/null @@ -1,114 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini cp implementation for busybox - * - * - * Copyright (C) 2000 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "busybox.h" - -extern int cp_main(int argc, char **argv) -{ - int status = 0; - int opt; - int flags = 0; - int i; - - while ((opt = getopt(argc, argv, "adfipR")) != -1) - switch (opt) { - case 'a': - flags |= FILEUTILS_PRESERVE_STATUS | FILEUTILS_RECUR; - /* fallthrough */ - case 'd': - flags |= FILEUTILS_PRESERVE_SYMLINKS; - break; - case 'f': - flags |= FILEUTILS_FORCE; - break; - case 'i': - flags |= FILEUTILS_INTERACTIVE; - break; - case 'p': - flags |= FILEUTILS_PRESERVE_STATUS; - break; - case 'R': - flags |= FILEUTILS_RECUR; - break; - default: - show_usage(); - } - - if (optind + 2 > argc) - show_usage(); - - /* If there are only two arguments and... */ - if (optind + 2 == argc) { - struct stat source_stat; - struct stat dest_stat; - int source_exists = 1; - int dest_exists = 1; - - if (((flags & FILEUTILS_PRESERVE_SYMLINKS) && - lstat(argv[optind], &source_stat) < 0) || - (!(flags & FILEUTILS_PRESERVE_SYMLINKS) && - stat(argv[optind], &source_stat))) { - if (errno != ENOENT) - perror_msg_and_die("unable to stat `%s'", argv[optind]); - source_exists = 0; - } - - if (stat(argv[optind + 1], &dest_stat) < 0) { - if (errno != ENOENT) - perror_msg_and_die("unable to stat `%s'", argv[optind + 1]); - dest_exists = 0; - } - - /* ...if neither is a directory or... */ - if (((!source_exists || !S_ISDIR(source_stat.st_mode)) && - (!dest_exists || !S_ISDIR(dest_stat.st_mode))) || - /* ...recursing, the first is a directory, and the - * second doesn't exist, then... */ - ((flags & FILEUTILS_RECUR) && S_ISDIR(source_stat.st_mode) && - !dest_exists)) { - /* ...do a simple copy. */ - if (copy_file(argv[optind], argv[optind + 1], flags) < 0) - status = 1; - return status; - } - } - - for (i = optind; i < argc - 1; i++) { - char *dest = concat_path_file(argv[argc - 1], - get_last_path_component(argv[i])); - if (copy_file(argv[i], dest, flags) < 0) - status = 1; - free(dest); - } - - return status; -} diff --git a/busybox/coreutils/cut.c b/busybox/coreutils/cut.c deleted file mode 100644 index 3ed264870..000000000 --- a/busybox/coreutils/cut.c +++ /dev/null @@ -1,356 +0,0 @@ -/* - * 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 - * - */ - -#include -#include -#include /* getopt */ -#include -#include -#include "busybox.h" - - -/* globals from other files */ -extern int optind; -extern char *optarg; - - -/* option vars */ -static char part = 0; /* (b)yte, (c)har, (f)ields */ -static unsigned int supress_non_delimited_lines = 0; -static char delim = '\t'; /* delimiter, default is tab */ - -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 */ - - -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; -} - - -/* - * 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) -{ - 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) - 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) - 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) - 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) - 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); - -} - - -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'; - } - 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) - 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++; - } - - /* 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++; - } - - 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 = get_line_from_file(file)) != NULL) { - chomp(line); - - /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */ - if (part == 'c' || part == 'b') - cut_line_by_chars(line); - - /* cut based on fields */ - else if (part == 'f') { - if (delim == '\n') - cut_file_by_lines(line, linenum); - else - cut_line_by_fields(line); - } - - linenum++; - free(line); - } -} - - -extern int cut_main(int argc, char **argv) -{ - int opt; - - while ((opt = getopt(argc, argv, "b:c:d:f:ns")) > 0) { - switch (opt) { - case 'b': - case 'c': - case 'f': - /* make sure they didn't ask for two types of lists */ - if (part != 0) { - error_msg_and_die("only one type of list may be specified"); - } - part = (char)opt; - parse_lists(optarg); - break; - case 'd': - if (strlen(optarg) > 1) { - error_msg_and_die("the delimiter must be a single character"); - } - delim = optarg[0]; - break; - case 'n': - /* no-op */ - break; - case 's': - supress_non_delimited_lines++; - break; - } - } - - if (part == 0) { - error_msg_and_die("you must specify a list of bytes, characters, or fields"); - } - - /* non-field (char or byte) cutting has some special handling */ - if (part != 'f') { - if (supress_non_delimited_lines) { - error_msg_and_die("suppressing non-delimited lines makes sense" - " only when operating on fields"); - } - if (delim != '\t' && part != 'f') { - error_msg_and_die("a delimiter may be specified only when operating on fields"); - } - } - - /* 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 = wfopen(argv[i], "r"); - if(file) { - cut_file(file); - fclose(file); - } - } - } - - return EXIT_SUCCESS; -} diff --git a/busybox/coreutils/date.c b/busybox/coreutils/date.c deleted file mode 100644 index 6db3e2838..000000000 --- a/busybox/coreutils/date.c +++ /dev/null @@ -1,247 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini date implementation for busybox - * - * by Matthew Grant - * - * 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 "busybox.h" - - -/* 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 - 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) { - error_msg_and_die(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); - -} - - -/* The new stuff for LRP */ - -static struct tm *date_conv_ftime(struct tm *tm_time, const char *t_string) -{ - 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) { - - t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */ - - } 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) { - - 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:%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 { - error_msg_and_die(invalid_date, t_string); - } - *tm_time = t; - return (tm_time); -} - - -int date_main(int argc, char **argv) -{ - char *date_str = NULL; - char *date_fmt = NULL; - char *t_buff; - int c; - int set_time = 0; - int rfc822 = 0; - int utc = 0; - int use_arg = 0; - time_t tm; - struct tm tm_time; - - /* Interpret command line args */ - while ((c = getopt(argc, argv, "Rs:ud:")) != EOF) { - switch (c) { - case 'R': - rfc822 = 1; - break; - case 's': - set_time = 1; - if ((date_str != NULL) || ((date_str = optarg) == NULL)) { - show_usage(); - } - break; - case 'u': - utc = 1; - if (putenv("TZ=UTC0") != 0) - error_msg_and_die(memory_exhausted); - break; - case 'd': - use_arg = 1; - if ((date_str != NULL) || ((date_str = optarg) == NULL)) - show_usage(); - break; - default: - show_usage(); - } - } - - 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]; - } -#if 0 - else { - error_msg("date_str='%s' date_fmt='%s'\n", date_str, date_fmt); - show_usage(); - } -#endif - - /* Now we have parsed all the information except the date format - which depends on whether the clock is being set or read */ - - time(&tm); - memcpy(&tm_time, localtime(&tm), sizeof(tm_time)); - /* Zero out fields - take her back to midnight! */ - if (date_str != NULL) { - 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); - } else { - date_conv_time(&tm_time, date_str); - } - - /* Correct any day of week and day of year etc. fields */ - tm = mktime(&tm_time); - if (tm < 0) - error_msg_and_die(invalid_date, date_str); - if ( utc ) { - if (putenv("TZ=UTC0") != 0) - error_msg_and_die(memory_exhausted); - } - - /* if setting time, set it */ - if (set_time) { - if (stime(&tm) < 0) { - perror_msg("cannot set date"); - } - } - } - - /* Display output */ - - /* Deal with format string */ - if (date_fmt == NULL) { - date_fmt = (rfc822 - ? (utc - ? "%a, %_d %b %Y %H:%M:%S GMT" - : "%a, %_d %b %Y %H:%M:%S %z") - : "%a %b %e %H:%M:%S %Z %Y"); - - } else if (*date_fmt == '\0') { - /* Imitate what GNU 'date' does with NO format string! */ - printf("\n"); - return EXIT_SUCCESS; - } - - /* Handle special conversions */ - - if (strncmp(date_fmt, "%f", 2) == 0) { - date_fmt = "%Y.%m.%d-%H:%M:%S"; - } - - /* Print OUTPUT (after ALL that!) */ - t_buff = xmalloc(201); - strftime(t_buff, 200, date_fmt, &tm_time); - puts(t_buff); - - return EXIT_SUCCESS; -} diff --git a/busybox/coreutils/dd.c b/busybox/coreutils/dd.c deleted file mode 100644 index d46db82a0..000000000 --- a/busybox/coreutils/dd.c +++ /dev/null @@ -1,154 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini dd implementation for busybox - * - * - * Copyright (C) 2000 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - - -static const struct suffix_mult dd_suffixes[] = { - { "c", 1 }, - { "w", 2 }, - { "b", 512 }, - { "kD", 1000 }, - { "k", 1024 }, - { "MD", 1000000 }, - { "M", 1048576 }, - { "GD", 1000000000 }, - { "G", 1073741824 }, - { NULL, 0 } -}; - -int dd_main(int argc, char **argv) -{ - int i, ifd, ofd, oflag, sync_flag = FALSE, trunc = TRUE; - size_t in_full = 0, in_part = 0, out_full = 0, out_part = 0; - size_t bs = 512, count = -1; - ssize_t n; - off_t seek = 0, skip = 0; - char *infile = NULL, *outfile = NULL, *buf; - - for (i = 1; i < argc; i++) { - if (strncmp("bs=", argv[i], 3) == 0) - bs = parse_number(argv[i]+3, dd_suffixes); - else if (strncmp("count=", argv[i], 6) == 0) - count = parse_number(argv[i]+6, dd_suffixes); - else if (strncmp("seek=", argv[i], 5) == 0) - seek = parse_number(argv[i]+5, dd_suffixes); - else if (strncmp("skip=", argv[i], 5) == 0) - skip = parse_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; - 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 { - error_msg_and_die("invalid conversion `%s'", argv[i]+5); - } - if (buf[0] == '\0') - break; - if (buf[0] == ',') - buf++; - } - } else - show_usage(); - } - - buf = xmalloc(bs); - - if (infile != NULL) { - if ((ifd = open(infile, O_RDONLY)) < 0) - perror_msg_and_die("%s", infile); - } else { - ifd = STDIN_FILENO; - infile = "standard input"; - } - - if (outfile != NULL) { - oflag = O_WRONLY | O_CREAT; - - if (!seek && trunc) - oflag |= O_TRUNC; - - if ((ofd = open(outfile, oflag, 0666)) < 0) - perror_msg_and_die("%s", outfile); - - if (seek && trunc) { - if (ftruncate(ofd, seek * bs) < 0) - perror_msg_and_die("%s", outfile); - } - } else { - ofd = STDOUT_FILENO; - outfile = "standard output"; - } - - if (skip) { - if (lseek(ifd, skip * bs, SEEK_CUR) < 0) - perror_msg_and_die("%s", infile); - } - - if (seek) { - if (lseek(ofd, seek * bs, SEEK_CUR) < 0) - perror_msg_and_die("%s", outfile); - } - - while (in_full + in_part != count) { - n = safe_read(ifd, buf, bs); - if (n < 0) - perror_msg_and_die("%s", infile); - if (n == 0) - break; - if (n == bs) - in_full++; - else - in_part++; - if (sync_flag) { - memset(buf + n, '\0', bs - n); - n = bs; - } - n = full_write(ofd, buf, n); - if (n < 0) - perror_msg_and_die("%s", outfile); - if (n == bs) - out_full++; - else - out_part++; - } - - fprintf(stderr, "%ld+%ld records in\n", (long)in_full, (long)in_part); - fprintf(stderr, "%ld+%ld records out\n", (long)out_full, (long)out_part); - - return EXIT_SUCCESS; -} diff --git a/busybox/coreutils/df.c b/busybox/coreutils/df.c deleted file mode 100644 index 8cb13fa6d..000000000 --- a/busybox/coreutils/df.c +++ /dev/null @@ -1,158 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini df implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -extern const char mtab_file[]; /* Defined in utility.c */ -#ifdef BB_FEATURE_HUMAN_READABLE -static unsigned long df_disp_hr = KILOBYTE; -#endif - -static int do_df(char *device, const char *mount_point) -{ - struct statfs s; - long blocks_used; - long blocks_percent_used; - - if (statfs(mount_point, &s) != 0) { - perror_msg("%s", mount_point); - return FALSE; - } - - if (s.f_blocks > 0) { - blocks_used = s.f_blocks - s.f_bfree; - if(blocks_used == 0) - blocks_percent_used = 0; - else { - blocks_percent_used = (long) - (blocks_used * 100.0 / (blocks_used + s.f_bavail) + 0.5); - } - if (strcmp(device, "/dev/root") == 0) { - /* Adjusts device to be the real root device, - * or leaves device alone if it can't find it */ - device = find_real_root_device_name(device); - if(device==NULL) - return FALSE; - } -#ifdef BB_FEATURE_HUMAN_READABLE - printf("%-20s %9s ", device, - make_human_readable_str(s.f_blocks, s.f_bsize, df_disp_hr)); - - printf("%9s ", - make_human_readable_str( (s.f_blocks - s.f_bfree), s.f_bsize, df_disp_hr)); - - printf("%9s %3ld%% %s\n", - make_human_readable_str(s.f_bavail, s.f_bsize, df_disp_hr), - blocks_percent_used, mount_point); -#else - printf("%-20s %9ld %9ld %9ld %3ld%% %s\n", - device, - (long) (s.f_blocks * (s.f_bsize / (double)KILOBYTE)), - (long) ((s.f_blocks - s.f_bfree)*(s.f_bsize/(double)KILOBYTE)), - (long) (s.f_bavail * (s.f_bsize / (double)KILOBYTE)), - blocks_percent_used, mount_point); -#endif - } - - return TRUE; -} - -extern int df_main(int argc, char **argv) -{ - int status = EXIT_SUCCESS; - int opt = 0; - int i = 0; - char disp_units_hdr[80] = "1k-blocks"; /* default display is kilobytes */ - - while ((opt = getopt(argc, argv, "k" -#ifdef BB_FEATURE_HUMAN_READABLE - "hm" -#endif -)) > 0) - { - switch (opt) { -#ifdef BB_FEATURE_HUMAN_READABLE - case 'h': - df_disp_hr = 0; - strcpy(disp_units_hdr, " Size"); - break; - case 'm': - df_disp_hr = MEGABYTE; - strcpy(disp_units_hdr, "1M-blocks"); - break; -#endif - case 'k': - /* default display is kilobytes */ - break; - default: - show_usage(); - } - } - - printf("%-20s %-14s %s %s %s %s\n", "Filesystem", disp_units_hdr, - "Used", "Available", "Use%", "Mounted on"); - - if(optind < argc) { - struct mntent *mount_entry; - for(i = optind; i < argc; i++) - { - if ((mount_entry = find_mount_point(argv[i], mtab_file)) == 0) { - error_msg("%s: can't find mount point.", argv[i]); - status = EXIT_FAILURE; - } else if (!do_df(mount_entry->mnt_fsname, mount_entry->mnt_dir)) - status = EXIT_FAILURE; - } - } else { - FILE *mount_table; - struct mntent *mount_entry; - - mount_table = setmntent(mtab_file, "r"); - if (mount_table == 0) { - perror_msg("%s", mtab_file); - return EXIT_FAILURE; - } - - while ((mount_entry = getmntent(mount_table))) { - if (!do_df(mount_entry->mnt_fsname, mount_entry->mnt_dir)) - status = EXIT_FAILURE; - } - endmntent(mount_table); - } - - return status; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/coreutils/dirname.c b/busybox/coreutils/dirname.c deleted file mode 100644 index b534e6950..000000000 --- a/busybox/coreutils/dirname.c +++ /dev/null @@ -1,40 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini dirname implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -/* getopt not needed */ - -#include -#include -#include -#include "busybox.h" - -extern int dirname_main(int argc, char **argv) -{ - if ((argc < 2) || (**(argv + 1) == '-')) - show_usage(); - argv++; - - puts (dirname (argv[0])); - - return EXIT_SUCCESS; -} diff --git a/busybox/coreutils/dos2unix.c b/busybox/coreutils/dos2unix.c deleted file mode 100644 index cb30c568b..000000000 --- a/busybox/coreutils/dos2unix.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * dos2unix for BusyBox - * - * dos2unix '\n' convertor 0.5.0 - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - - -/* 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) -{ - int c, fd; - struct timeval tv; - char tempFn[BUFSIZ]; - static bb_uint64_t value=0; - FILE *in = stdin, *out = stdout; - - if (fn != NULL) { - if ((in = wfopen(fn, "rw")) == NULL) { - return -1; - } - strcpy(tempFn, fn); - c = strlen(tempFn); - tempFn[c] = '.'; - while(1) { - if (c >=BUFSIZ) - 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; - } - } - - 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) { - perror_msg(NULL); - 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)) { - perror_msg(NULL); - return -2; - } - return 0; - } - if (!ConvType) { - ConvType = CT_UNIX2DOS; - } - if (ConvType == 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); - } - - if (fn != NULL) { - if (fclose(in) < 0 || fclose(out) < 0) { - perror_msg(NULL); - 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) { - perror_msg("unable to rename '%s' as '%s'", tempFn, fn); - return -1; - } - } - - return 0; -} - -int dos2unix_main(int argc, char *argv[]) -{ - int ConvType = CT_AUTO; - int o; - - //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; - } - - // process parameters - while ((o = getopt(argc, argv, "du")) != EOF) { - switch (o) { - case 'd': - ConvType = CT_UNIX2DOS; - break; - case 'u': - ConvType = CT_DOS2UNIX; - break; - default: - show_usage(); - } - } - - if (optind < argc) { - while(optind < argc) - if ((o = convert(argv[optind++], ConvType)) < 0) - break; - } - else - o = convert(NULL, ConvType); - - return o; -} - diff --git a/busybox/coreutils/du.c b/busybox/coreutils/du.c deleted file mode 100644 index fb649aee5..000000000 --- a/busybox/coreutils/du.c +++ /dev/null @@ -1,257 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini du implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by John Beppu - * - * 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 "busybox.h" - - -#ifdef BB_FEATURE_HUMAN_READABLE -static unsigned long disp_hr = KILOBYTE; -#endif - -typedef void (Display) (long, char *); - -static int du_depth = 0; -static int count_hardlinks = 0; - -static Display *print; - -static void print_normal(long size, char *filename) -{ -#ifdef BB_FEATURE_HUMAN_READABLE - printf("%s\t%s\n", make_human_readable_str(size<<10, 1, disp_hr), filename); -#else - printf("%ld\t%s\n", size, filename); -#endif -} - -static void print_summary(long size, char *filename) -{ - if (du_depth == 1) { - print_normal(size, filename); - } -} - -#define HASH_SIZE 311 /* Should be prime */ -#define hash_inode(i) ((i) % HASH_SIZE) - -typedef struct ino_dev_hash_bucket_struct { - struct ino_dev_hash_bucket_struct *next; - ino_t ino; - dev_t dev; - char name[1]; -} ino_dev_hashtable_bucket_t; - -static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE]; - -/* - * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in - * `ino_dev_hashtable', else return 0 - * - * If NAME is a non-NULL pointer to a character pointer, and there is - * a match, then set *NAME to the value of the name slot in that - * bucket. - */ -static int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name) -{ - ino_dev_hashtable_bucket_t *bucket; - - bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)]; - while (bucket != NULL) { - if ((bucket->ino == statbuf->st_ino) && - (bucket->dev == statbuf->st_dev)) - { - if (name) *name = bucket->name; - return 1; - } - bucket = bucket->next; - } - return 0; -} - -/* Add statbuf to statbuf hash table */ -static void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) -{ - int i; - size_t s; - ino_dev_hashtable_bucket_t *bucket; - - i = hash_inode(statbuf->st_ino); - s = name ? strlen(name) : 0; - bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s); - bucket->ino = statbuf->st_ino; - bucket->dev = statbuf->st_dev; - if (name) - strcpy(bucket->name, name); - else - bucket->name[0] = '\0'; - bucket->next = ino_dev_hashtable[i]; - ino_dev_hashtable[i] = bucket; -} - -/* Clear statbuf hash table */ -static void reset_ino_dev_hashtable(void) -{ - int i; - ino_dev_hashtable_bucket_t *bucket; - - for (i = 0; i < HASH_SIZE; i++) { - while (ino_dev_hashtable[i] != NULL) { - bucket = ino_dev_hashtable[i]->next; - free(ino_dev_hashtable[i]); - ino_dev_hashtable[i] = bucket; - } - } -} - -/* tiny recursive du */ -static long du(char *filename) -{ - struct stat statbuf; - long sum; - - if ((lstat(filename, &statbuf)) != 0) { - perror_msg("%s", filename); - return 0; - } - - du_depth++; - sum = (statbuf.st_blocks >> 1); - - /* Don't add in stuff pointed to by symbolic links */ - if (S_ISLNK(statbuf.st_mode)) { - sum = 0L; - if (du_depth == 1) { - } - } - if (S_ISDIR(statbuf.st_mode)) { - DIR *dir; - struct dirent *entry; - char *newfile; - - dir = opendir(filename); - if (!dir) { - du_depth--; - return 0; - } - - newfile = last_char_is(filename, '/'); - if (newfile) - *newfile = '\0'; - - while ((entry = readdir(dir))) { - char *name = entry->d_name; - - if ((strcmp(name, "..") == 0) - || (strcmp(name, ".") == 0)) { - continue; - } - newfile = concat_path_file(filename, name); - sum += du(newfile); - free(newfile); - } - closedir(dir); - print(sum, filename); - } - else if (statbuf.st_nlink > 1 && !count_hardlinks) { - /* Add files with hard links only once */ - if (is_in_ino_dev_hashtable(&statbuf, NULL)) { - sum = 0L; - if (du_depth == 1) - print(sum, filename); - } - else { - add_to_ino_dev_hashtable(&statbuf, NULL); - } - } - du_depth--; - return sum; -} - -int du_main(int argc, char **argv) -{ - int status = EXIT_SUCCESS; - int i; - int c; - - /* default behaviour */ - print = print_normal; - - /* parse argv[] */ - while ((c = getopt(argc, argv, "sl" -#ifdef BB_FEATURE_HUMAN_READABLE -"hm" -#endif -"k")) != EOF) { - switch (c) { - case 's': - print = print_summary; - break; - case 'l': - count_hardlinks = 1; - break; -#ifdef BB_FEATURE_HUMAN_READABLE - case 'h': disp_hr = 0; break; - case 'm': disp_hr = MEGABYTE; break; -#endif - case 'k': break; - default: - show_usage(); - } - } - - /* go through remaining args (if any) */ - if (optind >= argc) { - if (du(".") == 0) - status = EXIT_FAILURE; - } else { - long sum; - - for (i=optind; i < argc; i++) { - sum = du(argv[i]); - if(is_directory(argv[i], FALSE, NULL)==FALSE) { - print_normal(sum, argv[i]); - } - reset_ino_dev_hashtable(); - } - } - - return status; -} - -/* $Id: du.c,v 1.50 2001/06/30 17:54:20 andersen Exp $ */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/coreutils/echo.c b/busybox/coreutils/echo.c deleted file mode 100644 index 31c031528..000000000 --- a/busybox/coreutils/echo.c +++ /dev/null @@ -1,152 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * echo implementation for busybox - * - * 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 - * - * Original copyright notice is retained at the end of this file. - */ - -#include -#include -#include -#include "busybox.h" - -extern int -echo_main(int argc, char** argv) -{ - int nflag = 0; - int eflag = 0; - - /* Skip argv[0]. */ - argc--; - argv++; - - while (argc > 0 && *argv[0] == '-') - { - register char *temp; - register int ix; - - /* - * 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. - */ - temp = argv[0] + 1; - - for (ix = 0; temp[ix]; ix++) - { - if (strrchr("neE", temp[ix]) == 0) - goto just_echo; - } - - if (!*temp) - goto just_echo; - - /* - * All of the options in temp are valid options to echo. - * Handle them. - */ - while (*temp) - { - if (*temp == 'n') - nflag = 1; - else if (*temp == 'e') - eflag = 1; - else if (*temp == 'E') - eflag = 0; - else - goto just_echo; - - temp++; - } - argc--; - argv++; - } - -just_echo: - while (argc > 0) { - const char *arg = argv[0]; - register int c; - - while ((c = *arg++)) { - - /* Check for escape sequence. */ - if (c == '\\' && eflag && *arg) { - if (*arg == 'c') { - /* '\c' means cancel newline. */ - nflag = 1; - arg++; - continue; - } else { - c = process_escape_sequence(&arg); - } - } - - putchar(c); - } - argc--; - argv++; - if (argc > 0) - putchar(' '); - } - if (!nflag) - putchar('\n'); - fflush(stdout); - - return EXIT_SUCCESS; -} - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * 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. - * - * California, Berkeley and its contributors. - * 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. - * - * @(#)echo.c 8.1 (Berkeley) 5/31/93 - */ diff --git a/busybox/coreutils/env.c b/busybox/coreutils/env.c deleted file mode 100644 index 8bb690b72..000000000 --- a/busybox/coreutils/env.c +++ /dev/null @@ -1,106 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * env implementation for busybox - * - * 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 - * - * Original copyright notice is retained at the end of this file. - * - * Modified for BusyBox by Erik Andersen , - */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -extern int env_main(int argc, char** argv) -{ - char **ep, *p; - char *cleanenv[1]; - int ignore_environment = 0; - int ch; - - while ((ch = getopt(argc, argv, "+iu:")) != -1) { - switch(ch) { - case 'i': - ignore_environment = 1; - break; - case 'u': - unsetenv(optarg); - break; - default: - show_usage(); - } - } - if (optind != argc && !strcmp(argv[optind], "-")) { - ignore_environment = 1; - argv++; - } - if (ignore_environment) { - environ = cleanenv; - cleanenv[0] = NULL; - } - for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv) - if (putenv(*argv) < 0) - perror_msg_and_die("%s", *argv); - if (*argv) { - execvp(*argv, argv); - perror_msg_and_die("%s", *argv); - } - for (ep = environ; *ep; ep++) - puts(*ep); - return 0; -} - -/* - * Copyright (c) 1988, 1993, 1994 - * The 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. - */ - - diff --git a/busybox/coreutils/expr.c b/busybox/coreutils/expr.c deleted file mode 100644 index d6cc82e3e..000000000 --- a/busybox/coreutils/expr.c +++ /dev/null @@ -1,535 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini expr implementation for busybox - * - * based on GNU expr Mike Parker. - * Copyright (C) 86, 1991-1997, 1999 Free Software Foundation, Inc. - * - * Busybox modifications - * 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 - * - */ - -/* This program evaluates expressions. Each token (operator, operand, - * parenthesis) of the expression must be a seperate argument. The - * parser used is a reasonably general one, though any incarnation of - * it is language-specific. It is especially nice for expressions. - * - * No parse tree is needed; a new node is evaluated immediately. - * One function can handle multiple operators all of equal precedence, - * provided they all associate ((x op x) op x). */ - -/* no getopt needed */ - -#include -#include -#include -#include -#include -#include "busybox.h" - - -/* The kinds of value we can have. */ -enum valtype { - integer, - string -}; -typedef enum valtype TYPE; - -/* A value is.... */ -struct valinfo { - TYPE type; /* Which kind. */ - union { /* The value itself. */ - int 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) { - error_msg_and_die("too few arguments"); - } - - args = argv + 1; - - v = eval (); - if (*args) - error_msg_and_die ("syntax error"); - - if (v->type == integer) - printf ("%d\n", v->u.i); - else - puts (v->u.s); - - exit (null (v)); -} - -/* Return a VALUE for I. */ - -static VALUE *int_value (int i) -{ - VALUE *v; - - v = xmalloc (sizeof(VALUE)); - v->type = integer; - v->u.i = i; - return v; -} - -/* Return a VALUE for S. */ - -static VALUE *str_value (char *s) -{ - VALUE *v; - - v = xmalloc (sizeof(VALUE)); - v->type = string; - v->u.s = strdup (s); - return v; -} - -/* Free VALUE V, including structure components. */ - -static void freev (VALUE *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) -{ - 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 (); - } -} - -/* Coerce V to a string value (can't fail). */ - -static void tostring (VALUE *v) -{ - char *temp; - - if (v->type == integer) { - temp = xmalloc (4 * (sizeof (int) / sizeof (char))); - sprintf (temp, "%d", v->u.i); - v->u.s = temp; - v->type = string; - } -} - -/* Coerce V to an integer value. Return 1 on success, 0 on failure. */ - -static int 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 (); - } -} - -/* Return nonzero if the next token matches STR exactly. - STR must not be NULL. */ - -static int -nextarg (char *str) -{ - if (*args == NULL) - return 0; - return strcmp (*args, str) == 0; -} - -/* The comparison operator handling functions. */ - -#define cmpf(name, rel) \ -static int name (l, r) 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; \ -} - 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 (l, r) VALUE *l; VALUE *r; \ -{ \ - if (!toarith (l) || !toarith (r)) \ - error_msg_and_die ("non-numeric argument"); \ - return l->u.i op r->u.i; \ -} - -#define arithdivf(name, op) \ -static int name (l, r) VALUE *l; VALUE *r; \ -{ \ - if (!toarith (l) || !toarith (r)) \ - error_msg_and_die ( "non-numeric argument"); \ - if (r->u.i == 0) \ - error_msg_and_die ( "division by zero"); \ - return l->u.i op r->u.i; \ -} - - 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) -{ - VALUE *v; - const char *errmsg; - struct re_pattern_buffer re_buffer; - struct re_registers re_regs; - int len; - - 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); - } - - 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) { - error_msg_and_die("%s", errmsg); - } - - len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs); - if (len >= 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]); - } - else - v = int_value (len); - } - else { - /* Match failed -- return the right kind of null. */ - if (re_buffer.re_nsub > 0) - v = str_value (""); - else - v = int_value (0); - } - free (re_buffer.buffer); - return v; -} - -/* Handle bare operands and ( expr ) syntax. */ - -static VALUE *eval7 (void) -{ - VALUE *v; - - if (!*args) - error_msg_and_die ( "syntax error"); - - if (nextarg ("(")) { - args++; - v = eval (); - if (!nextarg (")")) - error_msg_and_die ( "syntax error"); - args++; - return v; - } - - if (nextarg (")")) - error_msg_and_die ( "syntax error"); - - return str_value (*args++); -} - -/* Handle match, substr, index, length, and quote keywords. */ - -static VALUE *eval6 (void) -{ - VALUE *l, *r, *v, *i1, *i2; - - if (nextarg ("quote")) { - args++; - if (!*args) - error_msg_and_die ( "syntax error"); - return str_value (*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; - } - 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) - v->u.i = 0; - freev (l); - freev (r); - return v; - } - 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 (""); - else { - v = xmalloc (sizeof(VALUE)); - v->type = string; - v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1), - l->u.s + i1->u.i - 1, i2->u.i); - v->u.s[i2->u.i] = 0; - } - freev (l); - freev (i1); - freev (i2); - return v; - } - else - return eval7 (); -} - -/* Handle : operator (pattern matching). - Calls docolon to do the real work. */ - -static VALUE *eval5 (void) -{ - VALUE *l, *r, *v; - - l = eval6 (); - while (nextarg (":")) { - args++; - r = eval6 (); - v = docolon (l, r); - freev (l); - freev (r); - l = v; - } - return l; -} - -/* Handle *, /, % operators. */ - -static VALUE *eval4 (void) -{ - VALUE *l, *r; - int (*fxn) (), val; - - 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); - } -} - -/* Handle +, - operators. */ - -static VALUE *eval3 (void) -{ - VALUE *l, *r; - int (*fxn) (), val; - - 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); - } -} - -/* Handle comparisons. */ - -static VALUE *eval2 (void) -{ - VALUE *l, *r; - int (*fxn) (), val; - - 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); - } -} - -/* Handle &. */ - -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); - } - return l; -} - -/* Handle |. */ - -static VALUE *eval (void) -{ - VALUE *l, *r; - - l = eval1 (); - while (nextarg ("|")) { - args++; - r = eval1 (); - if (null (l)) { - freev (l); - l = r; - } - else - freev (r); - } - return l; -} diff --git a/busybox/coreutils/head.c b/busybox/coreutils/head.c deleted file mode 100644 index 688c250b1..000000000 --- a/busybox/coreutils/head.c +++ /dev/null @@ -1,97 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini head implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by John Beppu - * - * 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 "busybox.h" - -static int head(int len, FILE *fp) -{ - int i; - char *input; - - for (i = 0; i < len; i++) { - if ((input = get_line_from_file(fp)) == NULL) - break; - fputs(input, stdout); - free(input); - } - return 0; -} - -/* BusyBoxed head(1) */ -int head_main(int argc, char **argv) -{ - FILE *fp; - int need_headers, opt, len = 10, status = EXIT_SUCCESS; - - /* parse argv[] */ - while ((opt = getopt(argc, argv, "n:")) > 0) { - switch (opt) { - case 'n': - len = atoi(optarg); - if (len >= 1) - break; - /* fallthrough */ - default: - show_usage(); - } - } - - /* get rest of argv[] or stdin if nothing's left */ - if (argv[optind] == NULL) { - head(len, stdin); - return status; - } - - need_headers = optind != (argc - 1); - while (argv[optind]) { - if (strcmp(argv[optind], "-") == 0) { - fp = stdin; - argv[optind] = "standard input"; - } else { - if ((fp = wfopen(argv[optind], "r")) == NULL) - status = EXIT_FAILURE; - } - if (fp) { - if (need_headers) { - printf("==> %s <==\n", argv[optind]); - } - head(len, fp); - if (ferror(fp)) { - perror_msg("%s", argv[optind]); - status = EXIT_FAILURE; - } - if (optind < argc - 1) - putchar('\n'); - if (fp != stdin) - fclose(fp); - } - optind++; - } - - return status; -} diff --git a/busybox/coreutils/hostid.c b/busybox/coreutils/hostid.c deleted file mode 100644 index 68a2cc659..000000000 --- a/busybox/coreutils/hostid.c +++ /dev/null @@ -1,32 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini hostid implementation for busybox - * - * 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 - * - */ - -#include -#include -#include -#include "busybox.h" - -extern int hostid_main(int argc, char **argv) -{ - printf("%lx\n", gethostid()); - return EXIT_SUCCESS; -} diff --git a/busybox/coreutils/id.c b/busybox/coreutils/id.c deleted file mode 100644 index 85b288c0c..000000000 --- a/busybox/coreutils/id.c +++ /dev/null @@ -1,97 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini id implementation for busybox - * - * Copyright (C) 2000 by Randolph Chung - * - * 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 "busybox.h" -#include -#include -#include -#include -#include - -extern int id_main(int argc, char **argv) -{ - int no_user = 0, no_group = 0, print_real = 0; - int name_not_number = 0; - char user[9], group[9]; - long gid; - long pwnam, grnam; - int opt; - - gid = 0; - - while ((opt = getopt(argc, argv, "ugrn")) > 0) { - switch (opt) { - case 'u': - no_group++; - break; - case 'g': - no_user++; - break; - case 'r': - print_real++; - break; - case 'n': - name_not_number++; - break; - default: - show_usage(); - } - } - - if (no_user && no_group) show_usage(); - - if (argv[optind] == NULL) { - if (print_real) { - my_getpwuid(user, getuid()); - my_getgrgid(group, getgid()); - } else { - my_getpwuid(user, geteuid()); - my_getgrgid(group, getegid()); - } - } else { - strncpy(user, argv[optind], 8); - user[8] = '\0'; - gid = my_getpwnamegid(user); - my_getgrgid(group, gid); - } - - pwnam=my_getpwnam(user); - grnam=my_getgrnam(group); - - if (no_group) { - if(name_not_number && user) - puts(user); - else - printf("%ld\n", pwnam); - } else if (no_user) { - if(name_not_number && group) - puts(group); - else - printf("%ld\n", grnam); - } else { - printf("uid=%ld(%s) gid=%ld(%s)\n", pwnam, user, grnam, group); - } - return(0); -} - - -/* END CODE */ diff --git a/busybox/coreutils/length.c b/busybox/coreutils/length.c deleted file mode 100644 index 73becd28a..000000000 --- a/busybox/coreutils/length.c +++ /dev/null @@ -1,13 +0,0 @@ -/* vi: set sw=4 ts=4: */ -#include -#include -#include -#include "busybox.h" - -extern int length_main(int argc, char **argv) -{ - if (argc != 2 || **(argv + 1) == '-') - show_usage(); - printf("%lu\n", (long)strlen(argv[1])); - return EXIT_SUCCESS; -} diff --git a/busybox/coreutils/ln.c b/busybox/coreutils/ln.c deleted file mode 100644 index 7412a86fd..000000000 --- a/busybox/coreutils/ln.c +++ /dev/null @@ -1,131 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini ln implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - - -static const int LN_SYMLINK = 1; -static const int LN_FORCE = 2; -static const int LN_NODEREFERENCE = 4; - -/* - * linkDestName is where the link points to, - * linkSrcName is the name of the link to be created. - */ -static int fs_link(const char *link_destname, const char *link_srcname, - const int flag) -{ - int status; - int src_is_dir; - char *src_name; - - if (link_destname==NULL) - return(FALSE); - - src_name = (char *) xmalloc(strlen(link_srcname)+strlen(link_destname)+1); - - if (link_srcname==NULL) - strcpy(src_name, link_destname); - else - strcpy(src_name, link_srcname); - - if (flag&LN_NODEREFERENCE) - src_is_dir = is_directory(src_name, TRUE, NULL); - else - src_is_dir = is_directory(src_name, FALSE, NULL); - - if ((src_is_dir==TRUE)&&((flag&LN_NODEREFERENCE)==0)) { - char* srcdir_name; - - srcdir_name = xstrdup(link_destname); - strcat(src_name, "/"); - strcat(src_name, get_last_path_component(srcdir_name)); - free(srcdir_name); - } - - if (flag&LN_FORCE) - unlink(src_name); - - if (flag&LN_SYMLINK) - status = symlink(link_destname, src_name); - else - status = link(link_destname, src_name); - - if (status != 0) { - perror_msg(src_name); - return(FALSE); - } - return(TRUE); -} - -extern int ln_main(int argc, char **argv) -{ - int status = EXIT_SUCCESS; - int flag = 0; - int opt; - - /* Parse any options */ - while ((opt=getopt(argc, argv, "sfn")) != -1) { - switch(opt) { - case 's': - flag |= LN_SYMLINK; - break; - case 'f': - flag |= LN_FORCE; - break; - case 'n': - flag |= LN_NODEREFERENCE; - break; - default: - show_usage(); - } - } - if (optind > (argc-1)) { - show_usage(); - } - if (optind == (argc-1)) { - if (fs_link(argv[optind], - get_last_path_component(argv[optind]), flag)==FALSE) - status = EXIT_FAILURE; - } - while(optind<(argc-1)) { - if (fs_link(argv[optind], argv[argc-1], flag)==FALSE) - status = EXIT_FAILURE; - optind++; - } - exit(status); -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/coreutils/logname.c b/busybox/coreutils/logname.c deleted file mode 100644 index 0924b2471..000000000 --- a/busybox/coreutils/logname.c +++ /dev/null @@ -1,41 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini logname implementation for busybox - * - * 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 - * - */ - -#include -#include -#include -#include "busybox.h" - -extern int logname_main(int argc, char **argv) -{ - char user[9]; - - if (argc > 1) - show_usage(); - - my_getpwuid(user, geteuid()); - if (*user) { - puts(user); - return EXIT_SUCCESS; - } - error_msg_and_die("no login name"); -} diff --git a/busybox/coreutils/ls.c b/busybox/coreutils/ls.c deleted file mode 100644 index 8d0282dfe..000000000 --- a/busybox/coreutils/ls.c +++ /dev/null @@ -1,937 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * 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. - */ - -/* - * 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 - * linking in substantial chunks of libc can be disabled. - * - * Although I don't really want to add new features to this program to - * keep it small, I *am* interested to receive bug fixes and ways to make - * it more portable. - * - * 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 - * - * NON-OPTIMAL BEHAVIOUR: - * 1. autowidth reads directories twice - * 2. if you do a short directory listing without filetype characters - * appended, there's no need to stat each one - * PORTABILITY: - * 1. requires lstat (BSD) - how do you do it without? - */ - -enum { - TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */ - COLUMN_WIDTH = 14, /* default if AUTOWIDTH not defined */ - COLUMN_GAP = 2, /* includes the file type char */ -}; - - -/************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#ifdef BB_FEATURE_LS_TIMESTAMPS -#include -#endif - -#ifndef MAJOR -#define MAJOR(dev) (((dev)>>8)&0xff) -#define MINOR(dev) ((dev)&0xff) -#endif - -/* what is the overall style of the listing */ -enum { -STYLE_AUTO = 0, -STYLE_LONG = 1, /* one record per line, extended info */ -STYLE_SINGLE = 2, /* one record per line */ -STYLE_COLUMNS = 3 /* fill columns */ -}; - -/* 51306 lrwxrwxrwx 1 root root 2 May 11 01:43 /bin/view -> vi* */ -/* what file information will be listed */ -#define LIST_INO (1<<0) -#define LIST_BLOCKS (1<<1) -#define LIST_MODEBITS (1<<2) -#define LIST_NLINKS (1<<3) -#define LIST_ID_NAME (1<<4) -#define LIST_ID_NUMERIC (1<<5) -#define LIST_SIZE (1<<6) -#define LIST_DEV (1<<7) -#define LIST_DATE_TIME (1<<8) -#define LIST_FULLTIME (1<<9) -#define LIST_FILENAME (1<<10) -#define LIST_SYMLINK (1<<11) -#define LIST_FILETYPE (1<<12) -#define LIST_EXEC (1<<13) - -/* what files will be displayed */ -#define DISP_NORMAL (0) /* show normal filenames */ -#define DISP_DIRNAME (1<<0) /* 2 or more items? label directories */ -#define DISP_HIDDEN (1<<1) /* show filenames starting with . */ -#define DISP_DOT (1<<2) /* show . and .. */ -#define DISP_NOLIST (1<<3) /* show directory as itself, not contents */ -#define DISP_RECURSIVE (1<<4) /* show directory and everything below it */ -#define DISP_ROWS (1<<5) /* print across rows */ - -#ifdef BB_FEATURE_LS_SORTFILES -/* how will the files be sorted */ -static const int SORT_FORWARD = 0; /* sort in reverse order */ -static const int SORT_REVERSE = 1; /* sort in reverse order */ -static const int SORT_NAME = 2; /* sort by file name */ -static const int SORT_SIZE = 3; /* sort by file size */ -static const int SORT_ATIME = 4; /* sort by last access time */ -static const int SORT_CTIME = 5; /* sort by last change time */ -static const int SORT_MTIME = 6; /* sort by last modification time */ -static const int SORT_VERSION = 7; /* sort by version */ -static const int SORT_EXT = 8; /* sort by file name extension */ -static const int SORT_DIR = 9; /* sort by file or directory */ -#endif - -#ifdef BB_FEATURE_LS_TIMESTAMPS -/* which of the three times will be used */ -static const int TIME_MOD = 0; -static const int TIME_CHANGE = 1; -static const int TIME_ACCESS = 2; -#endif - -#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) - -static const int SPLIT_DIR = 0; -static const int SPLIT_FILE = 1; -static const int SPLIT_SUBDIR = 2; - -#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f) -#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)]) -#ifdef BB_FEATURE_LS_FILETYPES -#define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)]) -#endif - -/* - * 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 */ - struct dnode *next; /* point at the next node */ -}; -typedef struct dnode dnode_t; - -static struct dnode **list_dir(char *); -static struct dnode **dnalloc(int); -static int list_single(struct dnode *); - -static unsigned int disp_opts; -static unsigned int style_fmt; -static unsigned int list_fmt; -#ifdef BB_FEATURE_LS_SORTFILES -static unsigned int sort_opts; -static unsigned int sort_order; -#endif -#ifdef BB_FEATURE_LS_TIMESTAMPS -static unsigned int time_fmt; -#endif -#ifdef BB_FEATURE_LS_FOLLOWLINKS -static unsigned int follow_links=FALSE; -#endif - -static unsigned short column = 0; -#ifdef BB_FEATURE_AUTOWIDTH -static unsigned short terminal_width = TERMINAL_WIDTH; -static unsigned short column_width = COLUMN_WIDTH; -static unsigned short tabstops = COLUMN_GAP; -#else -static unsigned short column_width = COLUMN_WIDTH; -#endif - -static int status = EXIT_SUCCESS; - -#ifdef BB_FEATURE_HUMAN_READABLE -static unsigned long ls_disp_hr = 0; -#endif - -static int my_stat(struct dnode *cur) -{ -#ifdef BB_FEATURE_LS_FOLLOWLINKS - if (follow_links == TRUE) { - if (stat(cur->fullname, &cur->dstat)) { - perror_msg("%s", cur->fullname); - status = EXIT_FAILURE; - free(cur->fullname); - free(cur); - return -1; - } - } else -#endif - if (lstat(cur->fullname, &cur->dstat)) { - perror_msg("%s", cur->fullname); - status = EXIT_FAILURE; - free(cur->fullname); - free(cur); - return -1; - } - return 0; -} - -static void newline(void) -{ - if (column > 0) { - putchar('\n'); - column = 0; - } -} - -/*----------------------------------------------------------------------*/ -#ifdef BB_FEATURE_LS_FILETYPES -static char append_char(mode_t mode) -{ - if ( !(list_fmt & LIST_FILETYPE)) - return '\0'; - if ((list_fmt & LIST_EXEC) && S_ISREG(mode) - && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return '*'; - return APPCHAR(mode); -} -#endif - -/*----------------------------------------------------------------------*/ -static void nexttabstop( void ) -{ - static short nexttab= 0; - int n=0; - - if (column > 0) { - n= nexttab - column; - if (n < 1) n= 1; - while (n--) { - putchar(' '); - column++; - } - } - nexttab= column + column_width + COLUMN_GAP; -} - -/*----------------------------------------------------------------------*/ -static int is_subdir(struct dnode *dn) -{ - return (S_ISDIR(dn->dstat.st_mode) && strcmp(dn->name, ".") != 0 && - strcmp(dn->name, "..") != 0); -} - -static int countdirs(struct dnode **dn, int nfiles) -{ - int i, dirs; - - if (dn==NULL || nfiles < 1) return(0); - dirs= 0; - for (i=0; idstat.st_mode)) dirs++; - } - return(dirs); -} - -static int countsubdirs(struct dnode **dn, int nfiles) -{ - int i, subdirs; - - if (dn == NULL || nfiles < 1) return 0; - subdirs = 0; - for (i = 0; i < nfiles; i++) - if (is_subdir(dn[i])) - subdirs++; - return subdirs; -} - -static int countfiles(struct dnode **dnp) -{ - int nfiles; - struct dnode *cur; - - if (dnp == NULL) return(0); - nfiles= 0; - for (cur= dnp[0]; cur->next != NULL ; cur= cur->next) nfiles++; - 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); - - p= (struct dnode **)xcalloc((size_t)num, (size_t)(sizeof(struct dnode *))); - return(p); -} - -#ifdef BB_FEATURE_LS_RECURSIVE -static void dfree(struct dnode **dnp) -{ - struct dnode *cur, *next; - - if(dnp == NULL) return; - - cur=dnp[0]; - while (cur != NULL) { - if (cur->fullname != NULL) free(cur->fullname); /* free the filename */ - next= cur->next; - free(cur); /* free the dnode */ - cur= next; - } - free(dnp); /* free the array holding the dnode pointers */ -} -#endif - -static struct dnode **splitdnarray(struct dnode **dn, int nfiles, int which) -{ - int dncnt, i, d; - struct dnode **dnp; - - if (dn==NULL || nfiles < 1) return(NULL); - - /* count how many dirs and regular files there are */ - if (which == SPLIT_SUBDIR) - dncnt = countsubdirs(dn, nfiles); - else { - dncnt= countdirs(dn, nfiles); /* assume we are looking for dirs */ - if (which == SPLIT_FILE) - dncnt= nfiles - dncnt; /* looking for files */ - } - - /* allocate a file array and a dir array */ - dnp= dnalloc(dncnt); - - /* copy the entrys into the file or dir array */ - for (d= i=0; idstat.st_mode)) { - dnp[d++]= dn[i]; - } /* else skip the file */ - } else if (which == SPLIT_SUBDIR) { - if (is_subdir(dn[i])) { - dnp[d++]= dn[i]; - } /* else skip the file or dir */ - } else { - if (!(S_ISDIR(dn[i]->dstat.st_mode))) { - dnp[d++]= dn[i]; - } /* else skip the dir */ - } - } - return(dnp); -} - -/*----------------------------------------------------------------------*/ -#ifdef BB_FEATURE_LS_SORTFILES -static int sortcmp(struct dnode *d1, struct dnode *d2) -{ - int cmp, dif; - - cmp= 0; - if (sort_opts == SORT_SIZE) { - dif= (int)(d1->dstat.st_size - d2->dstat.st_size); - } else if (sort_opts == SORT_ATIME) { - dif= (int)(d1->dstat.st_atime - d2->dstat.st_atime); - } else if (sort_opts == SORT_CTIME) { - dif= (int)(d1->dstat.st_ctime - d2->dstat.st_ctime); - } else if (sort_opts == SORT_MTIME) { - dif= (int)(d1->dstat.st_mtime - d2->dstat.st_mtime); - } else if (sort_opts == SORT_DIR) { - dif= S_ISDIR(d1->dstat.st_mode) - S_ISDIR(d2->dstat.st_mode); - /* } else if (sort_opts == SORT_VERSION) { */ - /* } else if (sort_opts == SORT_EXT) { */ - } else { /* assume SORT_NAME */ - dif= 0; - } - - if (dif > 0) cmp= -1; - if (dif < 0) cmp= 1; - if (dif == 0) { - /* sort by name- may be a tie_breaker for time or size cmp */ - dif= strcmp(d1->name, d2->name); - if (dif > 0) cmp= 1; - if (dif < 0) cmp= -1; - } - - if (sort_order == SORT_REVERSE) { - cmp= -1 * cmp; - } - return(cmp); -} - -/*----------------------------------------------------------------------*/ -static void shellsort(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=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; - } - } - } -} -#endif - -/*----------------------------------------------------------------------*/ -static void showfiles(struct dnode **dn, int nfiles) -{ - int i, ncols, nrows, row, nc; -#ifdef BB_FEATURE_AUTOWIDTH - int len; -#endif - - if(dn==NULL || nfiles < 1) return; - -#ifdef BB_FEATURE_AUTOWIDTH - /* find the longest file name- use that as the column width */ - column_width= 0; - for (i=0; iname) + - ((list_fmt & LIST_INO) ? 8 : 0) + - ((list_fmt & LIST_BLOCKS) ? 5 : 0) - ; - if (column_width < len) - column_width= len; - } - if (column_width >= 6) - ncols = (int)(terminal_width / (column_width + COLUMN_GAP)); - else { - ncols = 1; - column_width = COLUMN_WIDTH; - } -#else - ncols= TERMINAL_WIDTH; -#endif - switch (style_fmt) { - case STYLE_LONG: /* one record per line, extended info */ - case STYLE_SINGLE: /* one record per line */ - ncols= 1; - break; - } - - if (ncols > 1) { - nrows = nfiles / ncols; - } else { - nrows = nfiles; - ncols = 1; - } - if ((nrows * ncols) < nfiles) nrows++; /* round up fractionals */ - - if (nrows > nfiles) nrows= nfiles; - for (row=0; rowfullname); - } - subdnp= list_dir(dn[i]->fullname); - nfiles= countfiles(subdnp); - if (nfiles > 0) { - /* list all files at this level */ -#ifdef BB_FEATURE_LS_SORTFILES - shellsort(subdnp, nfiles); -#endif - showfiles(subdnp, nfiles); -#ifdef BB_FEATURE_LS_RECURSIVE - if (disp_opts & DISP_RECURSIVE) { - /* recursive- list the sub-dirs */ - dnd= splitdnarray(subdnp, nfiles, SPLIT_SUBDIR); - dndirs= countsubdirs(subdnp, nfiles); - if (dndirs > 0) { -#ifdef BB_FEATURE_LS_SORTFILES - shellsort(dnd, dndirs); -#endif - showdirs(dnd, dndirs); - free(dnd); /* free the array of dnode pointers to the dirs */ - } - } - dfree(subdnp); /* free the dnodes and the fullname mem */ -#endif - } - } -} - -/*----------------------------------------------------------------------*/ -static struct dnode **list_dir(char *path) -{ - struct dnode *dn, *cur, **dnp; - struct dirent *entry; - DIR *dir; - int i, nfiles; - - if (path==NULL) return(NULL); - - dn= NULL; - nfiles= 0; - dir = opendir(path); - if (dir == NULL) { - perror_msg("%s", path); - status = EXIT_FAILURE; - return(NULL); /* could not open the dir */ - } - while ((entry = readdir(dir)) != NULL) { - /* are we going to list the file- it may be . or .. or a hidden file */ - if ((strcmp(entry->d_name, ".")==0) && !(disp_opts & DISP_DOT)) - continue; - if ((strcmp(entry->d_name, "..")==0) && !(disp_opts & DISP_DOT)) - continue; - if ((entry->d_name[0] == '.') && !(disp_opts & DISP_HIDDEN)) - continue; - cur= (struct dnode *)xmalloc(sizeof(struct dnode)); - cur->fullname = concat_path_file(path, entry->d_name); - cur->name = cur->fullname + - (strlen(cur->fullname) - strlen(entry->d_name)); - if (my_stat(cur)) - continue; - cur->next= dn; - dn= cur; - nfiles++; - } - closedir(dir); - - /* now that we know how many files there are - ** allocate memory for an array to hold dnode pointers - */ - if (nfiles < 1) return(NULL); - dnp= dnalloc(nfiles); - for (i=0, cur=dn; inext; - } - - return(dnp); -} - -/*----------------------------------------------------------------------*/ -static int list_single(struct dnode *dn) -{ - int i; - char scratch[BUFSIZ + 1]; -#ifdef BB_FEATURE_LS_TIMESTAMPS - char *filetime; - time_t ttime, age; -#endif -#if defined (BB_FEATURE_LS_FILETYPES) - struct stat info; -#endif -#ifdef BB_FEATURE_LS_FILETYPES - char append; -#endif - - if (dn==NULL || dn->fullname==NULL) return(0); - -#ifdef BB_FEATURE_LS_TIMESTAMPS - ttime= dn->dstat.st_mtime; /* the default time */ - if (time_fmt & TIME_ACCESS) ttime= dn->dstat.st_atime; - if (time_fmt & TIME_CHANGE) ttime= dn->dstat.st_ctime; - filetime= ctime(&ttime); -#endif -#ifdef BB_FEATURE_LS_FILETYPES - append = append_char(dn->dstat.st_mode); -#endif - - for (i=0; i<=31; i++) { - switch (list_fmt & (1<dstat.st_ino); - column += 8; - break; - case LIST_BLOCKS: -#ifdef BB_FEATURE_HUMAN_READABLE - fprintf(stdout, "%6s ", make_human_readable_str(dn->dstat.st_blocks>>1, - KILOBYTE, (ls_disp_hr==TRUE)? 0: KILOBYTE)); -#else -#if _FILE_OFFSET_BITS == 64 - printf("%4lld ", dn->dstat.st_blocks>>1); -#else - printf("%4ld ", dn->dstat.st_blocks>>1); -#endif -#endif - column += 5; - break; - case LIST_MODEBITS: - printf("%-10s ", (char *)mode_string(dn->dstat.st_mode)); - column += 10; - break; - case LIST_NLINKS: - printf("%4ld ", (long)dn->dstat.st_nlink); - column += 10; - break; - case LIST_ID_NAME: -#ifdef BB_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; -#endif - case LIST_ID_NUMERIC: - printf("%-8d %-8d", dn->dstat.st_uid, dn->dstat.st_gid); - column += 17; - break; - case LIST_SIZE: - case LIST_DEV: - if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) { - printf("%4d, %3d ", (int)MAJOR(dn->dstat.st_rdev), (int)MINOR(dn->dstat.st_rdev)); - } else { -#ifdef BB_FEATURE_HUMAN_READABLE - if (ls_disp_hr==TRUE) { - fprintf(stdout, "%8s ", make_human_readable_str(dn->dstat.st_size, 1, 0)); - } else -#endif - { -#if _FILE_OFFSET_BITS == 64 - printf("%9lld ", (long long)dn->dstat.st_size); -#else - printf("%9ld ", dn->dstat.st_size); -#endif - } - } - column += 10; - break; -#ifdef BB_FEATURE_LS_TIMESTAMPS - case LIST_FULLTIME: - case LIST_DATE_TIME: - if (list_fmt & LIST_FULLTIME) { - printf("%24.24s ", filetime); - column += 25; - break; - } - age = time(NULL) - ttime; - printf("%6.6s ", filetime+4); - if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) { - /* hh:mm if less than 6 months old */ - printf("%5.5s ", filetime+11); - } else { - printf(" %4.4s ", filetime+20); - } - column += 13; - break; -#endif - case LIST_FILENAME: - printf("%s", dn->name); - column += strlen(dn->name); - break; - case LIST_SYMLINK: - if (S_ISLNK(dn->dstat.st_mode)) { - char *lpath = xreadlink(dn->fullname); - if (lpath) { - printf(" -> %s", lpath); -#ifdef BB_FEATURE_LS_FILETYPES - if (!stat(dn->fullname, &info)) { - append = append_char(info.st_mode); - } -#endif - column += strlen(lpath) + 4; - free(lpath); - } - } - break; -#ifdef BB_FEATURE_LS_FILETYPES - case LIST_FILETYPE: - if (append != '\0') { - printf("%1c", append); - column++; - } - break; -#endif - } - } - - return(0); -} - -/*----------------------------------------------------------------------*/ -extern int ls_main(int argc, 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 BB_FEATURE_AUTOWIDTH - struct winsize win = { 0, 0, 0, 0 }; -#endif - - disp_opts= DISP_NORMAL; - style_fmt= STYLE_AUTO; - list_fmt= LIST_SHORT; -#ifdef BB_FEATURE_LS_SORTFILES - sort_opts= SORT_NAME; - sort_order= SORT_FORWARD; -#endif -#ifdef BB_FEATURE_LS_TIMESTAMPS - time_fmt= TIME_MOD; -#endif -#ifdef BB_FEATURE_AUTOWIDTH - ioctl(fileno(stdout), TIOCGWINSZ, &win); - if (win.ws_row > 4) - column_width = win.ws_row - 2; - if (win.ws_col > 0) - terminal_width = win.ws_col - 1; -#endif - nfiles=0; - - /* process options */ - while ((opt = getopt(argc, argv, "1AaCdgilnsx" -#ifdef BB_FEATURE_AUTOWIDTH -"T:w:" -#endif -#ifdef BB_FEATURE_LS_FILETYPES -"Fp" -#endif -#ifdef BB_FEATURE_LS_RECURSIVE -"R" -#endif -#ifdef BB_FEATURE_LS_SORTFILES -"rSvX" -#endif -#ifdef BB_FEATURE_LS_TIMESTAMPS -"cetu" -#endif -#ifdef BB_FEATURE_LS_FOLLOWLINKS -"L" -#endif -#ifdef BB_FEATURE_HUMAN_READABLE -"h" -#endif -"k")) > 0) { - switch (opt) { - case '1': style_fmt = STYLE_SINGLE; break; - case 'A': disp_opts |= DISP_HIDDEN; break; - case 'a': disp_opts |= DISP_HIDDEN | DISP_DOT; break; - case 'C': style_fmt = STYLE_COLUMNS; break; - case 'd': disp_opts |= DISP_NOLIST; break; - case 'g': /* ignore -- for ftp servers */ break; - case 'i': list_fmt |= LIST_INO; break; - case 'l': - style_fmt = STYLE_LONG; - list_fmt |= LIST_LONG; -#ifdef BB_FEATURE_HUMAN_READABLE - ls_disp_hr = FALSE; -#endif - break; - case 'n': list_fmt |= LIST_ID_NUMERIC; break; - case 's': list_fmt |= LIST_BLOCKS; break; - case 'x': disp_opts = DISP_ROWS; break; -#ifdef BB_FEATURE_LS_FILETYPES - case 'F': list_fmt |= LIST_FILETYPE | LIST_EXEC; break; - case 'p': list_fmt |= LIST_FILETYPE; break; -#endif -#ifdef BB_FEATURE_LS_RECURSIVE - case 'R': disp_opts |= DISP_RECURSIVE; break; -#endif -#ifdef BB_FEATURE_LS_SORTFILES - case 'r': sort_order |= SORT_REVERSE; break; - case 'S': sort_opts= SORT_SIZE; break; - case 'v': sort_opts= SORT_VERSION; break; - case 'X': sort_opts= SORT_EXT; break; -#endif -#ifdef BB_FEATURE_LS_TIMESTAMPS - case 'e': list_fmt |= LIST_FULLTIME; break; - case 'c': - time_fmt = TIME_CHANGE; -#ifdef BB_FEATURE_LS_SORTFILES - sort_opts= SORT_CTIME; -#endif - break; - case 'u': - time_fmt = TIME_ACCESS; -#ifdef BB_FEATURE_LS_SORTFILES - sort_opts= SORT_ATIME; -#endif - break; - case 't': -#ifdef BB_FEATURE_LS_SORTFILES - sort_opts= SORT_MTIME; -#endif - break; -#endif -#ifdef BB_FEATURE_LS_FOLLOWLINKS - case 'L': follow_links= TRUE; break; -#endif -#ifdef BB_FEATURE_AUTOWIDTH - case 'T': tabstops= atoi(optarg); break; - case 'w': terminal_width= atoi(optarg); break; -#endif -#ifdef BB_FEATURE_HUMAN_READABLE - case 'h': ls_disp_hr = TRUE; break; -#endif - case 'k': break; - default: - goto print_usage_message; - } - } - - /* sort out which command line options take precedence */ -#ifdef BB_FEATURE_LS_RECURSIVE - if (disp_opts & DISP_NOLIST) - disp_opts &= ~DISP_RECURSIVE; /* no recurse if listing only dir */ -#endif -#if defined (BB_FEATURE_LS_TIMESTAMPS) && defined (BB_FEATURE_LS_SORTFILES) - if (time_fmt & TIME_CHANGE) sort_opts= SORT_CTIME; - if (time_fmt & TIME_ACCESS) sort_opts= SORT_ATIME; -#endif - if (style_fmt != STYLE_LONG) - list_fmt &= ~LIST_ID_NUMERIC; /* numeric uid only for long list */ -#ifdef BB_FEATURE_LS_USERNAME - if (style_fmt == STYLE_LONG && (list_fmt & LIST_ID_NUMERIC)) - list_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */ -#endif - - /* choose a display format */ - if (style_fmt == STYLE_AUTO) - style_fmt = isatty(fileno(stdout)) ? 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]= 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 */ - } - } - - /* now, everything is in the av array */ - if (ac > 1) - disp_opts |= DISP_DIRNAME; /* 2 or more items? label directories */ - - /* stuff the command line file names into an dnode array */ - dn=NULL; - for (oi=0 ; oi < ac; oi++) { - cur= (struct dnode *)xmalloc(sizeof(struct dnode)); - cur->fullname= xstrdup(av[oi]); - cur->name= cur->fullname; - if (my_stat(cur)) - continue; - cur->next= dn; - dn= cur; - nfiles++; - } - - /* now that we know how many files there are - ** allocate memory for an array to hold dnode pointers - */ - dnp= dnalloc(nfiles); - for (i=0, cur=dn; inext; - } - - - if (disp_opts & DISP_NOLIST) { -#ifdef BB_FEATURE_LS_SORTFILES - shellsort(dnp, nfiles); -#endif - if (nfiles > 0) showfiles(dnp, nfiles); - } else { - dnd= splitdnarray(dnp, nfiles, SPLIT_DIR); - dnf= splitdnarray(dnp, nfiles, SPLIT_FILE); - dndirs= countdirs(dnp, nfiles); - dnfiles= nfiles - dndirs; - if (dnfiles > 0) { -#ifdef BB_FEATURE_LS_SORTFILES - shellsort(dnf, dnfiles); -#endif - showfiles(dnf, dnfiles); - } - if (dndirs > 0) { -#ifdef BB_FEATURE_LS_SORTFILES - shellsort(dnd, dndirs); -#endif - showdirs(dnd, dndirs); - } - } - return(status); - - print_usage_message: - show_usage(); -} diff --git a/busybox/coreutils/md5sum.c b/busybox/coreutils/md5sum.c deleted file mode 100644 index bb4d115ca..000000000 --- a/busybox/coreutils/md5sum.c +++ /dev/null @@ -1,1074 +0,0 @@ -/* md5sum.c - Compute MD5 checksum of files or strings according to the - * definition of MD5 in RFC 1321 from April 1992. - * Copyright (C) 1995-1999 Free Software Foundation, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* Written by Ulrich Drepper */ -/* 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++; - temp = 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++; - temp = 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++; - temp = 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++; - temp = 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++; - temp = 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 = wfopen(filename, "r"); - if (fp == NULL) - return FALSE; - } - - if (md5_stream(fp, md5_result)) { - perror_msg("%s", filename); - - if (fp != stdin) - fclose(fp); - return FALSE; - } - - if (fp != stdin && fclose(fp) == EOF) { - 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 = 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) { - 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)) { - error_msg("%s: read error", checkfile_name); - return FALSE; - } - - if (checkfile_stream != stdin && fclose(checkfile_stream) == EOF) { - perror_msg("md5sum: %s", checkfile_name); - return FALSE; - } - - if (n_properly_formated_lines == 0) { - /* Warn if no tests are found. */ - 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) { - 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) { - 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: - show_usage(); - } - } - - if (file_type_specified && do_check) { - error_msg_and_die("the -b and -t options are meaningless when verifying checksums"); - } - - if (n_strings > 0 && do_check) { - error_msg_and_die("the -g and -c options are mutually exclusive"); - } - - if (status_only && !do_check) { - error_msg_and_die("the -s option is meaningful only when verifying checksums"); - } - - if (warn && !do_check) { - error_msg_and_die("the -w option is meaningful only when verifying checksums"); - } - - if (n_strings > 0) { - size_t i; - - if (optind < argc) { - 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) { - 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) { - error_msg_and_die("write error"); - } - - if (have_read_stdin && fclose (stdin) == EOF) { - error_msg_and_die("standard input"); - } - - if (err == 0) - return EXIT_SUCCESS; - else - return EXIT_FAILURE; -} diff --git a/busybox/coreutils/mkdir.c b/busybox/coreutils/mkdir.c deleted file mode 100644 index 03c49f098..000000000 --- a/busybox/coreutils/mkdir.c +++ /dev/null @@ -1,64 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mkdir implementation for busybox - * - * 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "busybox.h" - -extern int mkdir_main (int argc, char **argv) -{ - mode_t mode = -1; - int flags = 0; - int status = 0; - int i, opt; - - while ((opt = getopt (argc, argv, "m:p")) != -1) { - switch (opt) { - case 'm': - mode = 0777; - if (!parse_mode (optarg, &mode)) - error_msg_and_die ("invalid mode `%s'", optarg); - break; - case 'p': - flags |= FILEUTILS_RECUR; - break; - default: - show_usage (); - } - } - - if (optind == argc) - show_usage (); - - for (i = optind; i < argc; i++) - if (make_directory (argv[i], mode, flags) < 0) - status = 1; - - return status; -} diff --git a/busybox/coreutils/mkfifo.c b/busybox/coreutils/mkfifo.c deleted file mode 100644 index ca217fa23..000000000 --- a/busybox/coreutils/mkfifo.c +++ /dev/null @@ -1,60 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mkfifo implementation for busybox - * - * Copyright (C) 1999 by Randolph Chung - * - * 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 "busybox.h" - -extern int mkfifo_main(int argc, char **argv) -{ - char *thisarg; - mode_t mode = 0666; - - argc--; - argv++; - - /* Parse any options */ - while (argc > 1) { - if (**argv != '-') - show_usage(); - thisarg = *argv; - thisarg++; - switch (*thisarg) { - case 'm': - argc--; - argv++; - parse_mode(*argv, &mode); - break; - default: - show_usage(); - } - argc--; - argv++; - } - if (argc < 1 || *argv[0] == '-') - show_usage(); - if (mkfifo(*argv, mode) < 0) - perror_msg_and_die("mkfifo"); - return EXIT_SUCCESS; -} diff --git a/busybox/coreutils/mknod.c b/busybox/coreutils/mknod.c deleted file mode 100644 index b4d4b82a1..000000000 --- a/busybox/coreutils/mknod.c +++ /dev/null @@ -1,92 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mknod implementation for busybox - * - * 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -int mknod_main(int argc, char **argv) -{ - char *thisarg; - mode_t mode = 0; - mode_t perm = 0666; - dev_t dev = 0; - - argc--; - argv++; - - /* Parse any options */ - while (argc > 1) { - if (**argv != '-') - break; - thisarg = *argv; - thisarg++; - switch (*thisarg) { - case 'm': - argc--; - argv++; - parse_mode(*argv, &perm); - umask(0); - break; - default: - show_usage(); - } - argc--; - argv++; - } - if (argc != 4 && argc != 2) { - show_usage(); - } - switch (argv[1][0]) { - case 'c': - case 'u': - mode = S_IFCHR; - break; - case 'b': - mode = S_IFBLK; - break; - case 'p': - mode = S_IFIFO; - if (argc!=2) { - show_usage(); - } - break; - default: - show_usage(); - } - - if (mode == S_IFCHR || mode == S_IFBLK) { - dev = (atoi(argv[2]) << 8) | atoi(argv[3]); - } - - mode |= perm; - - if (mknod(argv[0], mode, dev) != 0) - perror_msg_and_die("%s", argv[0]); - return EXIT_SUCCESS; -} - diff --git a/busybox/coreutils/mv.c b/busybox/coreutils/mv.c deleted file mode 100644 index b890abf6e..000000000 --- a/busybox/coreutils/mv.c +++ /dev/null @@ -1,168 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mv implementation for busybox - * - * - * Copyright (C) 2000 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 - * - */ - -#include -#include -#include -#include -#include -#include - -#include "busybox.h" - -static int flags; - -static int manual_rename(const char *source, const char *dest) -{ - struct stat source_stat; - struct stat dest_stat; - int source_exists = 1; - int dest_exists = 1; - - if (stat(source, &source_stat) < 0) { - if (errno != ENOENT) { - perror_msg("unable to stat `%s'", source); - return -1; - } - source_exists = 0; - } - - if (stat(dest, &dest_stat) < 0) { - if (errno != ENOENT) { - perror_msg("unable to stat `%s'", dest); - return -1; - } - dest_exists = 0; - } - - if (dest_exists) { - if (S_ISDIR(dest_stat.st_mode) && - (!source_exists || !S_ISDIR(source_stat.st_mode))) { - error_msg("cannot overwrite directory with non-directory"); - return -1; - } - - if (!S_ISDIR(dest_stat.st_mode) && source_exists && - S_ISDIR(source_stat.st_mode)) { - error_msg("cannot overwrite non-directory with directory"); - return -1; - } - - if (unlink(dest) < 0) { - perror_msg("cannot remove `%s'", dest); - return -1; - } - } - - if (copy_file(source, dest, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS | - FILEUTILS_PRESERVE_SYMLINKS) < 0) - return -1; - - if (remove_file(source, FILEUTILS_RECUR | FILEUTILS_FORCE) < 0) - return -1; - - return 0; -} - -static int move_file(const char *source, const char *dest) -{ - struct stat dest_stat; - int dest_exists = 1; - - if (stat(dest, &dest_stat) < 0) { - if (errno != ENOENT) { - perror_msg("unable to stat `%s'", dest); - return -1; - } - dest_exists = 0; - } - - if (dest_exists && !(flags & FILEUTILS_FORCE) && - ((access(dest, W_OK) < 0 && isatty(0)) || - (flags & FILEUTILS_INTERACTIVE))) { - fprintf(stderr, "mv: overwrite `%s'? ", dest); - if (!ask_confirmation()) - return 0; - } - - if (rename(source, dest) < 0) { - if (errno == EXDEV) - return manual_rename(source, dest); - - perror_msg("unable to rename `%s'", source); - return -1; - } - - return 0; -} - -extern int mv_main(int argc, char **argv) -{ - int status = 0; - int opt; - int i; - - while ((opt = getopt(argc, argv, "fi")) != -1) - switch (opt) { - case 'f': - flags &= ~FILEUTILS_INTERACTIVE; - flags |= FILEUTILS_FORCE; - break; - case 'i': - flags &= ~FILEUTILS_FORCE; - flags |= FILEUTILS_INTERACTIVE; - break; - default: - show_usage(); - } - - if (optind + 2 > argc) - show_usage(); - - if (optind + 2 == argc) { - struct stat dest_stat; - int dest_exists = 1; - - if (stat(argv[optind + 1], &dest_stat) < 0) { - if (errno != ENOENT) - perror_msg_and_die("unable to stat `%s'", argv[optind + 1]); - dest_exists = 0; - } - - if (!dest_exists || !S_ISDIR(dest_stat.st_mode)) { - if (move_file(argv[optind], argv[optind + 1]) < 0) - status = 1; - return status; - } - } - - for (i = optind; i < argc - 1; i++) { - char *dest = concat_path_file(argv[argc - 1], - get_last_path_component(argv[i])); - if (move_file(argv[i], dest) < 0) - status = 1; - free(dest); - } - - return status; -} diff --git a/busybox/coreutils/printf.c b/busybox/coreutils/printf.c deleted file mode 100644 index d579a9b4e..000000000 --- a/busybox/coreutils/printf.c +++ /dev/null @@ -1,455 +0,0 @@ -/* 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. - - 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. */ - -/* Usage: printf format [argument...] - - A front end to the printf function that lets it be used from the shell. - - Backslash escapes: - - \" = double quote - \\ = backslash - \a = alert (bell) - \b = backspace - \c = produce no further output - \f = form feed - \n = new line - \r = carriage return - \t = horizontal tab - \v = vertical tab - \0ooo = octal number (ooo is 0 to 3 digits) - \xhhh = hexadecimal number (hhh is 1 to 3 digits) - - Additional directive: - - %b = print an argument string, interpreting backslash escapes - - The `format' argument is re-used as many times as necessary - to convert all of the given arguments. - - David MacKenzie */ - - -// 19990508 Busy Boxed! Dave Cinege - -#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)); -static void verify __P((char *s, char *end)); - -/* The value to return to the calling program. */ -static int exit_status; - -int printf_main(int argc, char **argv) -{ - char *format; - int args_used; - - exit_status = 0; - if (argc <= 1 || **(argv + 1) == '-') { - show_usage(); - } - - format = argv[1]; - argc -= 2; - argv += 2; - - do { - args_used = print_formatted(format, argc, argv); - argc -= args_used; - argv += args_used; - } - while (args_used > 0 && argc > 0); - -/* - if (argc > 0) - fprintf(stderr, "excess args ignored"); -*/ - - return(exit_status); -} - -/* Print the text in FORMAT, using ARGV (with ARGC elements) for - arguments to any `%' directives. - Return the number of elements of ARGV used. */ - -static int print_formatted(char *format, int argc, 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) { - switch (*f) { - case '%': - direc_start = f++; - direc_length = 1; - field_width = precision = -1; - if (*f == '%') { - putchar('%'); - break; - } - if (*f == 'b') { - if (argc > 0) { - print_esc_string(*argv); - ++argv; - --argc; - } - break; - } - if (strchr("-+ #", *f)) { - ++f; - ++direc_length; - } - if (*f == '*') { - ++f; - ++direc_length; - if (argc > 0) { - field_width = xstrtoul(*argv); - ++argv; - --argc; - } else - field_width = 0; - } 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)) { - ++f; - ++direc_length; - } - } - if (*f == 'l' || *f == 'L' || *f == 'h') { - ++f; - ++direc_length; - } - /* - 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); - break; - - default: - putchar(*f); - } - } - - return save_argc - argc; -} - -/* 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) -{ - 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); - } - break; - } - - free(p); -} - -static unsigned long xstrtoul(char *s) -{ - char *end; - unsigned long val; - - errno = 0; - val = strtoul(s, &end, 0); - verify(s, end); - return val; -} - -static long xstrtol(char *s) -{ - char *end; - long val; - - errno = 0; - val = strtol(s, &end, 0); - verify(s, end); - return val; -} - -static double xstrtod(char *s) -{ - char *end; - double val; - - errno = 0; - val = strtod(s, &end); - verify(s, end); - return val; -} - -static void verify(char *s, char *end) -{ - if (errno) { - fprintf(stderr, "%s", s); - exit_status = 1; - } else if (*end) { - /* - if (s == end) - fprintf(stderr, "%s: expected numeric", s); - else - fprintf(stderr, "%s: not completely converted", s); - */ - exit_status = 1; - } -} diff --git a/busybox/coreutils/pwd.c b/busybox/coreutils/pwd.c deleted file mode 100644 index f6a00bf1e..000000000 --- a/busybox/coreutils/pwd.c +++ /dev/null @@ -1,44 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini pwd implementation for busybox - * - * - * 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 - * - */ - -/* getopt not needed */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -extern int pwd_main(int argc, char **argv) -{ - static char *buf; - - buf = xgetcwd(buf); - - if (buf != NULL) { - puts(buf); - return EXIT_SUCCESS; - } - return EXIT_FAILURE; -} diff --git a/busybox/coreutils/rm.c b/busybox/coreutils/rm.c deleted file mode 100644 index 51c9f4ceb..000000000 --- a/busybox/coreutils/rm.c +++ /dev/null @@ -1,77 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini rm implementation for busybox - * - * - * 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -extern int rm_main(int argc, char **argv) -{ - int status = 0; - int opt; - int flags = 0; - int i; - - while ((opt = getopt(argc, argv, "fiRr")) != -1) { - switch (opt) { - case 'f': - flags &= ~FILEUTILS_INTERACTIVE; - flags |= FILEUTILS_FORCE; - break; - case 'i': - flags &= ~FILEUTILS_FORCE; - flags |= FILEUTILS_INTERACTIVE; - break; - case 'R': - case 'r': - flags |= FILEUTILS_RECUR; - break; - } - } - - if (!(flags & FILEUTILS_FORCE) && optind == argc) - show_usage(); - - for (i = optind; i < argc; i++) { - char *base = get_last_path_component(argv[i]); - - if (strcmp(base, ".") == 0 || strcmp(base, "..") == 0) { - error_msg("cannot remove `.' or `..'"); - status = 1; - continue; - } - - if (remove_file(argv[i], flags) < 0) - status = 1; - } - - return status; -} diff --git a/busybox/coreutils/rmdir.c b/busybox/coreutils/rmdir.c deleted file mode 100644 index cac27cac9..000000000 --- a/busybox/coreutils/rmdir.c +++ /dev/null @@ -1,97 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini rmdir implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include - -#include "busybox.h" - - -/* Return true if a path is composed of multiple components. */ - -static int -multiple_components_p (const char *path) -{ - const char *s = path; - - while (s[0] != '\0' && s[0] != '/') - s++; - - while (s[0] == '/') - s++; - - return (s[0] != '\0'); -} - - -/* Remove a directory. Returns 0 if successful, -1 on error. */ - -static int -remove_directory (char *path, int flags) -{ - if (!(flags & FILEUTILS_RECUR)) { - if (rmdir (path) < 0) { - perror_msg ("unable to remove `%s'", path); - return -1; - } - } else { - if (remove_directory (path, 0) < 0) - return -1; - - if (multiple_components_p (path)) - if (remove_directory (dirname (path), flags) < 0) - return -1; - } - - return 0; -} - - -extern int -rmdir_main (int argc, char **argv) -{ - int status = EXIT_SUCCESS; - int flags = 0; - int i, opt; - - while ((opt = getopt (argc, argv, "p")) != -1) - switch (opt) { - case 'p': - flags |= FILEUTILS_RECUR; - break; - - default: - show_usage (); - } - - if (optind == argc) - show_usage(); - - for (i = optind; i < argc; i++) - if (remove_directory (argv[i], flags) < 0) - status = EXIT_FAILURE; - - return status; -} diff --git a/busybox/coreutils/sleep.c b/busybox/coreutils/sleep.c deleted file mode 100644 index 3bcab88ee..000000000 --- a/busybox/coreutils/sleep.c +++ /dev/null @@ -1,38 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini sleep implementation for busybox - * - * - * 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 - * - */ - -#include -#include -#include -#include "busybox.h" - -extern int sleep_main(int argc, char **argv) -{ - if ((argc < 2) || (**(argv + 1) == '-')) { - show_usage(); - } - - if (sleep(atoi(*(++argv))) != 0) - perror_msg_and_die("sleep"); - return EXIT_SUCCESS; -} diff --git a/busybox/coreutils/sort.c b/busybox/coreutils/sort.c deleted file mode 100644 index 4f4979cc5..000000000 --- a/busybox/coreutils/sort.c +++ /dev/null @@ -1,106 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini sort implementation for busybox - * - * - * Copyright (C) 2000 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 - * - */ - -#include -#include -#include -#include "busybox.h" - -static int compare_ascii(const void *x, const void *y) -{ - return strcmp(*(char **)x, *(char **)y); -} - -static int compare_numeric(const void *x, const void *y) -{ - int z = atoi(*(char **)x) - atoi(*(char **)y); - return z ? z : strcmp(*(char **)x, *(char **)y); -} - -int sort_main(int argc, char **argv) -{ - FILE *fp; - char *line, **lines = NULL; - int i, opt, nlines = 0; - int (*compare)(const void *, const void *) = compare_ascii; -#ifdef BB_FEATURE_SORT_REVERSE - int reverse = FALSE; -#endif -#ifdef BB_FEATURE_SORT_UNIQUE - int unique = FALSE; -#endif - - while ((opt = getopt(argc, argv, "nru")) != -1) { - switch (opt) { - case 'n': - compare = compare_numeric; - break; -#ifdef BB_FEATURE_SORT_REVERSE - case 'r': - reverse = TRUE; - break; -#endif -#ifdef BB_FEATURE_SORT_UNIQUE - case 'u': - unique = TRUE; - break; -#endif - default: - show_usage(); - } - } - - /* read the input */ - for (i = optind; i == optind || i < argc; i++) { - if (argv[i] == NULL) - fp = stdin; - else - fp = xfopen(argv[i], "r"); - - while ((line = get_line_from_file(fp)) != NULL) { - lines = xrealloc(lines, sizeof(char *) * (nlines + 1)); - chomp(line); - lines[nlines++] = line; - } - } - - /* sort it */ - qsort(lines, nlines, sizeof(char *), compare); - - /* print it */ -#ifdef BB_FEATURE_SORT_REVERSE - if (reverse) { - for (i = --nlines; 0 <= i; i--) -#ifdef BB_FEATURE_SORT_UNIQUE - if((!unique) || (i == nlines) || (strcmp(lines[i + 1], lines[i]))) -#endif - puts(lines[i]); - } else -#endif - for (i = 0; i < nlines; i++) -#ifdef BB_FEATURE_SORT_UNIQUE - if((!unique) || (!i) || (strcmp(lines[i - 1], lines[i]))) -#endif - puts(lines[i]); - return EXIT_SUCCESS; -} diff --git a/busybox/coreutils/stty.c b/busybox/coreutils/stty.c deleted file mode 100644 index 2e00a496d..000000000 --- a/busybox/coreutils/stty.c +++ /dev/null @@ -1,1376 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* 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. */ - -/* Usage: stty [-ag] [-F device] [setting...] - - Options: - -a Write all current settings to stdout in human-readable form. - -g Write all current settings to stdout in stty-readable form. - -F Open and use the specified device instead of stdin - - If no args are given, write to stdout the baud rate and settings that - have been changed from their defaults. Mode reading and changes - are done on the specified device, or stdin if none was specified. - - David MacKenzie - - Special for busybox ported by Vladimir Oleynik 2001 - - */ - -//#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) - - -#ifndef _POSIX_VDISABLE -# define _POSIX_VDISABLE ((unsigned char) 0) -#endif - -#define Control(c) ((c) & 0x1f) -/* Canonical values for control characters. */ -#ifndef CINTR -# define CINTR Control ('c') -#endif -#ifndef CQUIT -# define CQUIT 28 -#endif -#ifndef CERASE -# define CERASE 127 -#endif -#ifndef CKILL -# define CKILL Control ('u') -#endif -#ifndef CEOF -# define CEOF Control ('d') -#endif -#ifndef CEOL -# define CEOL _POSIX_VDISABLE -#endif -#ifndef CSTART -# define CSTART Control ('q') -#endif -#ifndef CSTOP -# define CSTOP Control ('s') -#endif -#ifndef CSUSP -# 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. */ -#if defined(VSUSP) && !defined(VSWTCH) -# define VSWTCH VSUSP -# define CSWTCH CSUSP -#endif -#if defined(VSWTCH) && !defined(CSWTCH) -# 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__) -# undef CSWTCH -# define CSWTCH _POSIX_VDISABLE -#endif - -#if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */ -# define VWERASE VWERSE -#endif -#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') -#endif -#if defined(VWERASE) && !defined(CWERASE) -# define CWERASE Control ('w') -#endif -#if defined(VLNEXT) && !defined(CLNEXT) -# define CLNEXT Control ('v') -#endif -#if defined(VDISCARD) && !defined(VFLUSHO) -# define VFLUSHO VDISCARD -#endif -#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */ -# define VFLUSHO VFLUSH -#endif -#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */ -# define ECHOCTL CTLECH -#endif -#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */ -# define ECHOCTL TCTLECH -#endif -#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */ -# define ECHOKE CRTKIL -#endif -#if defined(VFLUSHO) && !defined(CFLUSHO) -# define CFLUSHO Control ('o') -#endif -#if defined(VSTATUS) && !defined(CSTATUS) -# define CSTATUS Control ('t') -#endif - -/* Which speeds to set. */ -enum speed_setting { - input_speed, output_speed, both_speeds -}; - -/* What to output and how. */ -enum output_type { - changed, all, recoverable /* Default, -a, -g. */ -}; - -/* Which member(s) of `struct termios' a mode uses. */ -enum mode_type { - control, input, output, local, combination -}; - - -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. */ -struct mode_info { - const char *name; /* Name given on command line. */ - enum mode_type type; /* Which structure element to change. */ - char flags; /* Setting and display options. */ - unsigned long bits; /* Bits to set for this mode. */ - unsigned long mask; /* Other bits to turn off for this mode. */ -}; - -static const struct mode_info mode_info[] = { - {"parenb", control, REV, PARENB, 0 }, - {"parodd", control, REV, PARODD, 0 }, - {"cs5", control, 0, CS5, CSIZE}, - {"cs6", control, 0, CS6, CSIZE}, - {"cs7", control, 0, CS7, CSIZE}, - {"cs8", control, 0, CS8, CSIZE}, - {"hupcl", control, REV, HUPCL, 0 }, - {"hup", control, REV | OMIT, HUPCL, 0 }, - {"cstopb", control, REV, CSTOPB, 0 }, - {"cread", control, SANE_SET | REV, CREAD, 0 }, - {"clocal", control, REV, CLOCAL, 0 }, -#ifdef CRTSCTS - {"crtscts", control, REV, CRTSCTS, 0 }, -#endif - {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 }, - {"brkint", input, SANE_SET | REV, BRKINT, 0 }, - {"ignpar", input, REV, IGNPAR, 0 }, - {"parmrk", input, REV, PARMRK, 0 }, - {"inpck", input, REV, INPCK, 0 }, - {"istrip", input, REV, ISTRIP, 0 }, - {"inlcr", input, SANE_UNSET | REV, INLCR, 0 }, - {"igncr", input, SANE_UNSET | REV, IGNCR, 0 }, - {"icrnl", input, SANE_SET | REV, ICRNL, 0 }, - {"ixon", input, REV, IXON, 0 }, - {"ixoff", input, SANE_UNSET | REV, IXOFF, 0 }, - {"tandem", input, REV | OMIT, IXOFF, 0 }, -#ifdef IUCLC - {"iuclc", input, SANE_UNSET | REV, IUCLC, 0 }, -#endif -#ifdef IXANY - {"ixany", input, SANE_UNSET | REV, IXANY, 0 }, -#endif -#ifdef IMAXBEL - {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0 }, -#endif - {"opost", output, SANE_SET | REV, OPOST, 0 }, -#ifdef OLCUC - {"olcuc", output, SANE_UNSET | REV, OLCUC, 0 }, -#endif -#ifdef OCRNL - {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0 }, -#endif -#ifdef ONLCR - {"onlcr", output, SANE_SET | REV, ONLCR, 0 }, -#endif -#ifdef ONOCR - {"onocr", output, SANE_UNSET | REV, ONOCR, 0 }, -#endif -#ifdef ONLRET - {"onlret", output, SANE_UNSET | REV, ONLRET, 0 }, -#endif -#ifdef OFILL - {"ofill", output, SANE_UNSET | REV, OFILL, 0 }, -#endif -#ifdef OFDEL - {"ofdel", output, SANE_UNSET | REV, OFDEL, 0 }, -#endif -#ifdef NLDLY - {"nl1", output, SANE_UNSET, NL1, NLDLY}, - {"nl0", output, SANE_SET, NL0, NLDLY}, -#endif -#ifdef CRDLY - {"cr3", output, SANE_UNSET, CR3, CRDLY}, - {"cr2", output, SANE_UNSET, CR2, CRDLY}, - {"cr1", output, SANE_UNSET, CR1, CRDLY}, - {"cr0", output, SANE_SET, CR0, CRDLY}, -#endif - -#ifdef TABDLY - {"tab3", output, SANE_UNSET, TAB3, TABDLY}, - {"tab2", output, SANE_UNSET, TAB2, TABDLY}, - {"tab1", output, SANE_UNSET, TAB1, TABDLY}, - {"tab0", output, SANE_SET, TAB0, TABDLY}, -#else -# ifdef OXTABS - {"tab3", output, SANE_UNSET, OXTABS, 0 }, -# endif -#endif - -#ifdef BSDLY - {"bs1", output, SANE_UNSET, BS1, BSDLY}, - {"bs0", output, SANE_SET, BS0, BSDLY}, -#endif -#ifdef VTDLY - {"vt1", output, SANE_UNSET, VT1, VTDLY}, - {"vt0", output, SANE_SET, VT0, VTDLY}, -#endif -#ifdef FFDLY - {"ff1", output, SANE_UNSET, FF1, FFDLY}, - {"ff0", output, SANE_SET, FF0, FFDLY}, -#endif - {"isig", local, SANE_SET | REV, ISIG, 0 }, - {"icanon", local, SANE_SET | REV, ICANON, 0 }, -#ifdef IEXTEN - {"iexten", local, SANE_SET | REV, IEXTEN, 0 }, -#endif - {"echo", local, SANE_SET | REV, ECHO, 0 }, - {"echoe", local, SANE_SET | REV, ECHOE, 0 }, - {"crterase", local, REV | OMIT, ECHOE, 0 }, - {"echok", local, SANE_SET | REV, ECHOK, 0 }, - {"echonl", local, SANE_UNSET | REV, ECHONL, 0 }, - {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0 }, -#ifdef XCASE - {"xcase", local, SANE_UNSET | REV, XCASE, 0 }, -#endif -#ifdef TOSTOP - {"tostop", local, SANE_UNSET | REV, TOSTOP, 0 }, -#endif -#ifdef ECHOPRT - {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 }, - {"prterase", local, REV | OMIT, ECHOPRT, 0 }, -#endif -#ifdef ECHOCTL - {"echoctl", local, SANE_SET | REV, ECHOCTL, 0 }, - {"ctlecho", local, REV | OMIT, ECHOCTL, 0 }, -#endif -#ifdef ECHOKE - {"echoke", local, SANE_SET | REV, ECHOKE, 0 }, - {"crtkill", local, REV | OMIT, ECHOKE, 0 }, -#endif - {evenp, combination, REV | OMIT, 0, 0 }, - {parity, combination, REV | OMIT, 0, 0 }, - {stty_oddp, combination, REV | OMIT, 0, 0 }, - {stty_nl, combination, REV | OMIT, 0, 0 }, - {stty_ek, combination, OMIT, 0, 0 }, - {stty_sane, combination, OMIT, 0, 0 }, - {cooked, combination, REV | OMIT, 0, 0 }, - {raw, combination, REV | OMIT, 0, 0 }, - {stty_pass8, combination, REV | OMIT, 0, 0 }, - {litout, combination, REV | OMIT, 0, 0 }, - {cbreak, combination, REV | OMIT, 0, 0 }, -#ifdef IXANY - {decctlq, combination, REV | OMIT, 0, 0 }, -#endif -#if defined (TABDLY) || defined (OXTABS) - {stty_tabs, combination, REV | OMIT, 0, 0 }, -#endif -#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) - {stty_lcase, combination, REV | OMIT, 0, 0 }, - {stty_LCASE, combination, REV | OMIT, 0, 0 }, -#endif - {stty_crt, combination, OMIT, 0, 0 }, - {stty_dec, combination, OMIT, 0, 0 }, -}; - -static const int NUM_mode_info = - - (sizeof(mode_info) / sizeof(struct mode_info)); - -/* Control character settings. */ -struct control_info { - const char *name; /* Name given on command line. */ - unsigned char saneval; /* Value to set for `stty sane'. */ - int 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}, -#ifdef VEOL2 - {"eol2", CEOL2, VEOL2}, -#endif -#ifdef VSWTCH - {stty_swtch, CSWTCH, VSWTCH}, -#endif - {"start", CSTART, VSTART}, - {"stop", CSTOP, VSTOP}, - {"susp", CSUSP, VSUSP}, -#ifdef VDSUSP - {"dsusp", CDSUSP, VDSUSP}, -#endif -#ifdef VREPRINT - {"rprnt", CRPRNT, VREPRINT}, -#endif -#ifdef VWERASE - {"werase", CWERASE, VWERASE}, -#endif -#ifdef VLNEXT - {"lnext", CLNEXT, VLNEXT}, -#endif -#ifdef VFLUSHO - {"flush", CFLUSHO, VFLUSHO}, -#endif -#ifdef VSTATUS - {"status", CSTATUS, VSTATUS}, -#endif - /* These must be last because of the display routines. */ - {stty_min, 1, VMIN}, - {stty_time, 0, VTIME}, -}; - -static const int NUM_control_info = - (sizeof(control_info) / sizeof(struct control_info)); - - -static const char * visible(unsigned int ch); -static unsigned long baud_to_value(speed_t speed); -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, - const char *device_name); -static void display_changed(struct termios *mode); -static void display_recoverable(struct termios *mode); -static void display_settings(enum output_type output_type, - struct termios *mode, int fd, - const char *device_name); -static void display_speed(struct termios *mode, int fancy); -static void display_window_size(int fancy, int fd, - const char *device_name); -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, - const char *device_name); - -/* The width of the screen, for output wrapping. */ -static int max_col; - -/* Current position, to know when to wrap. */ -static int current_col; - -/* Print format string MESSAGE and optional args. - Wrap to next line first if it won't fit. - Print a space first unless MESSAGE will start a new line. */ - -static void wrapf(const char *message, ...) -{ - va_list args; - char buf[1024]; /* Plenty long for our needs. */ - int buflen; - - va_start(args, message); - vsprintf(buf, message, args); - va_end(args); - buflen = strlen(buf); - if (current_col + (current_col > 0) + buflen >= max_col) { - putchar('\n'); - current_col = 0; - } - if (current_col > 0) { - putchar(' '); - current_col++; - } - fputs(buf, stdout); - current_col += buflen; -} - -static const struct suffix_mult stty_suffixes[] = { - {"b", 512 }, - {"k", 1024}, - {"B", 1024}, - {NULL, 0 } -}; - -#ifndef TEST -extern int stty_main(int argc, char **argv) -#else -extern int main(int argc, char **argv) -#endif -{ - struct termios mode; - enum output_type output_type; - 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; - const char *device_name; - - output_type = 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_type = all; - break; - - case 'g': - recoverable_output = 1; - output_type = recoverable; - break; - - case 'F': - if (file_name) - error_msg_and_die("only one device may be specified"); - file_name = optarg; - break; - - default: /* unrecognized option */ - noargs = 0; - break; - } - - if (noargs == 0) - break; - } - - if (optind < argc) - noargs = 0; - - /* Specifying both -a and -g gets an error. */ - if (verbose_output && recoverable_output) - error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive"); - - /* Specifying any other arguments with -a or -g gets an error. */ - if (!noargs && (verbose_output || recoverable_output)) - error_msg_and_die ("modes may not be set when specifying an output style"); - - /* FIXME: it'd be better not to open the file until we've verified - that all arguments are valid. Otherwise, we could end up doing - only some of the requested operations and then failing, probably - leaving things in an undesirable state. */ - - if (file_name) { - int fdflags; - - device_name = file_name; - fd = open(device_name, O_RDONLY | O_NONBLOCK); - if (fd < 0) - perror_msg_and_die("%s", device_name); - if ((fdflags = fcntl(fd, F_GETFL)) == -1 - || fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) - perror_msg_and_die("%s: couldn't reset non-blocking mode", - device_name); - } else { - fd = 0; - device_name = "standard input"; - } - - /* Initialize to all zeroes so there is no risk memcmp will report a - spurious difference in an uninitialized portion of the structure. */ - memset(&mode, 0, sizeof(mode)); - if (tcgetattr(fd, &mode)) - perror_msg_and_die("%s", device_name); - - if (verbose_output || recoverable_output || noargs) { - max_col = screen_columns(); - current_col = 0; - display_settings(output_type, &mode, fd, device_name); - return EXIT_SUCCESS; - } - - speed_was_set = 0; - require_set_attr = 0; - k = optind; - while (k < argc) { - int match_found = 0; - int reversed = 0; - int i; - - if (argv[k][0] == '-') { - ++argv[k]; - reversed = 1; - } - for (i = 0; i < NUM_mode_info; ++i) - if (STREQ(argv[k], mode_info[i].name)) { - match_found = set_mode(&mode_info[i], reversed, &mode); - require_set_attr = 1; - break; - } - - if (match_found == 0 && reversed) - 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) - error_msg_and_die("missing argument to `%s'", argv[k]); - match_found = 1; - ++k; - set_control_char(&control_info[i], argv[k], &mode); - require_set_attr = 1; - break; - } - - if (match_found == 0) { - if (STREQ(argv[k], "ispeed")) { - if (k == argc - 1) - 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) - 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) - error_msg_and_die("missing argument to `%s'", argv[k]); - ++k; - set_window_size((int) parse_number(argv[k], stty_suffixes), - -1, fd, device_name); - } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) { - if (k == argc - 1) - error_msg_and_die("missing argument to `%s'", argv[k]); - ++k; - set_window_size(-1, - (int) parse_number(argv[k], stty_suffixes), - fd, device_name); - } else if (STREQ(argv[k], "size")) { - max_col = screen_columns(); - current_col = 0; - display_window_size(0, fd, device_name); - } -#endif -#ifdef HAVE_C_LINE - else if (STREQ(argv[k], "line")) { - if (k == argc - 1) - error_msg_and_die("missing argument to `%s'", argv[k]); - ++k; - mode.c_line = parse_number(argv[k], stty_suffixes); - require_set_attr = 1; - } -#endif - else if (STREQ(argv[k], "speed")) { - max_col = screen_columns(); - display_speed(&mode, 0); - } else if (recover_mode(argv[k], &mode) == 1) - require_set_attr = 1; - else if (string_to_baud(argv[k]) != (speed_t) - 1) { - set_speed(both_speeds, argv[k], &mode); - speed_was_set = 1; - require_set_attr = 1; - } else - error_msg_and_die("invalid argument `%s'", argv[k]); - } - k++; - } - - if (require_set_attr) { - struct termios new_mode; - - if (tcsetattr(fd, TCSADRAIN, &mode)) - perror_msg_and_die("%s", device_name); - - /* POSIX (according to Zlotnick's book) tcsetattr returns zero if - it performs *any* of the requested operations. This means it - can report `success' when it has actually failed to perform - some proper subset of the requested operations. To detect - this partial failure, get the current terminal attributes and - compare them to the requested ones. */ - - /* Initialize to all zeroes so there is no risk memcmp will report a - spurious difference in an uninitialized portion of the structure. */ - memset(&new_mode, 0, sizeof(new_mode)); - if (tcgetattr(fd, &new_mode)) - perror_msg_and_die("%s", device_name); - - /* Normally, one shouldn't use memcmp to compare structures that - may have `holes' containing uninitialized data, but we have been - careful to initialize the storage of these two variables to all - zeroes. One might think it more efficient simply to compare the - modified fields, but that would require enumerating those fields -- - and not all systems have the same fields in this structure. */ - - if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) { -#ifdef CIBAUD - /* SunOS 4.1.3 (at least) has the problem that after this sequence, - tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2); - sometimes (m1 != m2). The only difference is in the four bits - of the c_cflag field corresponding to the baud rate. To save - Sun users a little confusion, don't report an error if this - happens. But suppress the error only if we haven't tried to - set the baud rate explicitly -- otherwise we'd never give an - error for a true failure to set the baud rate. */ - - new_mode.c_cflag &= (~CIBAUD); - if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0) -#endif - error_msg_and_die ("%s: unable to perform all requested operations", - device_name); - } - } - - return EXIT_SUCCESS; -} - -/* Return 0 if not applied because not reversible; otherwise return 1. */ - -static int -set_mode(const struct mode_info *info, int reversed, struct termios *mode) -{ - tcflag_t *bitsp; - - if (reversed && (info->flags & REV) == 0) - return 0; - - bitsp = mode_type_flag(info->type, mode); - - if (bitsp == NULL) { - /* Combination mode. */ - if (info->name == evenp || info->name == parity) { - if (reversed) - mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; - else - mode->c_cflag = - (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7; - } else if (info->name == stty_oddp) { - if (reversed) - mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; - else - mode->c_cflag = - (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB; - } else if (info->name == stty_nl) { - if (reversed) { - mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR; - mode->c_oflag = (mode->c_oflag -#ifdef ONLCR - | ONLCR -#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 & ~info->mask & ~info->bits; - else - *bitsp = (*bitsp & ~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 = parse_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 = parse_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 == input_speed || type == both_speeds) - cfsetispeed(mode, baud); - if (type == output_speed || type == both_speeds) - 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, const char *device_name) -{ - struct winsize win; - - if (get_win_size(fd, &win)) { - if (errno != EINVAL) - perror_msg_and_die("%s", device_name); - 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 = 1; - win.ws_col = 1; - - if (ioctl(fd, TIOCSWINSZ, (char *) &win)) - perror_msg_and_die("%s", device_name); - - if (ioctl(fd, TIOCSSIZE, (char *) &ttysz)) - perror_msg_and_die("%s", device_name); - return; - } -# endif - - if (ioctl(fd, TIOCSWINSZ, (char *) &win)) - perror_msg_and_die("%s", device_name); -} - -static void display_window_size(int fancy, int fd, const char *device_name) -{ - struct winsize win; - - if (get_win_size(fd, &win)) { - if (errno != EINVAL) - perror_msg_and_die("%s", device_name); - if (!fancy) - perror_msg_and_die("%s: no size information for this device", - device_name); - } else { - wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n", - win.ws_row, win.ws_col); - if (!fancy) - current_col = 0; - } -} -#endif - -static int screen_columns(void) -{ -#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 - - if (getenv("COLUMNS")) - return atoi(getenv("COLUMNS")); - return 80; -} - -static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode) -{ - switch (type) { - case control: - return &mode->c_cflag; - - case input: - return &mode->c_iflag; - - case output: - return &mode->c_oflag; - - case local: - return &mode->c_lflag; - - default: /* combination: */ - return NULL; - } -} - -static void -display_settings(enum output_type output_type, struct termios *mode, - int fd, const char *device_name) -{ - switch (output_type) { - case changed: - display_changed(mode); - break; - - case all: - display_all(mode, fd, device_name); - break; - - case recoverable: - display_recoverable(mode); - break; - } -} - -static void display_changed(struct termios *mode) -{ - int i; - int empty_line; - tcflag_t *bitsp; - unsigned long mask; - enum mode_type prev_type = control; - - display_speed(mode, 1); -#ifdef HAVE_C_LINE - wrapf("line = %d;", mode->c_line); -#endif - putchar('\n'); - current_col = 0; - - empty_line = 1; - for (i = 0; control_info[i].name != stty_min; ++i) { - if (mode->c_cc[control_info[i].offset] == control_info[i].saneval) - continue; - /* If swtch is the same as susp, don't print both. */ -#if VSWTCH == VSUSP - if (control_info[i].name == stty_swtch) - continue; -#endif - /* If eof uses the same slot as min, only print whichever applies. */ -#if VEOF == VMIN - if ((mode->c_lflag & ICANON) == 0 - && (control_info[i].name == stty_eof - || control_info[i].name == stty_eol)) continue; -#endif - - empty_line = 0; - wrapf("%s = %s;", control_info[i].name, - visible(mode->c_cc[control_info[i].offset])); - } - if ((mode->c_lflag & ICANON) == 0) { - wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN], - (int) mode->c_cc[VTIME]); - } else if (empty_line == 0) - putchar('\n'); - current_col = 0; - - empty_line = 1; - for (i = 0; i < NUM_mode_info; ++i) { - if (mode_info[i].flags & OMIT) - continue; - if (mode_info[i].type != prev_type) { - if (empty_line == 0) { - putchar('\n'); - current_col = 0; - empty_line = 1; - } - prev_type = mode_info[i].type; - } - - bitsp = mode_type_flag(mode_info[i].type, mode); - mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; - if ((*bitsp & mask) == mode_info[i].bits) { - if (mode_info[i].flags & SANE_UNSET) { - wrapf("%s", mode_info[i].name); - empty_line = 0; - } - } - else if ((mode_info[i].flags & (SANE_SET | REV)) == - (SANE_SET | REV)) { - wrapf("-%s", mode_info[i].name); - empty_line = 0; - } - } - if (empty_line == 0) - putchar('\n'); - current_col = 0; -} - -static void -display_all(struct termios *mode, int fd, const char *device_name) -{ - 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, device_name); -#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; -#endif - wrapf("%s = %s;", control_info[i].name, - visible(mode->c_cc[control_info[i].offset])); - } -#if VEOF == VMIN - if ((mode->c_lflag & ICANON) == 0) -#endif - wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]); - if (current_col != 0) - putchar('\n'); - current_col = 0; - - 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; - } - - 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) -{ - if (cfgetispeed(mode) == 0 || cfgetispeed(mode) == cfgetospeed(mode)) - wrapf(fancy ? "speed %lu baud;" : "%lu\n", - baud_to_value(cfgetospeed(mode))); - else - wrapf(fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n", - baud_to_value(cfgetispeed(mode)), - baud_to_value(cfgetospeed(mode))); - if (!fancy) - current_col = 0; -} - -static void display_recoverable(struct termios *mode) -{ - int i; - - printf("%lx:%lx:%lx:%lx", - (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag, - (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag); - for (i = 0; i < NCCS; ++i) - printf(":%x", (unsigned int) mode->c_cc[i]); - putchar('\n'); -} - -static int recover_mode(char *arg, struct termios *mode) -{ - int i, n; - unsigned int chr; - unsigned long iflag, oflag, cflag, lflag; - - /* Scan into temporaries since it is too much trouble to figure out - the right format for `tcflag_t'. */ - if (sscanf(arg, "%lx:%lx:%lx:%lx%n", - &iflag, &oflag, &cflag, &lflag, &n) != 4) - return 0; - mode->c_iflag = iflag; - mode->c_oflag = oflag; - mode->c_cflag = cflag; - mode->c_lflag = lflag; - arg += n; - for (i = 0; i < NCCS; ++i) { - if (sscanf(arg, ":%x%n", &chr, &n) != 1) - return 0; - mode->c_cc[i] = chr; - arg += n; - } - - /* Fail if there are too many fields. */ - if (*arg != '\0') - return 0; - - return 1; -} - -struct speed_map { - speed_t speed; /* Internal form. */ - unsigned long value; /* Numeric value. */ -}; - -static const struct speed_map speeds[] = { - {B0, 0}, - {B50, 50}, - {B75, 75}, - {B110, 110}, - {B134, 134}, - {B150, 150}, - {B200, 200}, - {B300, 300}, - {B600, 600}, - {B1200, 1200}, - {B1800, 1800}, - {B2400, 2400}, - {B4800, 4800}, - {B9600, 9600}, - {B19200, 19200}, - {B38400, 38400}, -#ifdef B57600 - {B57600, 57600}, -#endif -#ifdef B115200 - {B115200, 115200}, -#endif -#ifdef B230400 - {B230400, 230400}, -#endif -#ifdef B460800 - {B460800, 460800}, -#endif -}; - -static const int NUM_SPEEDS = (sizeof(speeds) / sizeof(struct speed_map)); - -static speed_t string_to_baud(const char *arg) -{ - int i; - - for (i = 0; i < NUM_SPEEDS; ++i) - if (parse_number(arg, 0) == speeds[i].value) - return speeds[i].speed; - return (speed_t) - 1; -} - -static unsigned long baud_to_value(speed_t speed) -{ - int i; - - for (i = 0; i < NUM_SPEEDS; ++i) - if (speed == speeds[i].speed) - return speeds[i].value; - return 0; -} - -static void sane_mode(struct termios *mode) -{ - int i; - tcflag_t *bitsp; - - for (i = 0; i < NUM_control_info; ++i) { -#if VMIN == VEOF - if (control_info[i].name == stty_min) - break; -#endif - mode->c_cc[control_info[i].offset] = control_info[i].saneval; - } - - 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 & ~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 & ~mode_info[i].mask & ~mode_info[i].bits; - } - } -} - -/* 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; - - if (ch == _POSIX_VDISABLE) - return ""; - - if (ch >= 32) { - if (ch < 127) - *bpout++ = ch; - else if (ch == 127) { - *bpout++ = '^'; - *bpout++ = '?'; - } else { - *bpout++ = 'M', *bpout++ = '-'; - if (ch >= 128 + 32) { - if (ch < 128 + 127) - *bpout++ = ch - 128; - else { - *bpout++ = '^'; - *bpout++ = '?'; - } - } else { - *bpout++ = '^'; - *bpout++ = ch - 128 + 64; - } - } - } else { - *bpout++ = '^'; - *bpout++ = ch + 64; - } - *bpout = '\0'; - return (const char *) buf; -} - -#ifdef TEST - -const char *applet_name = "stty"; - -#endif - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/coreutils/sync.c b/busybox/coreutils/sync.c deleted file mode 100644 index ee22ae109..000000000 --- a/busybox/coreutils/sync.c +++ /dev/null @@ -1,35 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini sync implementation for busybox - * - * - * 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 - * - */ - -#include -#include -#include -#include "busybox.h" - -extern int sync_main(int argc, char **argv) -{ - if (argc > 1 && **(argv + 1) == '-') - show_usage(); - sync(); - return(EXIT_SUCCESS); -} diff --git a/busybox/coreutils/tail.c b/busybox/coreutils/tail.c deleted file mode 100644 index 90cc2a6ef..000000000 --- a/busybox/coreutils/tail.c +++ /dev/null @@ -1,251 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini tail implementation for busybox - * - * - * 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 - * - */ - - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -static const struct suffix_mult tail_suffixes[] = { - { "b", 512 }, - { "k", 1024 }, - { "m", 1048576 }, - { NULL, 0 } -}; - -static const int BYTES = 0; -static const int LINES = 1; - -static char *tailbuf; -static int taillen; -static int newline; - -static void tailbuf_append(char *buf, int len) -{ - tailbuf = xrealloc(tailbuf, taillen + len); - memcpy(tailbuf + taillen, buf, len); - taillen += len; -} - -static void tailbuf_trunc() -{ - char *s; - s = memchr(tailbuf, '\n', taillen); - memmove(tailbuf, s + 1, taillen - ((s + 1) - tailbuf)); - taillen -= (s + 1) - tailbuf; - newline = 0; -} - -int tail_main(int argc, char **argv) -{ - int from_top = 0, units = LINES, count = 10, sleep_period = 1; - int show_headers = 0, hide_headers = 0, follow = 0; - int *fds, nfiles = 0, status = EXIT_SUCCESS, nread, nwrite, seen = 0; - char *s, *start, *end, buf[BUFSIZ]; - int i, opt; - - while ((opt = getopt(argc, argv, "c:fhn:q:s:v")) > 0) { - switch (opt) { - case 'f': - follow = 1; - break; -#ifdef BB_FEATURE_FANCY_TAIL - case 'c': - units = BYTES; - /* FALLS THROUGH */ -#endif - case 'n': - count = parse_number(optarg, tail_suffixes); - if (count < 0) - count = -count; - if (optarg[0] == '+') - from_top = 1; - break; -#ifdef BB_FEATURE_FANCY_TAIL - case 'q': - hide_headers = 1; - break; - case 's': - sleep_period = parse_number(optarg, 0); - break; - case 'v': - show_headers = 1; - break; -#endif - default: - show_usage(); - } - } - - /* open all the files */ - fds = (int *)xmalloc(sizeof(int) * (argc - optind + 1)); - if (argc == optind) { - fds[nfiles++] = STDIN_FILENO; - argv[optind] = "standard input"; - } else { - for (i = optind; i < argc; i++) { - if (strcmp(argv[i], "-") == 0) { - fds[nfiles++] = STDIN_FILENO; - argv[i] = "standard input"; - } else if ((fds[nfiles++] = open(argv[i], O_RDONLY)) < 0) { - perror_msg("%s", argv[i]); - status = EXIT_FAILURE; - } - } - } - -#ifdef BB_FEATURE_FANCY_TAIL - /* tail the files */ - if (!from_top && units == BYTES) - tailbuf = xmalloc(count); -#endif - - for (i = 0; i < nfiles; i++) { - if (fds[i] == -1) - continue; - if (!count) { - lseek(fds[i], 0, SEEK_END); - continue; - } - seen = 0; - if (show_headers || (!hide_headers && nfiles > 1)) - printf("%s==> %s <==\n", i == 0 ? "" : "\n", argv[optind + i]); - while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) { - if (from_top) { -#ifdef BB_FEATURE_FANCY_TAIL - if (units == BYTES) { - if (count - 1 <= seen) - nwrite = nread; - else if (count - 1 <= seen + nread) - nwrite = nread + seen - (count - 1); - else - nwrite = 0; - seen += nread; - } else { -#else - { -#endif - if (count - 1 <= seen) - nwrite = nread; - else { - nwrite = 0; - for (s = memchr(buf, '\n', nread); s != NULL; - s = memchr(s+1, '\n', nread - (s + 1 - buf))) { - if (count - 1 <= ++seen) { - nwrite = nread - (s + 1 - buf); - break; - } - } - } - } - if (full_write(STDOUT_FILENO, buf + nread - nwrite, - nwrite) < 0) { - perror_msg("write"); - status = EXIT_FAILURE; - break; - } - } else { -#ifdef BB_FEATURE_FANCY_TAIL - if (units == BYTES) { - if (nread < count) { - memmove(tailbuf, tailbuf + nread, count - nread); - memcpy(tailbuf + count - nread, buf, nread); - } else { - memcpy(tailbuf, buf + nread - count, count); - } - seen += nread; - } else { -#else - { -#endif - for (start = buf, end = memchr(buf, '\n', nread); - end != NULL; start = end+1, - end = memchr(start, '\n', nread - (start - buf))) { - if (newline && count <= seen) - tailbuf_trunc(); - tailbuf_append(start, end - start + 1); - seen++; - newline = 1; - } - if (newline && count <= seen && nread - (start - buf) > 0) - tailbuf_trunc(); - tailbuf_append(start, nread - (start - buf)); - } - } - } - - if (nread < 0) { - perror_msg("read"); - status = EXIT_FAILURE; - } - -#ifdef BB_FEATURE_FANCY_TAIL - if (!from_top && units == BYTES) { - if (count < seen) - seen = count; - if (full_write(STDOUT_FILENO, tailbuf + count - seen, seen) < 0) { - perror_msg("write"); - status = EXIT_FAILURE; - } - } -#endif - - if (!from_top && units == LINES) { - if (full_write(STDOUT_FILENO, tailbuf, taillen) < 0) { - perror_msg("write"); - status = EXIT_FAILURE; - } - } - - taillen = 0; - } - - while (follow) { - sleep(sleep_period); - - for (i = 0; i < nfiles; i++) { - if (fds[i] == -1) - continue; - - if ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) { - if (show_headers || (!hide_headers && nfiles > 1)) - printf("\n==> %s <==\n", argv[optind + i]); - - do { - full_write(STDOUT_FILENO, buf, nread); - } while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0); - } - - if (nread < 0) { - perror_msg("read"); - status = EXIT_FAILURE; - } - } - } - - return status; -} diff --git a/busybox/coreutils/tee.c b/busybox/coreutils/tee.c deleted file mode 100644 index 439cf7dc5..000000000 --- a/busybox/coreutils/tee.c +++ /dev/null @@ -1,68 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini tee implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include "busybox.h" -#include -#include - -int -tee_main(int argc, char **argv) -{ - char *mode = "w"; - int c, i, status = 0, nfiles = 0; - FILE **files; - - while ((c = getopt(argc, argv, "a")) != EOF) { - switch (c) { - case 'a': - mode = "a"; - break; - default: - show_usage(); - } - } - - files = (FILE **)xmalloc(sizeof(FILE *) * (argc - optind + 1)); - files[nfiles++] = stdout; - while (optind < argc) { - if ((files[nfiles++] = fopen(argv[optind++], mode)) == NULL) { - nfiles--; - perror_msg("%s", argv[optind-1]); - status = 1; - } - } - - while ((c = getchar()) != EOF) - for (i = 0; i < nfiles; i++) - putc(c, files[i]); - - return status; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/coreutils/test.c b/busybox/coreutils/test.c deleted file mode 100644 index 9c66cbb87..000000000 --- a/busybox/coreutils/test.c +++ /dev/null @@ -1,579 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * test implementation for busybox - * - * 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. - * - * 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 - * - * Original copyright notice states: - * "This program is in the Public Domain." - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -/* test(1) accepts the following grammar: - oexpr ::= aexpr | aexpr "-o" oexpr ; - aexpr ::= nexpr | nexpr "-a" aexpr ; - nexpr ::= primary | "!" primary - primary ::= unary-operator operand - | operand binary-operator operand - | operand - | "(" oexpr ")" - ; - 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"| - "-nt"|"-ot"|"-ef"; - operand ::= -*/ - -enum token { - 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 -}; - -enum token_types { - UNOP, - BINOP, - BUNOP, - BBINOP, - 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} -}; - -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(); -static int oexpr(); -static int aexpr(); -static int nexpr(); -static int binop(); -static int primary(); -static int filstat(); -static int getn(); -static int newerf(); -static int olderf(); -static int equalf(); -static void syntax(); -static int test_eaccess(); -static int is_a_group_member(); -static void initialize_group_array(); - -extern int -test_main(int argc, char** argv) -{ - int res; - - if (strcmp(applet_name, "[") == 0) { - if (strcmp(argv[--argc], "]")) - 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)); - - if (*t_wp != NULL && *++t_wp != NULL) - syntax(*t_wp, "unknown operand"); - - return( res); -} - -static void -syntax(op, msg) - char *op; - char *msg; -{ - if (op && *op) - error_msg_and_die("%s: %s", op, msg); - else - error_msg_and_die("%s", msg); -} - -static int -oexpr(n) - enum token n; -{ - int res; - - res = aexpr(n); - if (t_lex(*++t_wp) == BOR) - return oexpr(t_lex(*++t_wp)) || res; - t_wp--; - return res; -} - -static int -aexpr(n) - enum token n; -{ - int res; - - res = nexpr(n); - if (t_lex(*++t_wp) == BAND) - return aexpr(t_lex(*++t_wp)) && res; - t_wp--; - return res; -} - -static int -nexpr(n) - enum token n; /* token */ -{ - if (n == UNOT) - return !nexpr(t_lex(*++t_wp)); - return primary(n); -} - -static int -primary(n) - enum token n; -{ - int res; - - 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; - } - 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); - } - } - - if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) { - return binop(); - } - - return strlen(*t_wp) > 0; -} - -static int -binop() -{ - const char *opnd1, *opnd2; - struct t_op const *op; - - opnd1 = *t_wp; - (void) t_lex(*++t_wp); - op = t_wp_op; - - if ((opnd2 = *++t_wp) == (char *)0) - syntax(op->op_text, "argument expected"); - - 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); - } - /* NOTREACHED */ - return 1; -} - -static int -filstat(nm, mode) - char *nm; - enum token mode; -{ - struct stat s; - unsigned int i; - - if (mode == FILSYM) { -#ifdef S_IFLNK - if (lstat(nm, &s) == 0) { - i = S_IFLNK; - goto filetype; - } -#endif - return 0; - } - - 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: - 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: -#ifdef S_IFIFO - i = S_IFIFO; - goto filetype; -#else - return 0; -#endif - case FILSOCK: -#ifdef S_IFSOCK - i = S_IFSOCK; - goto filetype; -#else - 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: - return s.st_size > 0L; - case FILUID: - return s.st_uid == geteuid(); - case FILGID: - return s.st_gid == getegid(); - default: - return 1; - } - -filetype: - return ((s.st_mode & S_IFMT) == i); - -filebit: - return ((s.st_mode & i) != 0); -} - -static enum token -t_lex(s) - 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; - } - op++; - } - t_wp_op = (struct t_op *)0; - return OPERAND; -} - -/* atoi with error detection */ -static int -getn(s) - char *s; -{ - char *p; - long r; - - errno = 0; - r = strtol(s, &p, 10); - - if (errno != 0) - error_msg_and_die("%s: out of range", s); - - while (isspace(*p)) - p++; - - if (*p) - error_msg_and_die("%s: bad number", s); - - return (int) r; -} - -static int -newerf (f1, f2) -char *f1, *f2; -{ - struct stat b1, b2; - - return (stat (f1, &b1) == 0 && - stat (f2, &b2) == 0 && - b1.st_mtime > b2.st_mtime); -} - -static int -olderf (f1, f2) -char *f1, *f2; -{ - struct stat b1, b2; - - return (stat (f1, &b1) == 0 && - stat (f2, &b2) == 0 && - b1.st_mtime < b2.st_mtime); -} - -static int -equalf (f1, f2) -char *f1, *f2; -{ - struct stat b1, b2; - - return (stat (f1, &b1) == 0 && - stat (f2, &b2) == 0 && - b1.st_dev == b2.st_dev && - b1.st_ino == b2.st_ino); -} - -/* 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 (path, mode) -char *path; -int mode; -{ - struct stat st; - unsigned int euid = geteuid(); - - if (stat (path, &st) < 0) - return (-1); - - if (euid == 0) { - /* Root can read or write any file. */ - if (mode != X_OK) - return (0); - - /* 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); - } - - 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 void -initialize_group_array () -{ - ngroups = getgroups(0, NULL); - group_array = xrealloc(group_array, ngroups * sizeof(gid_t)); - getgroups(ngroups, group_array); -} - -/* Return non-zero if GID is one that we have in our groups list. */ -static int -is_a_group_member (gid) -gid_t gid; -{ - register 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); -} diff --git a/busybox/coreutils/touch.c b/busybox/coreutils/touch.c deleted file mode 100644 index 1718da71e..000000000 --- a/busybox/coreutils/touch.c +++ /dev/null @@ -1,75 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini touch implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -extern int touch_main(int argc, char **argv) -{ - int fd; - int create = TRUE; - - /* Parse options */ - while (--argc > 0 && **(++argv) == '-') { - while (*(++(*argv))) { - switch (**argv) { - case 'c': - create = FALSE; - break; - default: - show_usage(); - } - } - } - - if (argc < 1) { - show_usage(); - } - - while (argc > 0) { - fd = open(*argv, (create == FALSE) ? O_RDWR : O_RDWR | O_CREAT, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - if (fd < 0) { - if (create == FALSE && errno == ENOENT) - return EXIT_SUCCESS; - else { - perror_msg_and_die("%s", *argv); - } - } - close(fd); - if (utime(*argv, NULL)) { - perror_msg_and_die("%s", *argv); - } - argc--; - argv++; - } - - return EXIT_SUCCESS; -} diff --git a/busybox/coreutils/tr.c b/busybox/coreutils/tr.c deleted file mode 100644 index 5b7b8d091..000000000 --- a/busybox/coreutils/tr.c +++ /dev/null @@ -1,248 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini tr implementation for busybox - * - * Copyright (c) Michiel Huisjes - * - * This version of tr is adapted from Minix tr and was modified - * by Erik Andersen to be used in busybox. - * - * 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 - * - * Original copyright notice is retained at the end of this file. - */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -/* This must be a #define, since when DODEBUG 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() -{ - 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) - error_msg("%s", 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) - error_msg_and_die("%s", write_error); - out_index = 0; - } - } - - /* NOTREACHED */ -} - -static void map(register unsigned char *string1, unsigned int string1_len, - register unsigned char *string2, unsigned int string2_len) -{ - unsigned char last = '0'; - unsigned int i, j; - - for (j = 0, i = 0; i < string1_len; i++) { - if (string2_len <= j) - pvector[string1[i]] = last; - else - pvector[string1[i]] = last = string2[j++]; - } -} - -/* supported constructs: - * Ranges, e.g., [0-9] ==> 0123456789 - * Escapes, e.g., \a ==> Control-G - */ -static unsigned int expand(const char *arg, register unsigned char *buffer) -{ - unsigned char *buffer_start = buffer; - int i, ac; - - while (*arg) { - if (*arg == '\\') { - arg++; - *buffer++ = process_escape_sequence(&arg); - } else if (*(arg+1) == '-') { - ac = *(arg+2); - if(ac == 0) { - *buffer++ = *arg++; - continue; - } - i = *arg; - while (i <= ac) - *buffer++ = i++; - arg += 3; /* Skip the assumed a-z */ - } else if (*arg == '[') { - arg++; - i = *arg++; - if (*arg++ != '-') { - *buffer++ = '['; - arg -= 2; - continue; - } - ac = *arg++; - while (i <= ac) - *buffer++ = i++; - arg++; /* Skip the assumed ']' */ - } else - *buffer++ = *arg++; - } - - return (buffer - buffer_start); -} - -static int complement(unsigned char *buffer, int buffer_len) -{ - register short i, j, ix; - char conv[ASCII + 2]; - - 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; - } - memcpy(buffer, conv, ix); - return ix; -} - -extern int tr_main(int argc, char **argv) -{ - register unsigned char *ptr; - int output_length=0, input_length; - int idx = 1; - int i; - RESERVE_BB_BUFFER(output, BUFSIZ); - RESERVE_BB_BUFFER(input, BUFSIZ); - RESERVE_BB_UBUFFER(vector, ASCII+1); - RESERVE_BB_BUFFER(invec, ASCII+1); - RESERVE_BB_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: - show_usage(); - } - } - idx++; - } - for (i = 0; i <= ASCII; i++) { - vector[i] = i; - invec[i] = outvec[i] = FALSE; - } - - 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') - 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; - } - convert(); - return (0); -} - -/* - * 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. - * - */ - diff --git a/busybox/coreutils/tty.c b/busybox/coreutils/tty.c deleted file mode 100644 index 4510c2996..000000000 --- a/busybox/coreutils/tty.c +++ /dev/null @@ -1,44 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini tty implementation for busybox - * - * 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 - * - */ - -#include -#include -#include -#include -#include "busybox.h" - -extern int tty_main(int argc, char **argv) -{ - char *tty; - - if (argc > 1) { - if (argv[1][0] != '-' || argv[1][1] != 's') - show_usage(); - } else { - tty = ttyname(0); - if (tty) - puts(tty); - else - puts("not a tty"); - } - return(isatty(0) ? EXIT_SUCCESS : EXIT_FAILURE); -} diff --git a/busybox/coreutils/uname.c b/busybox/coreutils/uname.c deleted file mode 100644 index f7e2291a8..000000000 --- a/busybox/coreutils/uname.c +++ /dev/null @@ -1,156 +0,0 @@ -/* 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. */ - -/* 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 */ - -/* Busyboxed by Erik Andersen */ - -#include -#include -#include -#include -#include - -#if defined (HAVE_SYSINFO) && defined (HAVE_SYS_SYSTEMINFO_H) -# include -#endif -#include "busybox.h" - -static void print_element(unsigned int mask, char *element); - -/* Values that are bitwise or'd into `toprint'. */ -/* Operating system name. */ -static const int PRINT_SYSNAME = 1; - -/* Node name on a communications network. */ -static const int PRINT_NODENAME = 2; - -/* Operating system release. */ -static const int PRINT_RELEASE = 4; - -/* Operating system version. */ -static const int PRINT_VERSION = 8; - -/* Machine hardware name. */ -static const int PRINT_MACHINE = 16; - - /* Host processor type. */ -static const int PRINT_PROCESSOR = 32; - -/* Mask indicating which elements of the name to print. */ -static unsigned char toprint; - - -int uname_main(int argc, char **argv) -{ - struct utsname name; - char processor[256]; - -#if defined(__sparc__) && defined(__linux__) - char *fake_sparc = getenv("FAKE_SPARC"); -#endif - - toprint = 0; - - /* Parse any options */ - //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv); - while (--argc > 0 && **(++argv) == '-') { - while (*(++(*argv))) { - switch (**argv) { - case 's': - toprint |= PRINT_SYSNAME; - break; - case 'n': - toprint |= PRINT_NODENAME; - break; - case 'r': - toprint |= PRINT_RELEASE; - break; - case 'v': - toprint |= PRINT_VERSION; - break; - case 'm': - toprint |= PRINT_MACHINE; - break; - case 'p': - toprint |= PRINT_PROCESSOR; - break; - case 'a': - toprint = (PRINT_SYSNAME | PRINT_NODENAME | PRINT_RELEASE | - PRINT_PROCESSOR | PRINT_VERSION | - PRINT_MACHINE); - break; - default: - show_usage(); - } - } - } - - if (toprint == 0) - toprint = PRINT_SYSNAME; - - if (uname(&name) == -1) - perror_msg("cannot get system name"); - -#if defined (HAVE_SYSINFO) && defined (SI_ARCHITECTURE) - if (sysinfo(SI_ARCHITECTURE, processor, sizeof(processor)) == -1) - perror_msg("cannot get processor type"); -} - -#else - strcpy(processor, "unknown"); -#endif - -#if defined(__sparc__) && defined(__linux__) - if (fake_sparc != NULL - && (fake_sparc[0] == 'y' - || fake_sparc[0] == 'Y')) strcpy(name.machine, "sparc"); -#endif - - print_element(PRINT_SYSNAME, name.sysname); - print_element(PRINT_NODENAME, name.nodename); - print_element(PRINT_RELEASE, name.release); - print_element(PRINT_VERSION, name.version); - print_element(PRINT_MACHINE, name.machine); - print_element(PRINT_PROCESSOR, processor); - - return EXIT_SUCCESS; -} - -/* If the name element set in MASK is selected for printing in `toprint', - print ELEMENT; then print a space unless it is the last element to - be printed, in which case print a newline. */ - -static void print_element(unsigned int mask, char *element) -{ - if (toprint & mask) { - toprint &= ~mask; - printf("%s%c", element, toprint ? ' ' : '\n'); - } -} diff --git a/busybox/coreutils/uniq.c b/busybox/coreutils/uniq.c deleted file mode 100644 index 53e3c64f2..000000000 --- a/busybox/coreutils/uniq.c +++ /dev/null @@ -1,89 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini uniq implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by John Beppu - * Rewritten 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 - * - */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -static int print_count; -static int print_uniq = 1; -static int print_duplicates = 1; - -static void print_line(char *line, int count, FILE *fp) -{ - if ((print_duplicates && count > 1) || (print_uniq && count == 1)) { - if (print_count) - fprintf(fp, "%7d\t%s", count, line); - else - fputs(line, fp); - } -} - -int uniq_main(int argc, char **argv) -{ - FILE *in = stdin, *out = stdout; - char *lastline = NULL, *input; - int opt, count = 0; - - /* parse argv[] */ - while ((opt = getopt(argc, argv, "cdu")) > 0) { - switch (opt) { - case 'c': - print_count = 1; - break; - case 'd': - print_duplicates = 1; - print_uniq = 0; - break; - case 'u': - print_duplicates = 0; - print_uniq = 1; - break; - } - } - - if (argv[optind] != NULL) { - in = xfopen(argv[optind], "r"); - if (argv[optind+1] != NULL) - out = xfopen(argv[optind+1], "w"); - } - - while ((input = get_line_from_file(in)) != NULL) { - if (lastline == NULL || strcmp(input, lastline) != 0) { - print_line(lastline, count, out); - free(lastline); - lastline = input; - count = 0; - } - count++; - } - print_line(lastline, count, out); - free(lastline); - - return EXIT_SUCCESS; -} diff --git a/busybox/coreutils/usleep.c b/busybox/coreutils/usleep.c deleted file mode 100644 index 6023bf430..000000000 --- a/busybox/coreutils/usleep.c +++ /dev/null @@ -1,38 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini usleep implementation for busybox - * - * - * 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 - * - */ - -/* getopt not needed */ - -#include -#include -#include "busybox.h" - -extern int usleep_main(int argc, char **argv) -{ - if ((argc < 2) || (**(argv + 1) == '-')) { - show_usage(); - } - - usleep(atoi(*(++argv))); /* return void */ - return EXIT_SUCCESS; -} diff --git a/busybox/coreutils/uudecode.c b/busybox/coreutils/uudecode.c deleted file mode 100644 index a4059ddfe..000000000 --- a/busybox/coreutils/uudecode.c +++ /dev/null @@ -1,353 +0,0 @@ -/* uudecode.c -- uudecode utility. - * Copyright (C) 1994, 1995 Free Software Foundation, Inc. - * - * 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. - * - * 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. - * - * 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. - */ - - - -#include -#include -#include -#include -#include -#include "busybox.h" -#include "pwd_grp/pwd.h" -#include "pwd_grp/grp.h" - -/*struct passwd *getpwnam();*/ - -/* Single character decode. */ -#define DEC(Char) (((Char) - ' ') & 077) - -static int read_stduu (const char *inname) -{ - char buf[2 * BUFSIZ]; - - while (1) { - int n; - char *p; - - if (fgets (buf, sizeof(buf), stdin) == NULL) { - 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")) { - error_msg("%s: No `end' line", inname); - return FALSE; - } - - return TRUE; -} - -static int read_base64 (const char *inname) -{ - 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) { - error_msg("%s: Short file", inname); - return FALSE; - } - p = buf; - - if (memcmp (buf, "====", 4) == 0) - break; - if (last_data != 0) { - 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++ == '=') { - error_msg("%s: illegal line", inname); - return FALSE; - } - c2 = b64_tab[*p++]; - - while (b64_tab[*p] == '\177') - if (*p++ == '\n') { - 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') { - 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; -} - -static int decode (const char *inname, - const char *forced_outname) -{ - 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) { - 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') { - error_msg("%s: Illegal ~user", inname); - return FALSE; - } - *p++ = '\0'; - pw = getpwnam (buf + 1); - if (pw == NULL) { - 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)) - )) { - 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: - 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 { - perror_msg("%s", argv[optind]); - exit_status = EXIT_FAILURE; - } - optind++; - } - while (optind < argc); - } - return(exit_status); -} - -/* 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. - */ - - diff --git a/busybox/coreutils/uuencode.c b/busybox/coreutils/uuencode.c deleted file mode 100644 index fc037403a..000000000 --- a/busybox/coreutils/uuencode.c +++ /dev/null @@ -1,180 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Copyright (C) 2000 by Glenn McGrath - * - * 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. - */ -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -/* Conversion table. for base 64 */ -static char tbl_base64[64] = { - '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', '+', '/' -}; - -static char tbl_std[64] = { - '`', '!', '"', '#', '$', '%', '&', '\'', - '(', ')', '*', '+', ',', '-', '.', '/', - '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', '[', '\\', ']', '^', '_' -}; - -/* - * 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) = '='; - } - else if (i == length + 2) { - *(p - 1) = *(p - 2) = '='; - } - /* ...and zero-terminate it. */ - *p = '\0'; -} - -int uuencode_main(int argc, char **argv) -{ - const int src_buf_size = 60; // This *MUST* be a multiple of 3 - const int dst_buf_size = 4 * ((src_buf_size + 2) / 3); - RESERVE_BB_BUFFER(src_buf, src_buf_size + 1); - RESERVE_BB_BUFFER(dst_buf, dst_buf_size + 1); - struct stat stat_buf; - FILE *src_stream = stdin; - char *tbl = tbl_std; - size_t size; - mode_t mode; - int opt; - int column = 0; - int write_size = 0; - int remaining; - int buffer_offset = 0; - - while ((opt = getopt(argc, argv, "m")) != -1) { - switch (opt) { - case 'm': - tbl = tbl_base64; - break; - default: - show_usage(); - } - } - - switch (argc - optind) { - case 2: - src_stream = xfopen(argv[optind], "r"); - stat(argv[optind], &stat_buf); - mode = stat_buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); - if (src_stream == stdout) { - printf("NULL\n"); - } - break; - case 1: - mode = 0666 & ~umask(0666); - break; - default: - show_usage(); - } - - 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) { - /* Encode the buffer we just read in */ - uuencode(src_buf, dst_buf, size, tbl); - - /* Write the buffer to stdout, wrapping at 60 chars. - * This looks overly complex, but it gets tricky as - * the line has to continue to wrap correctly if we - * have to refill the buffer - * - * Improvments most welcome - */ - - /* Initialise values for the new buffer */ - remaining = 4 * ((size + 2) / 3); - buffer_offset = 0; - - /* Write the buffer to stdout, wrapping at 60 chars - * starting from the column the last buffer ran out - */ - do { - if (remaining > (60 - column)) { - write_size = 60 - column; - } - else if (remaining < 60) { - write_size = remaining; - } else { - write_size = 60; - } - - /* Setup a new row if required */ - if (column == 0) { - putchar('\n'); - if (tbl == tbl_std) { - putchar('M'); - } - } - /* Write to the 60th column */ - if (fwrite(&dst_buf[buffer_offset], 1, write_size, stdout) != write_size) { - perror("Couldnt finish writing"); - } - /* Update variables based on last write */ - buffer_offset += write_size; - remaining -= write_size; - column += write_size; - if (column % 60 == 0) { - column = 0; - } - } while (remaining > 0); - } - printf(tbl == tbl_std ? "\n`\nend\n" : "\n====\n"); - - return(EXIT_SUCCESS); -} diff --git a/busybox/coreutils/wc.c b/busybox/coreutils/wc.c deleted file mode 100644 index 695e7e7d4..000000000 --- a/busybox/coreutils/wc.c +++ /dev/null @@ -1,156 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini wc implementation for busybox - * - * 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 - * - */ - -#include -#include -#include -#include -#include "busybox.h" - -static int total_lines, total_words, total_chars, max_length; -static int print_lines, print_words, print_chars, print_length; - -static void print_counts(int lines, int words, int chars, int length, - const char *name) -{ - char const *space = ""; - - if (print_lines) { - printf("%7d", lines); - space = " "; - } - if (print_words) { - printf("%s%7d", space, words); - space = " "; - } - if (print_chars) { - printf("%s%7d", space, chars); - space = " "; - } - if (print_length) - printf("%s%7d", space, length); - if (*name) - printf(" %s", name); - putchar('\n'); -} - -static void wc_file(FILE * file, const char *name) -{ - int lines, words, chars, length; - int in_word = 0, linepos = 0; - int c; - - lines = words = chars = length = 0; - while ((c = getc(file)) != EOF) { - chars++; - switch (c) { - case '\n': - lines++; - case '\r': - case '\f': - if (linepos > length) - length = linepos; - linepos = 0; - goto word_separator; - case '\t': - linepos += 8 - (linepos % 8); - goto word_separator; - case ' ': - linepos++; - case '\v': - word_separator: - if (in_word) { - in_word = 0; - words++; - } - break; - default: - linepos++; - in_word = 1; - break; - } - } - if (linepos > length) - length = linepos; - if (in_word) - words++; - print_counts(lines, words, chars, length, name); - total_lines += lines; - total_words += words; - total_chars += chars; - if (length > max_length) - max_length = length; - fclose(file); - fflush(stdout); -} - -int wc_main(int argc, char **argv) -{ - FILE *file; - unsigned int num_files_counted = 0; - int opt, status = EXIT_SUCCESS; - - total_lines = total_words = total_chars = max_length = 0; - print_lines = print_words = print_chars = print_length = 0; - - while ((opt = getopt(argc, argv, "clLw")) > 0) { - switch (opt) { - case 'c': - print_chars = 1; - break; - case 'l': - print_lines = 1; - break; - case 'L': - print_length = 1; - break; - case 'w': - print_words = 1; - break; - default: - show_usage(); - } - } - - if (!print_lines && !print_words && !print_chars && !print_length) - print_lines = print_words = print_chars = 1; - - if (argv[optind] == NULL || strcmp(argv[optind], "-") == 0) { - wc_file(stdin, ""); - return EXIT_SUCCESS; - } else { - while (optind < argc) { - if ((file = wfopen(argv[optind], "r")) != NULL) - wc_file(file, argv[optind]); - else - status = EXIT_FAILURE; - num_files_counted++; - optind++; - } - } - - if (num_files_counted > 1) - print_counts(total_lines, total_words, total_chars, - max_length, "total"); - - return status; -} diff --git a/busybox/coreutils/whoami.c b/busybox/coreutils/whoami.c deleted file mode 100644 index c3b1140e6..000000000 --- a/busybox/coreutils/whoami.c +++ /dev/null @@ -1,44 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini whoami implementation for busybox - * - * 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 - * - */ - -/* getopt not needed */ - -#include -#include -#include -#include "busybox.h" - -extern int whoami_main(int argc, char **argv) -{ - char user[9]; - uid_t uid = geteuid(); - - if (argc > 1) - show_usage(); - - my_getpwuid(user, uid); - if (*user) { - puts(user); - return EXIT_SUCCESS; - } - error_msg_and_die("cannot find username for UID %u", (unsigned) uid); -} diff --git a/busybox/coreutils/yes.c b/busybox/coreutils/yes.c deleted file mode 100644 index 7d9596d0b..000000000 --- a/busybox/coreutils/yes.c +++ /dev/null @@ -1,53 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini yes implementation for busybox - * - * 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 - * - */ - -/* getopt not needed */ - -#include -#include -#include "busybox.h" - -extern int yes_main(int argc, char **argv) -{ - int i; - - if (argc >= 2 && *argv[1] == '-') - show_usage(); - - if (argc == 1) { - while (1) - if (puts("y") == EOF) { - perror("yes"); - return EXIT_FAILURE; - } - } - - while (1) - for (i = 1; i < argc; i++) - if (fputs(argv[i], stdout) == EOF - || putchar(i == argc - 1 ? '\n' : ' ') == EOF) { - perror("yes"); - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} diff --git a/busybox/cp.c b/busybox/cp.c deleted file mode 100644 index 82d43adff..000000000 --- a/busybox/cp.c +++ /dev/null @@ -1,114 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini cp implementation for busybox - * - * - * Copyright (C) 2000 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "busybox.h" - -extern int cp_main(int argc, char **argv) -{ - int status = 0; - int opt; - int flags = 0; - int i; - - while ((opt = getopt(argc, argv, "adfipR")) != -1) - switch (opt) { - case 'a': - flags |= FILEUTILS_PRESERVE_STATUS | FILEUTILS_RECUR; - /* fallthrough */ - case 'd': - flags |= FILEUTILS_PRESERVE_SYMLINKS; - break; - case 'f': - flags |= FILEUTILS_FORCE; - break; - case 'i': - flags |= FILEUTILS_INTERACTIVE; - break; - case 'p': - flags |= FILEUTILS_PRESERVE_STATUS; - break; - case 'R': - flags |= FILEUTILS_RECUR; - break; - default: - show_usage(); - } - - if (optind + 2 > argc) - show_usage(); - - /* If there are only two arguments and... */ - if (optind + 2 == argc) { - struct stat source_stat; - struct stat dest_stat; - int source_exists = 1; - int dest_exists = 1; - - if (((flags & FILEUTILS_PRESERVE_SYMLINKS) && - lstat(argv[optind], &source_stat) < 0) || - (!(flags & FILEUTILS_PRESERVE_SYMLINKS) && - stat(argv[optind], &source_stat))) { - if (errno != ENOENT) - perror_msg_and_die("unable to stat `%s'", argv[optind]); - source_exists = 0; - } - - if (stat(argv[optind + 1], &dest_stat) < 0) { - if (errno != ENOENT) - perror_msg_and_die("unable to stat `%s'", argv[optind + 1]); - dest_exists = 0; - } - - /* ...if neither is a directory or... */ - if (((!source_exists || !S_ISDIR(source_stat.st_mode)) && - (!dest_exists || !S_ISDIR(dest_stat.st_mode))) || - /* ...recursing, the first is a directory, and the - * second doesn't exist, then... */ - ((flags & FILEUTILS_RECUR) && S_ISDIR(source_stat.st_mode) && - !dest_exists)) { - /* ...do a simple copy. */ - if (copy_file(argv[optind], argv[optind + 1], flags) < 0) - status = 1; - return status; - } - } - - for (i = optind; i < argc - 1; i++) { - char *dest = concat_path_file(argv[argc - 1], - get_last_path_component(argv[i])); - if (copy_file(argv[i], dest, flags) < 0) - status = 1; - free(dest); - } - - return status; -} diff --git a/busybox/cpio.c b/busybox/cpio.c deleted file mode 100644 index 7f68715eb..000000000 --- a/busybox/cpio.c +++ /dev/null @@ -1,95 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini cpio implementation for busybox - * - * Copyright (C) 2001 by 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 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 - * - * Limitations: - * Doesn't check CRC's - * Only supports new ASCII and CRC formats - * - */ -#include -#include -#include -#include -#include -#include "busybox.h" - -extern int cpio_main(int argc, char **argv) -{ - FILE *src_stream = stdin; - char **extract_names = NULL; - int extract_function = 0; - int num_of_entries = 0; - int opt = 0; - mode_t oldmask = 0; - - while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) { - switch (opt) { - case 'i': // extract - extract_function |= extract_all_to_fs; - break; - case 'd': // create _leading_ directories - extract_function |= extract_create_leading_dirs; - oldmask = umask(077); /* Make make_directory act like GNU cpio */ - break; - case 'm': // preserve modification time - extract_function |= extract_preserve_date; - break; - case 'v': // verbosly list files - extract_function |= extract_verbose_list; - break; - case 'u': // unconditional - extract_function |= extract_unconditional; - break; - case 't': // list files - extract_function |= extract_list; - break; - case 'F': - src_stream = xfopen(optarg, "r"); - break; - default: - show_usage(); - } - } - - if ((extract_function & extract_all_to_fs) && (extract_function & extract_list)) { - extract_function ^= extract_all_to_fs; /* If specify t, don't extract*/ - } - - if ((extract_function & extract_all_to_fs) && (extract_function & extract_verbose_list)) { - /* The meaning of v changes on extract */ - extract_function ^= extract_verbose_list; - extract_function |= extract_list; - } - - while (optind < argc) { - extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2)); - extract_names[num_of_entries] = xstrdup(argv[optind]); - num_of_entries++; - extract_names[num_of_entries] = NULL; - optind++; - } - - unarchive(src_stream, stdout, &get_header_cpio, extract_function, "./", extract_names); - if (oldmask) { - umask(oldmask); /* Restore umask if we changed it */ - } - return EXIT_SUCCESS; -} - diff --git a/busybox/cut.c b/busybox/cut.c deleted file mode 100644 index 3ed264870..000000000 --- a/busybox/cut.c +++ /dev/null @@ -1,356 +0,0 @@ -/* - * 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 - * - */ - -#include -#include -#include /* getopt */ -#include -#include -#include "busybox.h" - - -/* globals from other files */ -extern int optind; -extern char *optarg; - - -/* option vars */ -static char part = 0; /* (b)yte, (c)har, (f)ields */ -static unsigned int supress_non_delimited_lines = 0; -static char delim = '\t'; /* delimiter, default is tab */ - -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 */ - - -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; -} - - -/* - * 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) -{ - 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) - 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) - 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) - 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) - 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); - -} - - -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'; - } - 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) - 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++; - } - - /* 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++; - } - - 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 = get_line_from_file(file)) != NULL) { - chomp(line); - - /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */ - if (part == 'c' || part == 'b') - cut_line_by_chars(line); - - /* cut based on fields */ - else if (part == 'f') { - if (delim == '\n') - cut_file_by_lines(line, linenum); - else - cut_line_by_fields(line); - } - - linenum++; - free(line); - } -} - - -extern int cut_main(int argc, char **argv) -{ - int opt; - - while ((opt = getopt(argc, argv, "b:c:d:f:ns")) > 0) { - switch (opt) { - case 'b': - case 'c': - case 'f': - /* make sure they didn't ask for two types of lists */ - if (part != 0) { - error_msg_and_die("only one type of list may be specified"); - } - part = (char)opt; - parse_lists(optarg); - break; - case 'd': - if (strlen(optarg) > 1) { - error_msg_and_die("the delimiter must be a single character"); - } - delim = optarg[0]; - break; - case 'n': - /* no-op */ - break; - case 's': - supress_non_delimited_lines++; - break; - } - } - - if (part == 0) { - error_msg_and_die("you must specify a list of bytes, characters, or fields"); - } - - /* non-field (char or byte) cutting has some special handling */ - if (part != 'f') { - if (supress_non_delimited_lines) { - error_msg_and_die("suppressing non-delimited lines makes sense" - " only when operating on fields"); - } - if (delim != '\t' && part != 'f') { - error_msg_and_die("a delimiter may be specified only when operating on fields"); - } - } - - /* 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 = wfopen(argv[i], "r"); - if(file) { - cut_file(file); - fclose(file); - } - } - } - - return EXIT_SUCCESS; -} diff --git a/busybox/date.c b/busybox/date.c deleted file mode 100644 index 6db3e2838..000000000 --- a/busybox/date.c +++ /dev/null @@ -1,247 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini date implementation for busybox - * - * by Matthew Grant - * - * 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 "busybox.h" - - -/* 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 - 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) { - error_msg_and_die(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); - -} - - -/* The new stuff for LRP */ - -static struct tm *date_conv_ftime(struct tm *tm_time, const char *t_string) -{ - 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) { - - t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */ - - } 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) { - - 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:%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 { - error_msg_and_die(invalid_date, t_string); - } - *tm_time = t; - return (tm_time); -} - - -int date_main(int argc, char **argv) -{ - char *date_str = NULL; - char *date_fmt = NULL; - char *t_buff; - int c; - int set_time = 0; - int rfc822 = 0; - int utc = 0; - int use_arg = 0; - time_t tm; - struct tm tm_time; - - /* Interpret command line args */ - while ((c = getopt(argc, argv, "Rs:ud:")) != EOF) { - switch (c) { - case 'R': - rfc822 = 1; - break; - case 's': - set_time = 1; - if ((date_str != NULL) || ((date_str = optarg) == NULL)) { - show_usage(); - } - break; - case 'u': - utc = 1; - if (putenv("TZ=UTC0") != 0) - error_msg_and_die(memory_exhausted); - break; - case 'd': - use_arg = 1; - if ((date_str != NULL) || ((date_str = optarg) == NULL)) - show_usage(); - break; - default: - show_usage(); - } - } - - 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]; - } -#if 0 - else { - error_msg("date_str='%s' date_fmt='%s'\n", date_str, date_fmt); - show_usage(); - } -#endif - - /* Now we have parsed all the information except the date format - which depends on whether the clock is being set or read */ - - time(&tm); - memcpy(&tm_time, localtime(&tm), sizeof(tm_time)); - /* Zero out fields - take her back to midnight! */ - if (date_str != NULL) { - 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); - } else { - date_conv_time(&tm_time, date_str); - } - - /* Correct any day of week and day of year etc. fields */ - tm = mktime(&tm_time); - if (tm < 0) - error_msg_and_die(invalid_date, date_str); - if ( utc ) { - if (putenv("TZ=UTC0") != 0) - error_msg_and_die(memory_exhausted); - } - - /* if setting time, set it */ - if (set_time) { - if (stime(&tm) < 0) { - perror_msg("cannot set date"); - } - } - } - - /* Display output */ - - /* Deal with format string */ - if (date_fmt == NULL) { - date_fmt = (rfc822 - ? (utc - ? "%a, %_d %b %Y %H:%M:%S GMT" - : "%a, %_d %b %Y %H:%M:%S %z") - : "%a %b %e %H:%M:%S %Z %Y"); - - } else if (*date_fmt == '\0') { - /* Imitate what GNU 'date' does with NO format string! */ - printf("\n"); - return EXIT_SUCCESS; - } - - /* Handle special conversions */ - - if (strncmp(date_fmt, "%f", 2) == 0) { - date_fmt = "%Y.%m.%d-%H:%M:%S"; - } - - /* Print OUTPUT (after ALL that!) */ - t_buff = xmalloc(201); - strftime(t_buff, 200, date_fmt, &tm_time); - puts(t_buff); - - return EXIT_SUCCESS; -} diff --git a/busybox/dc.c b/busybox/dc.c deleted file mode 100644 index 8d7a92a28..000000000 --- a/busybox/dc.c +++ /dev/null @@ -1,182 +0,0 @@ -/* vi: set sw=4 ts=4: */ -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */ - -static double stack[100]; -static unsigned int pointer; - -static void push(double a) -{ - if (pointer >= (sizeof(stack) / sizeof(*stack))) - error_msg_and_die("stack overflow"); - stack[pointer++] = a; -} - -static double pop() -{ - if (pointer == 0) - error_msg_and_die("stack underflow"); - return stack[--pointer]; -} - -static void add() -{ - push(pop() + pop()); -} - -static void sub() -{ - double subtrahend = pop(); - - push(pop() - subtrahend); -} - -static void mul() -{ - push(pop() * pop()); -} - -static void divide() -{ - double divisor = pop(); - - push(pop() / divisor); -} - -static void and() -{ - push((unsigned int) pop() & (unsigned int) pop()); -} - -static void or() -{ - push((unsigned int) pop() | (unsigned int) pop()); -} - -static void eor() -{ - push((unsigned int) pop() ^ (unsigned int) pop()); -} - -static void not() -{ - push(~(unsigned int) pop()); -} - -static void print() -{ - printf("%g\n", pop()); -} - -struct op { - const char *name; - void (*function) (); -}; - -static const struct op operators[] = { - {"+", add}, - {"add", add}, - {"-", sub}, - {"sub", sub}, - {"*", mul}, - {"mul", mul}, - {"/", divide}, - {"div", divide}, - {"and", and}, - {"or", or}, - {"not", not}, - {"eor", eor}, - {0, 0} -}; - -static void stack_machine(const char *argument) -{ - char *endPointer = 0; - double d; - const struct op *o = operators; - - if (argument == 0) { - print(); - return; - } - - d = strtod(argument, &endPointer); - - if (endPointer != argument) { - push(d); - return; - } - - while (o->name != 0) { - if (strcmp(o->name, argument) == 0) { - (*(o->function)) (); - return; - } - o++; - } - error_msg_and_die("%s: syntax error.", argument); -} - -/* return pointer to next token in buffer and set *buffer to one char - * past the end of the above mentioned token - */ -static char *get_token(char **buffer) -{ - char *start = NULL; - char *current = *buffer; - - while (isspace(*current)) { current++; } - if (*current != 0) { - start = current; - while (!isspace(*current) && current != 0) { current++; } - *buffer = current; - } - return start; -} - -/* In Perl one might say, scalar m|\s*(\S+)\s*|g */ -static int number_of_tokens(char *buffer) -{ - int i = 0; - char *b = buffer; - while (get_token(&b)) { i++; } - return i; -} - -int dc_main(int argc, char **argv) -{ - /* take stuff from stdin if no args are given */ - if (argc <= 1) { - int i, len; - char *line = NULL; - char *cursor = NULL; - char *token = NULL; - while ((line = get_line_from_file(stdin))) { - cursor = line; - len = number_of_tokens(line); - for (i = 0; i < len; i++) { - token = get_token(&cursor); - *cursor++ = 0; - stack_machine(token); - } - free(line); - } - } else { - if (*argv[1]=='-') - show_usage(); - while (argc >= 2) { - stack_machine(argv[1]); - argv++; - argc--; - } - } - stack_machine(0); - return EXIT_SUCCESS; -} diff --git a/busybox/dd.c b/busybox/dd.c deleted file mode 100644 index d46db82a0..000000000 --- a/busybox/dd.c +++ /dev/null @@ -1,154 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini dd implementation for busybox - * - * - * Copyright (C) 2000 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - - -static const struct suffix_mult dd_suffixes[] = { - { "c", 1 }, - { "w", 2 }, - { "b", 512 }, - { "kD", 1000 }, - { "k", 1024 }, - { "MD", 1000000 }, - { "M", 1048576 }, - { "GD", 1000000000 }, - { "G", 1073741824 }, - { NULL, 0 } -}; - -int dd_main(int argc, char **argv) -{ - int i, ifd, ofd, oflag, sync_flag = FALSE, trunc = TRUE; - size_t in_full = 0, in_part = 0, out_full = 0, out_part = 0; - size_t bs = 512, count = -1; - ssize_t n; - off_t seek = 0, skip = 0; - char *infile = NULL, *outfile = NULL, *buf; - - for (i = 1; i < argc; i++) { - if (strncmp("bs=", argv[i], 3) == 0) - bs = parse_number(argv[i]+3, dd_suffixes); - else if (strncmp("count=", argv[i], 6) == 0) - count = parse_number(argv[i]+6, dd_suffixes); - else if (strncmp("seek=", argv[i], 5) == 0) - seek = parse_number(argv[i]+5, dd_suffixes); - else if (strncmp("skip=", argv[i], 5) == 0) - skip = parse_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; - 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 { - error_msg_and_die("invalid conversion `%s'", argv[i]+5); - } - if (buf[0] == '\0') - break; - if (buf[0] == ',') - buf++; - } - } else - show_usage(); - } - - buf = xmalloc(bs); - - if (infile != NULL) { - if ((ifd = open(infile, O_RDONLY)) < 0) - perror_msg_and_die("%s", infile); - } else { - ifd = STDIN_FILENO; - infile = "standard input"; - } - - if (outfile != NULL) { - oflag = O_WRONLY | O_CREAT; - - if (!seek && trunc) - oflag |= O_TRUNC; - - if ((ofd = open(outfile, oflag, 0666)) < 0) - perror_msg_and_die("%s", outfile); - - if (seek && trunc) { - if (ftruncate(ofd, seek * bs) < 0) - perror_msg_and_die("%s", outfile); - } - } else { - ofd = STDOUT_FILENO; - outfile = "standard output"; - } - - if (skip) { - if (lseek(ifd, skip * bs, SEEK_CUR) < 0) - perror_msg_and_die("%s", infile); - } - - if (seek) { - if (lseek(ofd, seek * bs, SEEK_CUR) < 0) - perror_msg_and_die("%s", outfile); - } - - while (in_full + in_part != count) { - n = safe_read(ifd, buf, bs); - if (n < 0) - perror_msg_and_die("%s", infile); - if (n == 0) - break; - if (n == bs) - in_full++; - else - in_part++; - if (sync_flag) { - memset(buf + n, '\0', bs - n); - n = bs; - } - n = full_write(ofd, buf, n); - if (n < 0) - perror_msg_and_die("%s", outfile); - if (n == bs) - out_full++; - else - out_part++; - } - - fprintf(stderr, "%ld+%ld records in\n", (long)in_full, (long)in_part); - fprintf(stderr, "%ld+%ld records out\n", (long)out_full, (long)out_part); - - return EXIT_SUCCESS; -} diff --git a/busybox/deallocvt.c b/busybox/deallocvt.c deleted file mode 100644 index 15cd0c9b9..000000000 --- a/busybox/deallocvt.c +++ /dev/null @@ -1,43 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * disalloc.c - aeb - 940501 - Disallocate virtual terminal(s) - * Renamed deallocvt. - */ -#include -#include -#include -#include -#include -#include "busybox.h" - -/* From */ -static const int VT_DISALLOCATE = 0x5608; /* free memory associated to vt */ - -int deallocvt_main(int argc, char *argv[]) -{ - int fd, num, i; - - //if ((argc > 2) || ((argv == 2) && (**(argv + 1) == '-'))) - if (argc > 2) - show_usage(); - - fd = get_console_fd("/dev/console"); - - if (argc == 1) { - /* deallocate all unused consoles */ - if (ioctl(fd, VT_DISALLOCATE, 0)) - perror_msg_and_die("VT_DISALLOCATE"); - } else { - for (i = 1; i < argc; i++) { - num = atoi(argv[i]); - if (num == 0) - error_msg("0: illegal VT number"); - else if (num == 1) - error_msg("VT 1 cannot be deallocated"); - else if (ioctl(fd, VT_DISALLOCATE, num)) - perror_msg_and_die("VT_DISALLOCATE"); - } - } - - return EXIT_SUCCESS; -} diff --git a/busybox/debian/Config.h-deb b/busybox/debian/Config.h-deb deleted file mode 100644 index 368b5e97c..000000000 --- a/busybox/debian/Config.h-deb +++ /dev/null @@ -1,469 +0,0 @@ -/* vi: set sw=4 ts=4: */ -// This file defines the feature set to be compiled into busybox. -// When you turn things off here, they won't be compiled in at all. -// -//// This file is parsed by sed. You MUST use single line comments. -// i.e., //#define BB_BLAH -// -// -// BusyBox Applications -//#define BB_ADJTIMEX -#define BB_AR -//#define BB_ASH -//#define BB_BASENAME -#define BB_CAT -#define BB_CHGRP -#define BB_CHMOD -#define BB_CHOWN -#define BB_CHROOT -//#define BB_CHVT -#define BB_CLEAR -//#define BB_CMP -#define BB_CP -//#define BB_CPIO -#define BB_CUT -//#define BB_DATE -//#define BB_DC -#define BB_DD -//#define BB_DEALLOCVT -#define BB_DF -#define BB_DIRNAME -#define BB_DMESG -//#define BB_DOS2UNIX -//#define BB_DPKG -//#define BB_DPKG_DEB -//#define BB_DUTMP -//#define BB_DU -//#define BB_DUMPKMAP -#define BB_ECHO -//#define BB_ENV -#define BB_EXPR -//#define BB_FBSET -//#define BB_FDFLUSH -#define BB_FIND -#define BB_FREE -//#define BB_FREERAMDISK -//#define BB_FSCK_MINIX -//#define BB_GETOPT -#define BB_GREP -#define BB_GUNZIP -#define BB_GZIP -#define BB_HALT -#define BB_HEAD -//#define BB_HOSTID -//#define BB_HOSTNAME -//#define BB_HUSH -#define BB_ID -#define BB_IFCONFIG -#define BB_INIT -//#define BB_INSMOD -#define BB_KILL -#define BB_KILLALL -#define BB_KLOGD -//#define BB_LASH -//#define BB_LENGTH -#define BB_LN -//#define BB_LOADACM -//#define BB_LOADFONT -#define BB_LOADKMAP -#define BB_LOGGER -//#define BB_LOGNAME -#define BB_LS -//#define BB_LSMOD -//#define BB_MAKEDEVS -#define BB_MD5SUM -#define BB_MKDIR -//#define BB_MKFIFO -//#define BB_MKFS_MINIX -#define BB_MKNOD -#define BB_MKSWAP -//#define BB_MKTEMP -//#define BB_MODPROBE -#define BB_MORE -#define BB_MOUNT -//#define BB_MSH -//#define BB_MT -#define BB_MV -//#define BB_NC -//#define BB_NSLOOKUP -//#define BB_PIDOF -#define BB_PING -//#define BB_PIVOT_ROOT -#define BB_POWEROFF -//#define BB_PRINTF -#define BB_PS -#define BB_PWD -//#define BB_RDATE -//#define BB_READLINK -#define BB_REBOOT -//#define BB_RENICE -#define BB_RESET -#define BB_RM -#define BB_RMDIR -//#define BB_RMMOD -#define BB_ROUTE -//#define BB_RPM2CPIO -#define BB_SED -//#define BB_SETKEYCODES -#define BB_SLEEP -#define BB_SORT -//#define BB_STTY -#define BB_SWAPONOFF -#define BB_SYNC -#define BB_SYSLOGD -#define BB_TAIL -#define BB_TAR -//#define BB_TEE -#define BB_TEST -//#define BB_TELNET -//#define BB_TFTP -#define BB_TOUCH -#define BB_TR -//#define BB_TRACEROUTE -#define BB_TRUE_FALSE -#define BB_TTY -//#define BB_UNIX2DOS -//#define BB_UUENCODE -//#define BB_UUDECODE -#define BB_UMOUNT -#define BB_UNIQ -#define BB_UNAME -//#define BB_UPDATE -#define BB_UPTIME -//#define BB_USLEEP -//#define BB_VI -//#define BB_WATCHDOG -#define BB_WC -#define BB_WGET -#define BB_WHICH -#define BB_WHOAMI -//#define BB_XARGS -//#define BB_YES -// End of Applications List -// -// -// -// --------------------------------------------------------- -// This is where feature definitions go. Generally speaking, -// turning this stuff off makes things a bit smaller (and less -// pretty/useful). -// -// -// If you enabled one or more of the shells, you may select which one -// should be run when sh is invoked: -//#define BB_FEATURE_SH_IS_ASH -//#define BB_FEATURE_SH_IS_HUSH -//#define BB_FEATURE_SH_IS_LASH -//#define BB_FEATURE_SH_IS_MSH -// -// BusyBox will, by default, malloc space for its buffers. This costs code -// size for the call to xmalloc. You can use the following feature to have -// them put on the stack. For some very small machines with limited stack -// space, this can be deadly. For most folks, this works just fine... -//#define BB_FEATURE_BUFFERS_GO_ON_STACK -// The third alternative for buffer allocation is to use BSS. This works -// beautifully for computers with a real MMU (and OS support), but wastes -// runtime RAM for uCLinux. This behavior was the only one available for -// BusyBox versions 0.48 and earlier. -//#define BB_FEATURE_BUFFERS_GO_IN_BSS -// -// Turn this on to use Erik's very cool devps, and devmtab kernel drivers, -// thereby eliminating the need for the /proc filesystem and thereby saving -// lots and lots memory for more important things. NOTE: If you enable this -// feature, you _must_ have patched the kernel to include the devps patch that -// is included in the busybox/kernel-patches directory. You will also need to -// create some device special files in /dev on your embedded system: -// mknod /dev/mtab c 10 22 -// mknod /dev/ps c 10 21 -// I emailed Linus and this patch will not be going into the stock kernel. -//#define BB_FEATURE_USE_DEVPS_PATCH -// -// show verbose usage messages -//#define BB_FEATURE_VERBOSE_USAGE -// -// Use termios to manipulate the screen ('more' is prettier with this on) -#define BB_FEATURE_USE_TERMIOS -// -// calculate terminal & column widths (for more and ls) -#define BB_FEATURE_AUTOWIDTH -// -// show username/groupnames for ls -#define BB_FEATURE_LS_USERNAME -// -// show file timestamps in ls -#define BB_FEATURE_LS_TIMESTAMPS -// -// enable ls -p and -F -#define BB_FEATURE_LS_FILETYPES -// -// sort the file names -#define BB_FEATURE_LS_SORTFILES -// -// enable ls -R -#define BB_FEATURE_LS_RECURSIVE -// -// enable ls -L -#define BB_FEATURE_LS_FOLLOWLINKS -// -// Disable for a smaller (but less functional) ping -#define BB_FEATURE_FANCY_PING -// -// Make init use a simplified /etc/inittab file (recommended). -#define BB_FEATURE_USE_INITTAB -// -//Enable init being called as /linuxrc -#define BB_FEATURE_LINUXRC -// -//Have init enable core dumping for child processes (for debugging only) -//#define BB_FEATURE_INIT_COREDUMPS -// -//Make sure nothing is printed to the console on boot -//#define BB_FEATURE_EXTRA_QUIET -// -// enable syslogd -R remotehost -//#define BB_FEATURE_REMOTE_LOG -// -// enable syslogd -C -//#define BB_FEATURE_IPC_SYSLOG -// -//Disable for a simple tail implementation (2.34k vs 3k for the full one). -//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. -//#define BB_FEATURE_FANCY_TAIL -// -// Enable support for loop devices in mount -#define BB_FEATURE_MOUNT_LOOP -// -// Enable support for a real /etc/mtab file instead of /proc/mounts -//#define BB_FEATURE_MTAB_SUPPORT -// -// Enable support for mounting remote NFS volumes. -// You may need to mount with "-o nolock" if you are -// not running a local portmapper daemon... -#define BB_FEATURE_NFSMOUNT -// -// Enable support forced filesystem unmounting -// (i.e., in case of an unreachable NFS system). -#define BB_FEATURE_MOUNT_FORCE -// -// Enable support for creation of tar files. -#define BB_FEATURE_TAR_CREATE -// -// Enable support for "--exclude" and "-X" for excluding files -//#define BB_FEATURE_TAR_EXCLUDE -// -// Enable support for tar -z option (currently only works for inflating) -#define BB_FEATURE_TAR_GZIP -// -// Enable reverse sort -//#define BB_FEATURE_SORT_REVERSE -// -// Enable uniqe sort -//#define BB_FEATURE_SORT_UNIQUE -// -// Enable command line editing in the shell. -// Only relevant if a shell is enabled. On by default. -#define BB_FEATURE_COMMAND_EDITING -// -// Enable tab completion in the shell. This is now working quite nicely. -// This feature adds a bit over 4k. Only relevant if a shell is enabled. -#define BB_FEATURE_COMMAND_TAB_COMPLETION -// -// Attempts to match usernames in a ~-prefixed path -//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION -// -//Allow the shell to invoke all the compiled in BusyBox applets as if they -//were shell builtins. Nice for staticly linking an emergency rescue shell, -//among other things. Off by default. -// Only relevant if a shell is enabled. -//#define BB_FEATURE_SH_STANDALONE_SHELL -// -//When this is enabled, busybox shell applets can be called using full path -//names. This causes applets (i.e., most busybox commands) to override -//real commands on the filesystem. For example, if you run run /bin/cat, it -//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_ -//busybox. Some systems want this, others do not. Choose wisely. :-) This -//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled. -// Only relevant if a shell is enabled. Off by default. -//#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN -// -// Uncomment this option for a fancy shell prompt that includes the -// current username and hostname. On systems that don't have usernames -// or hostnames, this can look hideous. -// Only relevant if a shell is enabled. -//#define BB_FEATURE_SH_FANCY_PROMPT -// -//Turn on extra fbset options -//#define BB_FEATURE_FBSET_FANCY -// -//Turn on fbset readmode support -//#define BB_FEATURE_FBSET_READMODE -// -// Support insmod/lsmod/rmmod for post 2.1 kernels -//#define BB_FEATURE_NEW_MODULE_INTERFACE -// -// Support insmod/lsmod/rmmod for pre 2.1 kernels -//#define BB_FEATURE_OLD_MODULE_INTERFACE -// -// Support module version checking -//#define BB_FEATURE_INSMOD_VERSION_CHECKING -// -// Support for uClinux memory usage optimization, which will load the image -// directly into the kernel memory. This divides memory requrements by three. -// If you are not running uClinux (i.e., your CPU has an MMU) leave this -// disabled... -//#define BB_FEATURE_INSMOD_LOADINKMEM -// -// Support for Minix filesystem, version 2 -//#define BB_FEATURE_MINIX2 -// -// Enable ifconfig status reporting output -- this feature adds 12k. -#define BB_FEATURE_IFCONFIG_STATUS -// -// Enable ifconfig slip-specific options "keepalive" and "outfill" -//#define BB_FEATURE_IFCONFIG_SLIP -// -// Enable ifconfig options "mem_start", "io_addr", and "irq". -//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ -// -// Enable ifconfig option "hw". Currently works for only with "ether". -#define BB_FEATURE_IFCONFIG_HW -// -// Enable busybox --install [-s] -// to create links (or symlinks) for all the commands that are -// compiled into the binary. (needs /proc filesystem) -#define BB_FEATURE_INSTALLER -// -// Enable a nifty progress meter in wget (adds just under 2k) -#define BB_FEATURE_WGET_STATUSBAR -// -// Enable HTTP authentication in wget -#define BB_FEATURE_WGET_AUTHENTICATION -// -// Clean up all memory before exiting -- usually not needed -// as the OS can clean up... Don't enable this unless you -// have a really good reason for cleaning things up manually. -//#define BB_FEATURE_CLEAN_UP -// -// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G) -#define BB_FEATURE_HUMAN_READABLE -// -// Support for the find -type option. -#define BB_FEATURE_FIND_TYPE -// -// Support for the find -perm option. -#define BB_FEATURE_FIND_PERM -// -// Support for the find -mtine option. -#define BB_FEATURE_FIND_MTIME -// -// Support for the -A -B and -C context flags in grep -//#define BB_FEATURE_GREP_CONTEXT -// -// Support for the EGREP applet (alias to the grep applet) -//#define BB_FEATURE_GREP_EGREP_ALIAS -// -// Tell tftp what commands that should be supported. -#define BB_FEATURE_TFTP_PUT -#define BB_FEATURE_TFTP_GET -// -// features for vi -#define BB_FEATURE_VI_COLON // ":" colon commands, no "ex" mode -#define BB_FEATURE_VI_YANKMARK // Yank/Put commands and Mark cmds -#define BB_FEATURE_VI_SEARCH // search and replace cmds -#define BB_FEATURE_VI_USE_SIGNALS // catch signals -#define BB_FEATURE_VI_DOT_CMD // remember previous cmd and "." cmd -#define BB_FEATURE_VI_READONLY // vi -R and "view" mode -#define BB_FEATURE_VI_SETOPTS // set-able options, ai ic showmatch -#define BB_FEATURE_VI_SET // :set -#define BB_FEATURE_VI_WIN_RESIZE // handle window resize -// -// Enable a if you system have setuped locale -//#define BB_LOCALE_SUPPORT -// -// Support for TELNET to pass TERM type to remote host. Adds 384 bytes. -#define BB_FEATURE_TELNET_TTYPE -// -// End of Features List -// -// -// -// -// -// -//--------------------------------------------------- -// Nothing beyond this point should ever be touched by -// mere mortals so leave this stuff alone. -// -#include -#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__ - #undef BB_RPM2CPIO /* Uses gz_open(), which uses fork() */ - #undef BB_DPKG_DEB /* Uses gz_open(), which uses fork() */ - #undef BB_ASH /* Uses fork() */ - #undef BB_HUSH /* Uses fork() */ - #undef BB_LASH /* Uses fork() */ - #undef BB_INIT /* Uses fork() */ - #undef BB_FEATURE_TAR_GZIP /* Uses fork() */ - #undef BB_SYSLOGD /* Uses daemon() */ - #undef BB_KLOGD /* Uses daemon() */ - #undef BB_UPDATE /* Uses daemon() */ -#endif -#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH - #if defined BB_FEATURE_COMMAND_EDITING - #define BB_CMDEDIT - #else - #undef BB_FEATURE_COMMAND_EDITING - #undef BB_FEATURE_COMMAND_TAB_COMPLETION - #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION - #undef BB_FEATURE_SH_FANCY_PROMPT - #endif -#else - #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN - #undef BB_FEATURE_SH_STANDALONE_SHELL - #undef BB_FEATURE_SH_FANCY_PROMPT -#endif -// -#ifdef BB_KILLALL - #ifndef BB_KILL - #define BB_KILL - #endif -#endif -// -#ifndef BB_INIT - #undef BB_FEATURE_LINUXRC -#endif -// -#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT - #define BB_NFSMOUNT -#endif -// -#if defined BB_FEATURE_AUTOWIDTH - #ifndef BB_FEATURE_USE_TERMIOS - #define BB_FEATURE_USE_TERMIOS - #endif -#endif -// -#if defined BB_INSMOD || defined BB_LSMOD - #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE - #define BB_FEATURE_NEW_MODULE_INTERFACE - #endif -#endif -// -#ifdef BB_UNIX2DOS - #define BB_DOS2UNIX -#endif -// -#ifdef BB_SYSLOGD - #if defined BB_FEATURE_IPC_SYSLOG - #define BB_LOGREAD - #endif -#endif -// -#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH -# define shell_main ash_main -#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH -# define shell_main hush_main -#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH -# define shell_main lash_main -#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH -# define shell_main msh_main -#endif diff --git a/busybox/debian/Config.h-static b/busybox/debian/Config.h-static deleted file mode 100644 index 094b1f9b4..000000000 --- a/busybox/debian/Config.h-static +++ /dev/null @@ -1,469 +0,0 @@ -/* vi: set sw=4 ts=4: */ -// This file defines the feature set to be compiled into busybox. -// When you turn things off here, they won't be compiled in at all. -// -//// This file is parsed by sed. You MUST use single line comments. -// i.e., //#define BB_BLAH -// -// -// BusyBox Applications -//#define BB_ADJTIMEX -#define BB_AR -#define BB_ASH -#define BB_BASENAME -#define BB_CAT -#define BB_CHGRP -#define BB_CHMOD -#define BB_CHOWN -#define BB_CHROOT -#define BB_CHVT -#define BB_CLEAR -#define BB_CMP -#define BB_CP -#define BB_CPIO -#define BB_CUT -#define BB_DATE -#define BB_DC -#define BB_DD -#define BB_DEALLOCVT -#define BB_DF -#define BB_DIRNAME -#define BB_DMESG -#define BB_DOS2UNIX -#define BB_DPKG -#define BB_DPKG_DEB -#define BB_DUTMP -#define BB_DU -#define BB_DUMPKMAP -#define BB_ECHO -#define BB_ENV -#define BB_EXPR -#define BB_FBSET -#define BB_FDFLUSH -#define BB_FIND -#define BB_FREE -#define BB_FREERAMDISK -#define BB_FSCK_MINIX -#define BB_GETOPT -#define BB_GREP -#define BB_GUNZIP -#define BB_GZIP -#define BB_HALT -#define BB_HEAD -#define BB_HOSTID -#define BB_HOSTNAME -//#define BB_HUSH -#define BB_ID -#define BB_IFCONFIG -#define BB_INIT -//#define BB_INSMOD -#define BB_KILL -#define BB_KILLALL -#define BB_KLOGD -//#define BB_LASH -#define BB_LENGTH -#define BB_LN -#define BB_LOADACM -#define BB_LOADFONT -#define BB_LOADKMAP -#define BB_LOGGER -#define BB_LOGNAME -#define BB_LS -#define BB_LSMOD -#define BB_MAKEDEVS -#define BB_MD5SUM -#define BB_MKDIR -#define BB_MKFIFO -#define BB_MKFS_MINIX -#define BB_MKNOD -#define BB_MKSWAP -#define BB_MKTEMP -//#define BB_MODPROBE -#define BB_MORE -#define BB_MOUNT -//#define BB_MSH -#define BB_MT -#define BB_MV -#define BB_NC -#define BB_NSLOOKUP -#define BB_PIDOF -#define BB_PING -#define BB_PIVOT_ROOT -#define BB_POWEROFF -#define BB_PRINTF -#define BB_PS -#define BB_PWD -#define BB_RDATE -#define BB_READLINK -#define BB_REBOOT -#define BB_RENICE -#define BB_RESET -#define BB_RM -#define BB_RMDIR -#define BB_RMMOD -#define BB_ROUTE -#define BB_RPM2CPIO -#define BB_SED -#define BB_SETKEYCODES -#define BB_SLEEP -#define BB_SORT -#define BB_STTY -#define BB_SWAPONOFF -#define BB_SYNC -#define BB_SYSLOGD -#define BB_TAIL -#define BB_TAR -#define BB_TEE -#define BB_TEST -#define BB_TELNET -#define BB_TFTP -#define BB_TOUCH -#define BB_TR -#define BB_TRACEROUTE -#define BB_TRUE_FALSE -#define BB_TTY -#define BB_UNIX2DOS -#define BB_UUENCODE -#define BB_UUDECODE -#define BB_UMOUNT -#define BB_UNIQ -#define BB_UNAME -#define BB_UPDATE -#define BB_UPTIME -#define BB_USLEEP -#define BB_VI -#define BB_WATCHDOG -#define BB_WC -#define BB_WGET -#define BB_WHICH -#define BB_WHOAMI -#define BB_XARGS -#define BB_YES -// End of Applications List -// -// -// -// --------------------------------------------------------- -// This is where feature definitions go. Generally speaking, -// turning this stuff off makes things a bit smaller (and less -// pretty/useful). -// -// -// If you enabled one or more of the shells, you may select which one -// should be run when sh is invoked: -#define BB_FEATURE_SH_IS_ASH -//#define BB_FEATURE_SH_IS_HUSH -//#define BB_FEATURE_SH_IS_LASH -//#define BB_FEATURE_SH_IS_MSH -// -// BusyBox will, by default, malloc space for its buffers. This costs code -// size for the call to xmalloc. You can use the following feature to have -// them put on the stack. For some very small machines with limited stack -// space, this can be deadly. For most folks, this works just fine... -//#define BB_FEATURE_BUFFERS_GO_ON_STACK -// The third alternative for buffer allocation is to use BSS. This works -// beautifully for computers with a real MMU (and OS support), but wastes -// runtime RAM for uCLinux. This behavior was the only one available for -// BusyBox versions 0.48 and earlier. -//#define BB_FEATURE_BUFFERS_GO_IN_BSS -// -// Turn this on to use Erik's very cool devps, and devmtab kernel drivers, -// thereby eliminating the need for the /proc filesystem and thereby saving -// lots and lots memory for more important things. NOTE: If you enable this -// feature, you _must_ have patched the kernel to include the devps patch that -// is included in the busybox/kernel-patches directory. You will also need to -// create some device special files in /dev on your embedded system: -// mknod /dev/mtab c 10 22 -// mknod /dev/ps c 10 21 -// I emailed Linus and this patch will not be going into the stock kernel. -//#define BB_FEATURE_USE_DEVPS_PATCH -// -// show verbose usage messages -#define BB_FEATURE_VERBOSE_USAGE -// -// Use termios to manipulate the screen ('more' is prettier with this on) -#define BB_FEATURE_USE_TERMIOS -// -// calculate terminal & column widths (for more and ls) -#define BB_FEATURE_AUTOWIDTH -// -// show username/groupnames for ls -#define BB_FEATURE_LS_USERNAME -// -// show file timestamps in ls -#define BB_FEATURE_LS_TIMESTAMPS -// -// enable ls -p and -F -#define BB_FEATURE_LS_FILETYPES -// -// sort the file names -#define BB_FEATURE_LS_SORTFILES -// -// enable ls -R -#define BB_FEATURE_LS_RECURSIVE -// -// enable ls -L -#define BB_FEATURE_LS_FOLLOWLINKS -// -// Disable for a smaller (but less functional) ping -#define BB_FEATURE_FANCY_PING -// -// Make init use a simplified /etc/inittab file (recommended). -#define BB_FEATURE_USE_INITTAB -// -//Enable init being called as /linuxrc -#define BB_FEATURE_LINUXRC -// -//Have init enable core dumping for child processes (for debugging only) -//#define BB_FEATURE_INIT_COREDUMPS -// -//Make sure nothing is printed to the console on boot -//#define BB_FEATURE_EXTRA_QUIET -// -// enable syslogd -R remotehost -#define BB_FEATURE_REMOTE_LOG -// -// enable syslogd -C -//#define BB_FEATURE_IPC_SYSLOG -// -//Disable for a simple tail implementation (2.34k vs 3k for the full one). -//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. -#define BB_FEATURE_FANCY_TAIL -// -// Enable support for loop devices in mount -#define BB_FEATURE_MOUNT_LOOP -// -// Enable support for a real /etc/mtab file instead of /proc/mounts -//#define BB_FEATURE_MTAB_SUPPORT -// -// Enable support for mounting remote NFS volumes. -// You may need to mount with "-o nolock" if you are -// not running a local portmapper daemon... -#define BB_FEATURE_NFSMOUNT -// -// Enable support forced filesystem unmounting -// (i.e., in case of an unreachable NFS system). -#define BB_FEATURE_MOUNT_FORCE -// -// Enable support for creation of tar files. -#define BB_FEATURE_TAR_CREATE -// -// Enable support for "--exclude" and "-X" for excluding files -#define BB_FEATURE_TAR_EXCLUDE -// -// Enable support for tar -z option (currently only works for inflating) -#define BB_FEATURE_TAR_GZIP -// -// Enable reverse sort -#define BB_FEATURE_SORT_REVERSE -// -// Enable uniqe sort -#define BB_FEATURE_SORT_UNIQUE -// -// Enable command line editing in the shell. -// Only relevant if a shell is enabled. On by default. -#define BB_FEATURE_COMMAND_EDITING -// -// Enable tab completion in the shell. This is now working quite nicely. -// This feature adds a bit over 4k. Only relevant if a shell is enabled. -#define BB_FEATURE_COMMAND_TAB_COMPLETION -// -// Attempts to match usernames in a ~-prefixed path -//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION -// -//Allow the shell to invoke all the compiled in BusyBox applets as if they -//were shell builtins. Nice for staticly linking an emergency rescue shell, -//among other things. Off by default. -// Only relevant if a shell is enabled. -#define BB_FEATURE_SH_STANDALONE_SHELL -// -//When this is enabled, busybox shell applets can be called using full path -//names. This causes applets (i.e., most busybox commands) to override -//real commands on the filesystem. For example, if you run run /bin/cat, it -//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_ -//busybox. Some systems want this, others do not. Choose wisely. :-) This -//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled. -// Only relevant if a shell is enabled. Off by default. -#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN -// -// Uncomment this option for a fancy shell prompt that includes the -// current username and hostname. On systems that don't have usernames -// or hostnames, this can look hideous. -// Only relevant if a shell is enabled. -#define BB_FEATURE_SH_FANCY_PROMPT -// -//Turn on extra fbset options -//#define BB_FEATURE_FBSET_FANCY -// -//Turn on fbset readmode support -//#define BB_FEATURE_FBSET_READMODE -// -// Support insmod/lsmod/rmmod for post 2.1 kernels -#define BB_FEATURE_NEW_MODULE_INTERFACE -// -// Support insmod/lsmod/rmmod for pre 2.1 kernels -//#define BB_FEATURE_OLD_MODULE_INTERFACE -// -// Support module version checking -//#define BB_FEATURE_INSMOD_VERSION_CHECKING -// -// Support for uClinux memory usage optimization, which will load the image -// directly into the kernel memory. This divides memory requrements by three. -// If you are not running uClinux (i.e., your CPU has an MMU) leave this -// disabled... -//#define BB_FEATURE_INSMOD_LOADINKMEM -// -// Support for Minix filesystem, version 2 -//#define BB_FEATURE_MINIX2 -// -// Enable ifconfig status reporting output -- this feature adds 12k. -#define BB_FEATURE_IFCONFIG_STATUS -// -// Enable ifconfig slip-specific options "keepalive" and "outfill" -//#define BB_FEATURE_IFCONFIG_SLIP -// -// Enable ifconfig options "mem_start", "io_addr", and "irq". -//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ -// -// Enable ifconfig option "hw". Currently works for only with "ether". -#define BB_FEATURE_IFCONFIG_HW -// -// Enable busybox --install [-s] -// to create links (or symlinks) for all the commands that are -// compiled into the binary. (needs /proc filesystem) -#define BB_FEATURE_INSTALLER -// -// Enable a nifty progress meter in wget (adds just under 2k) -#define BB_FEATURE_WGET_STATUSBAR -// -// Enable HTTP authentication in wget -#define BB_FEATURE_WGET_AUTHENTICATION -// -// Clean up all memory before exiting -- usually not needed -// as the OS can clean up... Don't enable this unless you -// have a really good reason for cleaning things up manually. -//#define BB_FEATURE_CLEAN_UP -// -// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G) -#define BB_FEATURE_HUMAN_READABLE -// -// Support for the find -type option. -#define BB_FEATURE_FIND_TYPE -// -// Support for the find -perm option. -#define BB_FEATURE_FIND_PERM -// -// Support for the find -mtine option. -#define BB_FEATURE_FIND_MTIME -// -// Support for the -A -B and -C context flags in grep -//#define BB_FEATURE_GREP_CONTEXT -// -// Support for the EGREP applet (alias to the grep applet) -//#define BB_FEATURE_GREP_EGREP_ALIAS -// -// Tell tftp what commands that should be supported. -#define BB_FEATURE_TFTP_PUT -#define BB_FEATURE_TFTP_GET -// -// features for vi -#define BB_FEATURE_VI_COLON // ":" colon commands, no "ex" mode -#define BB_FEATURE_VI_YANKMARK // Yank/Put commands and Mark cmds -#define BB_FEATURE_VI_SEARCH // search and replace cmds -#define BB_FEATURE_VI_USE_SIGNALS // catch signals -#define BB_FEATURE_VI_DOT_CMD // remember previous cmd and "." cmd -#define BB_FEATURE_VI_READONLY // vi -R and "view" mode -#define BB_FEATURE_VI_SETOPTS // set-able options, ai ic showmatch -#define BB_FEATURE_VI_SET // :set -#define BB_FEATURE_VI_WIN_RESIZE // handle window resize -// -// Enable a if you system have setuped locale -//#define BB_LOCALE_SUPPORT -// -// Support for TELNET to pass TERM type to remote host. Adds 384 bytes. -#define BB_FEATURE_TELNET_TTYPE -// -// End of Features List -// -// -// -// -// -// -//--------------------------------------------------- -// Nothing beyond this point should ever be touched by -// mere mortals so leave this stuff alone. -// -#include -#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__ - #undef BB_RPM2CPIO /* Uses gz_open(), which uses fork() */ - #undef BB_DPKG_DEB /* Uses gz_open(), which uses fork() */ - #undef BB_ASH /* Uses fork() */ - #undef BB_HUSH /* Uses fork() */ - #undef BB_LASH /* Uses fork() */ - #undef BB_INIT /* Uses fork() */ - #undef BB_FEATURE_TAR_GZIP /* Uses fork() */ - #undef BB_SYSLOGD /* Uses daemon() */ - #undef BB_KLOGD /* Uses daemon() */ - #undef BB_UPDATE /* Uses daemon() */ -#endif -#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH - #if defined BB_FEATURE_COMMAND_EDITING - #define BB_CMDEDIT - #else - #undef BB_FEATURE_COMMAND_EDITING - #undef BB_FEATURE_COMMAND_TAB_COMPLETION - #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION - #undef BB_FEATURE_SH_FANCY_PROMPT - #endif -#else - #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN - #undef BB_FEATURE_SH_STANDALONE_SHELL - #undef BB_FEATURE_SH_FANCY_PROMPT -#endif -// -#ifdef BB_KILLALL - #ifndef BB_KILL - #define BB_KILL - #endif -#endif -// -#ifndef BB_INIT - #undef BB_FEATURE_LINUXRC -#endif -// -#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT - #define BB_NFSMOUNT -#endif -// -#if defined BB_FEATURE_AUTOWIDTH - #ifndef BB_FEATURE_USE_TERMIOS - #define BB_FEATURE_USE_TERMIOS - #endif -#endif -// -#if defined BB_INSMOD || defined BB_LSMOD - #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE - #define BB_FEATURE_NEW_MODULE_INTERFACE - #endif -#endif -// -#ifdef BB_UNIX2DOS - #define BB_DOS2UNIX -#endif -// -#ifdef BB_SYSLOGD - #if defined BB_FEATURE_IPC_SYSLOG - #define BB_LOGREAD - #endif -#endif -// -#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH -# define shell_main ash_main -#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH -# define shell_main hush_main -#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH -# define shell_main lash_main -#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH -# define shell_main msh_main -#endif diff --git a/busybox/debian/Config.h-udeb b/busybox/debian/Config.h-udeb deleted file mode 100644 index 4fb0597e2..000000000 --- a/busybox/debian/Config.h-udeb +++ /dev/null @@ -1,469 +0,0 @@ -/* vi: set sw=4 ts=4: */ -// This file defines the feature set to be compiled into busybox. -// When you turn things off here, they won't be compiled in at all. -// -//// This file is parsed by sed. You MUST use single line comments. -// i.e., //#define BB_BLAH -// -// -// BusyBox Applications -//#define BB_ADJTIMEX -#define BB_AR -//#define BB_ASH -#define BB_BASENAME -#define BB_CAT -//#define BB_CHGRP -#define BB_CHMOD -#define BB_CHOWN -#define BB_CHROOT -#define BB_CHVT -//#define BB_CLEAR -//#define BB_CMP -#define BB_CP -//#define BB_CPIO -#define BB_CUT -//#define BB_DATE -//#define BB_DC -//#define BB_DD -//#define BB_DEALLOCVT -#define BB_DF -#define BB_DIRNAME -#define BB_DMESG -//#define BB_DOS2UNIX -//#define BB_DPKG -//#define BB_DPKG_DEB -//#define BB_DUTMP -//#define BB_DU -//#define BB_DUMPKMAP -#define BB_ECHO -#define BB_ENV -#define BB_EXPR -//#define BB_FBSET -//#define BB_FDFLUSH -#define BB_FIND -#define BB_FREE -#define BB_FREERAMDISK -//#define BB_FSCK_MINIX -//#define BB_GETOPT -#define BB_GREP -#define BB_GUNZIP -//#define BB_GZIP -//#define BB_HALT -//#define BB_HEAD -//#define BB_HOSTID -//#define BB_HOSTNAME -//#define BB_HUSH -//#define BB_ID -#define BB_IFCONFIG -#define BB_INIT -//#define BB_INSMOD -#define BB_KILL -//#define BB_KILLALL -#define BB_KLOGD -//#define BB_LASH -//#define BB_LENGTH -#define BB_LN -//#define BB_LOADACM -//#define BB_LOADFONT -//#define BB_LOADKMAP -//#define BB_LOGGER -//#define BB_LOGNAME -#define BB_LS -#define BB_LSMOD -//#define BB_MAKEDEVS -#define BB_MD5SUM -#define BB_MKDIR -//#define BB_MKFIFO -//#define BB_MKFS_MINIX -#define BB_MKNOD -//#define BB_MKSWAP -//#define BB_MKTEMP -//#define BB_MODPROBE -//#define BB_MORE -#define BB_MOUNT -//#define BB_MSH -//#define BB_MT -#define BB_MV -//#define BB_NC -//#define BB_NSLOOKUP -//#define BB_PIDOF -#define BB_PING -#define BB_PIVOT_ROOT -//#define BB_POWEROFF -//#define BB_PRINTF -#define BB_PS -#define BB_PWD -//#define BB_RDATE -//#define BB_READLINK -#define BB_REBOOT -//#define BB_RENICE -//#define BB_RESET -#define BB_RM -#define BB_RMDIR -//#define BB_RMMOD -#define BB_ROUTE -//#define BB_RPM2CPIO -#define BB_SED -//#define BB_SETKEYCODES -//#define BB_SLEEP -//#define BB_SORT -//#define BB_STTY -//#define BB_SWAPONOFF -#define BB_SYNC -#define BB_SYSLOGD -#define BB_TAIL -#define BB_TAR -//#define BB_TEE -//#define BB_TEST -#define BB_TELNET -//#define BB_TFTP -//#define BB_TOUCH -#define BB_TR -//#define BB_TRACEROUTE -#define BB_TRUE_FALSE -//#define BB_TTY -//#define BB_UNIX2DOS -//#define BB_UUENCODE -//#define BB_UUDECODE -#define BB_UMOUNT -//#define BB_UNIQ -//#define BB_UNAME -//#define BB_UPDATE -//#define BB_UPTIME -//#define BB_USLEEP -//#define BB_VI -//#define BB_WATCHDOG -//#define BB_WC -#define BB_WGET -//#define BB_WHICH -//#define BB_WHOAMI -//#define BB_XARGS -//#define BB_YES -// End of Applications List -// -// -// -// --------------------------------------------------------- -// This is where feature definitions go. Generally speaking, -// turning this stuff off makes things a bit smaller (and less -// pretty/useful). -// -// -// If you enabled one or more of the shells, you may select which one -// should be run when sh is invoked: -//#define BB_FEATURE_SH_IS_ASH -//#define BB_FEATURE_SH_IS_HUSH -//#define BB_FEATURE_SH_IS_LASH -#define BB_FEATURE_SH_IS_MSH -// -// BusyBox will, by default, malloc space for its buffers. This costs code -// size for the call to xmalloc. You can use the following feature to have -// them put on the stack. For some very small machines with limited stack -// space, this can be deadly. For most folks, this works just fine... -//#define BB_FEATURE_BUFFERS_GO_ON_STACK -// The third alternative for buffer allocation is to use BSS. This works -// beautifully for computers with a real MMU (and OS support), but wastes -// runtime RAM for uCLinux. This behavior was the only one available for -// BusyBox versions 0.48 and earlier. -//#define BB_FEATURE_BUFFERS_GO_IN_BSS -// -// Turn this on to use Erik's very cool devps, and devmtab kernel drivers, -// thereby eliminating the need for the /proc filesystem and thereby saving -// lots and lots memory for more important things. NOTE: If you enable this -// feature, you _must_ have patched the kernel to include the devps patch that -// is included in the busybox/kernel-patches directory. You will also need to -// create some device special files in /dev on your embedded system: -// mknod /dev/mtab c 10 22 -// mknod /dev/ps c 10 21 -// I emailed Linus and this patch will not be going into the stock kernel. -//#define BB_FEATURE_USE_DEVPS_PATCH -// -// show verbose usage messages -//#define BB_FEATURE_VERBOSE_USAGE -// -// Use termios to manipulate the screen ('more' is prettier with this on) -#define BB_FEATURE_USE_TERMIOS -// -// calculate terminal & column widths (for more and ls) -#define BB_FEATURE_AUTOWIDTH -// -// show username/groupnames for ls -#define BB_FEATURE_LS_USERNAME -// -// show file timestamps in ls -#define BB_FEATURE_LS_TIMESTAMPS -// -// enable ls -p and -F -//#define BB_FEATURE_LS_FILETYPES -// -// sort the file names -#define BB_FEATURE_LS_SORTFILES -// -// enable ls -R -//#define BB_FEATURE_LS_RECURSIVE -// -// enable ls -L -//#define BB_FEATURE_LS_FOLLOWLINKS -// -// Disable for a smaller (but less functional) ping -#define BB_FEATURE_FANCY_PING -// -// Make init use a simplified /etc/inittab file (recommended). -#define BB_FEATURE_USE_INITTAB -// -//Enable init being called as /linuxrc -#define BB_FEATURE_LINUXRC -// -//Have init enable core dumping for child processes (for debugging only) -//#define BB_FEATURE_INIT_COREDUMPS -// -//Make sure nothing is printed to the console on boot -//#define BB_FEATURE_EXTRA_QUIET -// -// enable syslogd -R remotehost -//#define BB_FEATURE_REMOTE_LOG -// -// enable syslogd -C -//#define BB_FEATURE_IPC_SYSLOG -// -//Disable for a simple tail implementation (2.34k vs 3k for the full one). -//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. -//#define BB_FEATURE_FANCY_TAIL -// -// Enable support for loop devices in mount -#define BB_FEATURE_MOUNT_LOOP -// -// Enable support for a real /etc/mtab file instead of /proc/mounts -//#define BB_FEATURE_MTAB_SUPPORT -// -// Enable support for mounting remote NFS volumes. -// You may need to mount with "-o nolock" if you are -// not running a local portmapper daemon... -#define BB_FEATURE_NFSMOUNT -// -// Enable support forced filesystem unmounting -// (i.e., in case of an unreachable NFS system). -#define BB_FEATURE_MOUNT_FORCE -// -// Enable support for creation of tar files. -//#define BB_FEATURE_TAR_CREATE -// -// Enable support for "--exclude" and "-X" for excluding files -//#define BB_FEATURE_TAR_EXCLUDE -// -// Enable support for tar -z option (currently only works for inflating) -#define BB_FEATURE_TAR_GZIP -// -// Enable reverse sort -//#define BB_FEATURE_SORT_REVERSE -// -// Enable uniqe sort -//#define BB_FEATURE_SORT_UNIQUE -// -// Enable command line editing in the shell. -// Only relevant if a shell is enabled. On by default. -#define BB_FEATURE_COMMAND_EDITING -// -// Enable tab completion in the shell. This is now working quite nicely. -// This feature adds a bit over 4k. Only relevant if a shell is enabled. -#define BB_FEATURE_COMMAND_TAB_COMPLETION -// -// Attempts to match usernames in a ~-prefixed path -//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION -// -//Allow the shell to invoke all the compiled in BusyBox applets as if they -//were shell builtins. Nice for staticly linking an emergency rescue shell, -//among other things. Off by default. -// Only relevant if a shell is enabled. -//#define BB_FEATURE_SH_STANDALONE_SHELL -// -//When this is enabled, busybox shell applets can be called using full path -//names. This causes applets (i.e., most busybox commands) to override -//real commands on the filesystem. For example, if you run run /bin/cat, it -//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_ -//busybox. Some systems want this, others do not. Choose wisely. :-) This -//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled. -// Only relevant if a shell is enabled. Off by default. -//#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN -// -// Uncomment this option for a fancy shell prompt that includes the -// current username and hostname. On systems that don't have usernames -// or hostnames, this can look hideous. -// Only relevant if a shell is enabled. -//#define BB_FEATURE_SH_FANCY_PROMPT -// -//Turn on extra fbset options -//#define BB_FEATURE_FBSET_FANCY -// -//Turn on fbset readmode support -//#define BB_FEATURE_FBSET_READMODE -// -// Support insmod/lsmod/rmmod for post 2.1 kernels -//#define BB_FEATURE_NEW_MODULE_INTERFACE -// -// Support insmod/lsmod/rmmod for pre 2.1 kernels -//#define BB_FEATURE_OLD_MODULE_INTERFACE -// -// Support module version checking -//#define BB_FEATURE_INSMOD_VERSION_CHECKING -// -// Support for uClinux memory usage optimization, which will load the image -// directly into the kernel memory. This divides memory requrements by three. -// If you are not running uClinux (i.e., your CPU has an MMU) leave this -// disabled... -//#define BB_FEATURE_INSMOD_LOADINKMEM -// -// Support for Minix filesystem, version 2 -//#define BB_FEATURE_MINIX2 -// -// Enable ifconfig status reporting output -- this feature adds 12k. -#define BB_FEATURE_IFCONFIG_STATUS -// -// Enable ifconfig slip-specific options "keepalive" and "outfill" -//#define BB_FEATURE_IFCONFIG_SLIP -// -// Enable ifconfig options "mem_start", "io_addr", and "irq". -//#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ -// -// Enable ifconfig option "hw". Currently works for only with "ether". -#define BB_FEATURE_IFCONFIG_HW -// -// Enable busybox --install [-s] -// to create links (or symlinks) for all the commands that are -// compiled into the binary. (needs /proc filesystem) -//#define BB_FEATURE_INSTALLER -// -// Enable a nifty progress meter in wget (adds just under 2k) -#define BB_FEATURE_WGET_STATUSBAR -// -// Enable HTTP authentication in wget -//#define BB_FEATURE_WGET_AUTHENTICATION -// -// Clean up all memory before exiting -- usually not needed -// as the OS can clean up... Don't enable this unless you -// have a really good reason for cleaning things up manually. -//#define BB_FEATURE_CLEAN_UP -// -// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G) -//#define BB_FEATURE_HUMAN_READABLE -// -// Support for the find -type option. -#define BB_FEATURE_FIND_TYPE -// -// Support for the find -perm option. -#define BB_FEATURE_FIND_PERM -// -// Support for the find -mtine option. -#define BB_FEATURE_FIND_MTIME -// -// Support for the -A -B and -C context flags in grep -//#define BB_FEATURE_GREP_CONTEXT -// -// Support for the EGREP applet (alias to the grep applet) -//#define BB_FEATURE_GREP_EGREP_ALIAS -// -// Tell tftp what commands that should be supported. -#define BB_FEATURE_TFTP_PUT -#define BB_FEATURE_TFTP_GET -// -// features for vi -#define BB_FEATURE_VI_COLON // ":" colon commands, no "ex" mode -#define BB_FEATURE_VI_YANKMARK // Yank/Put commands and Mark cmds -#define BB_FEATURE_VI_SEARCH // search and replace cmds -#define BB_FEATURE_VI_USE_SIGNALS // catch signals -#define BB_FEATURE_VI_DOT_CMD // remember previous cmd and "." cmd -#define BB_FEATURE_VI_READONLY // vi -R and "view" mode -#define BB_FEATURE_VI_SETOPTS // set-able options, ai ic showmatch -#define BB_FEATURE_VI_SET // :set -#define BB_FEATURE_VI_WIN_RESIZE // handle window resize -// -// Enable a if you system have setuped locale -//#define BB_LOCALE_SUPPORT -// -// Support for TELNET to pass TERM type to remote host. Adds 384 bytes. -#define BB_FEATURE_TELNET_TTYPE -// -// End of Features List -// -// -// -// -// -// -//--------------------------------------------------- -// Nothing beyond this point should ever be touched by -// mere mortals so leave this stuff alone. -// -#include -#if defined __UCLIBC__ && ! defined __UCLIBC_HAS_MMU__ - #undef BB_RPM2CPIO /* Uses gz_open(), which uses fork() */ - #undef BB_DPKG_DEB /* Uses gz_open(), which uses fork() */ - #undef BB_ASH /* Uses fork() */ - #undef BB_HUSH /* Uses fork() */ - #undef BB_LASH /* Uses fork() */ - #undef BB_INIT /* Uses fork() */ - #undef BB_FEATURE_TAR_GZIP /* Uses fork() */ - #undef BB_SYSLOGD /* Uses daemon() */ - #undef BB_KLOGD /* Uses daemon() */ - #undef BB_UPDATE /* Uses daemon() */ -#endif -#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH - #if defined BB_FEATURE_COMMAND_EDITING - #define BB_CMDEDIT - #else - #undef BB_FEATURE_COMMAND_EDITING - #undef BB_FEATURE_COMMAND_TAB_COMPLETION - #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION - #undef BB_FEATURE_SH_FANCY_PROMPT - #endif -#else - #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN - #undef BB_FEATURE_SH_STANDALONE_SHELL - #undef BB_FEATURE_SH_FANCY_PROMPT -#endif -// -#ifdef BB_KILLALL - #ifndef BB_KILL - #define BB_KILL - #endif -#endif -// -#ifndef BB_INIT - #undef BB_FEATURE_LINUXRC -#endif -// -#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT - #define BB_NFSMOUNT -#endif -// -#if defined BB_FEATURE_AUTOWIDTH - #ifndef BB_FEATURE_USE_TERMIOS - #define BB_FEATURE_USE_TERMIOS - #endif -#endif -// -#if defined BB_INSMOD || defined BB_LSMOD - #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE - #define BB_FEATURE_NEW_MODULE_INTERFACE - #endif -#endif -// -#ifdef BB_UNIX2DOS - #define BB_DOS2UNIX -#endif -// -#ifdef BB_SYSLOGD - #if defined BB_FEATURE_IPC_SYSLOG - #define BB_LOGREAD - #endif -#endif -// -#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH -# define shell_main ash_main -#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH -# define shell_main hush_main -#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH -# define shell_main lash_main -#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH -# define shell_main msh_main -#endif diff --git a/busybox/debian/README.debian b/busybox/debian/README.debian deleted file mode 100644 index f210a3e39..000000000 --- a/busybox/debian/README.debian +++ /dev/null @@ -1,10 +0,0 @@ -BusyBox for Debian ----------------------- - -BusyBox is being developed and maintained by Erik Andersen -. - -If you have a problem with BusyBox, send email to the Debian bug tracking -system that lives at - -Erik Andersen , Sun, 18 Jun 2000 21:52:00 -0600 diff --git a/busybox/debian/changelog b/busybox/debian/changelog deleted file mode 100644 index 4b719e211..000000000 --- a/busybox/debian/changelog +++ /dev/null @@ -1,192 +0,0 @@ -busybox (1:0.60.2-1) unstable; urgency=low - - * New stable version released. See changelog for details. - * Teaches 'mount -t auto' to ignore usbdevfs, thanks to - Ethan Benson (closes: #111055) - * Removes all the .o files from the source tarball (oops!) - thanks to Matt Kraai, who noticed. - - -- Erik Andersen Thu, 23 Aug 2001 15:44:14 -0600 - -busybox (1:0.60.1-1) unstable; urgency=low - - * New stable version released. See changelog for details. - * Enabled 'ar' for the udeb - - -- Erik Andersen Thu, 23 Aug 2001 15:44:14 -0600 - -busybox (1:0.60.0-1) unstable; urgency=low - - * New stable version released. See changelog for details. - - -- Erik Andersen Thu, 2 Aug 2001 12:12:37 -0600 - -busybox (1:0.52-1.1) unstable; urgency=high - - * Non-maintainer upload - * Fixed wget -P handling (closes: #106223). - - -- Matt Kraai Wed, 25 Jul 2001 11:01:38 -0600 - -busybox (1:0.52-1) unstable; urgency=high - - * New version released. See changelog for details. - - -- Erik Andersen Sat, 7 Jul 2001 01:23:45 -0600 - -busybox (1:0.51-10) unstable; urgency=high - - * Fix a compile problem with gcc 3.0 on hppa (closes: #102045) - - -- Erik Andersen Sat, 23 Jun 2001 23:55:57 -0600 - -busybox (1:0.51-9) unstable; urgency=high - - * tar was creating leading directories with 0777 permissions as - as reult of faulty umask handling. This fixes it, repairing - a grave security problem in the woody the boot floppies. - (closes: #101169) - - -- Erik Andersen Wed, 20 Jun 2001 16:17:38 -0600 - -busybox (1:0.51-8) unstable; urgency=high - - * Fix cp from /proc, where size=0 (closes: #100369) - * Add some padding to struct sysinfo for m68k. - * Apparently some bugs failed to be closed when master choked - (closes: #99627, #99637, #98571) - * Disable the busybox shell for the .deb, since it is not needed - for the boot floppies. - - -- Erik Andersen Mon, 11 Jun 2001 13:26:07 -0600 - -busybox (1:0.51-7) unstable; urgency=high - - * Fix tar permission setting for existing directories (closes: #99627) - * Do not remove the .cvsignore files on 'make release' (closes: #99637) - - -- Erik Andersen Mon, 4 Jun 2001 10:55:19 -0600 - -busybox (1:0.51-6) testing unstable; urgency=high - - * Update the version in testing so DHCP in the woody boot-floppies will work. - * Enable expr for the boot-floppies (closes: #98433) - * It builds on arm just fine now (closes: #97510) - - -- Erik Andersen Wed, 23 May 2001 14:50:13 -0600 - -busybox (1:0.51-5) unstable; urgency=low - - * Backport a sed fix from 0.52pre - * Backport chroot fix from 0.52pre - - -- Erik Andersen Wed, 16 May 2001 23:50:33 -0600 - -busybox (1:0.51-4) unstable; urgency=low - - * Backport from 0.52pre an endianness bugfix for md5sum - * Backport some updates to grep and sed - * Fix 'wget -O -' so it sets the quiet flag - - -- Erik Andersen Mon, 14 May 2001 14:17:36 -0600 - -busybox (1:0.51-3) unstable; urgency=low - - * This is the "I am an idiot" release. - * Make cp and mv work again (closes: #97290) - * Fix the version number. - - -- Erik Andersen Sat, 12 May 2001 17:35:58 -0600 - -busybox (0.51-2) unstable; urgency=low - - * Backport several release critical fixes into the 0.51 codebase - so the boot-floppies will work again. - * Fix a link ordering problem. (closes: #93362) - * Fixed gunzip (closes: #94331) - * Fixed cp permission setting (closes: #94580) - - -- Erik Andersen Sat, 12 May 2001 11:22:35 -0600 - -busybox (0.51-1) unstable; urgency=low - - * Fixes several critical bugs (see the busybox changelog - for complete details) - * Force USE_SYSTEM_PWD_GRP=false, so busybox bypasses - the glibc NSS libraries. (closes: #93362) - * Fixed a bug in sed's address range handling (closes: #91758) - * Removed irrelevant cruft from the bottem of debian/changelog - - -- Erik Andersen Tue, 10 Apr 2001 14:07:29 -0600 - -busybox (0.50-2) unstable; urgency=low - - * Enabled freeramdisk and pivot_root in the udeb (closes: #91336) - * Disabled lash (the busybox shell) in the udeb (closes: #91337) - * fixed a bug in syslog, a problem with rebooting when booted as - an initrd, and a few other minor problems. - - -- Erik Andersen Sun, 25 Mar 2001 20:59:44 -0700 - - -busybox (0.50-2) unstable; urgency=low - - * Enabled freeramdisk and pivot_root in the udeb (closes: #91336) - * Disabled lash (the busybox shell) in the udeb (closes: #91337) - * fixed a bug in syslog, a problem with rebooting when booted as - an initrd, and a few other minor problems. - - -- Erik Andersen Sun, 25 Mar 2001 20:59:44 -0700 - -busybox (0.50-1) unstable; urgency=low - - * Tons on improvements all around -- See changelog for details. - * Fix malformed Build-Depends (closes: #86930) - * grep has worked for some time now (closes: #81084) - * init compiles with DEBUG_INIT enabled (closes: #85794) - * md5sum no longer displays filename when reading stdin (closes: #81283) - * lsmod, rmmod, and insmod are no longer enabled (closes: #85642) - * busybox and buxybox-static now conflict/replace each other (closes: #80421) - - -- Erik Andersen Thu, 15 Mar 2001 14:45:00 -0700 - -busybox (0.49-1) unstable; urgency=low - - * Lots more source updates and bug fixes. See changelog for details. - - -- Erik Andersen Sat, 27 Jan 2001 01:45:53 -0700 - -busybox (0.48-1) unstable; urgency=low - - * Lots more source updates and bug fixes. See changelog for details. - * Now includes .udeb support for the debian-installer. The .udeb - probably needs some more work, but this should be a good start. - - -- Erik Andersen Wed, 13 Dec 2000 08:36:07 -0700 - -busybox (0.47-1) unstable; urgency=low - - * New version released. See changelog for details. - - -- Erik Andersen Mon, 25 Sep 2000 23:00:56 -0600 - -busybox (0.46-1) unstable; urgency=low - - * New version released. See changelog for details. - - -- Erik Andersen Tue, 11 Jul 2000 12:15:44 -0600 - -busybox (0.45-1) unstable; urgency=low - - * First attempt at packaging BusyBox as a .deb. This has been in - in the Debian boot-floppies CVS tree forever. Hopefully, having it as a - standalone app will make life easier for me, the debian-installer team, and - everyone else as well... - * I have created a busybox-static that can be used as a rescue shell when you - hose your system. Just invoke "busybox sh" to fir up the shell. This has - every app provided by busybox staically linked in. There have been several - times in the past that I would have loved to have this sitting on my system - (i.e. when libc gets screwed up.) - - -- Erik Andersen Tue, 27 Jun 2000 12:26:41 -0600 - diff --git a/busybox/debian/control b/busybox/debian/control deleted file mode 100644 index 3626718da..000000000 --- a/busybox/debian/control +++ /dev/null @@ -1,66 +0,0 @@ -Source: busybox -Priority: optional -Maintainer: Erik Andersen -Build-Depends: debhelper (>= 2.1.18), dpkg-dev (>= 1.7.0) -Standards-Version: 3.2.1.0 - -Package: busybox -Architecture: any -Depends: ${shlibs:Depends} -Conflicts: busybox-static -Replaces: busybox-static -Section: utils -Description: Tiny utilities for small and embedded systems. - BusyBox combines tiny versions of many common UNIX utilities into a single - small executable. It provides minimalist replacements for the most common - utilities you would usually find on your desktop system (i.e., ls, cp, mv, - mount, tar, etc.). The utilities in BusyBox generally have fewer options than - their full-featured GNU cousins; however, the options that are included - provide the expected functionality and behave very much like their GNU - counterparts. - . - This package installs the BusyBox binary but does not install symlinks - for any of the supported utilities. You can use /bin/busybox --install - to install BusyBox to the current directory (you do not want to do this - in / on your Debian system!). - -Package: busybox-static -Architecture: any -Depends: ${shlibs:Depends} -Conflicts: busybox -Replaces: busybox -Section: shells -Description: Standalone rescue shell with tons of builtin utilities. - BusyBox combines tiny versions of many common UNIX utilities into a single - small executable. It provides minimalist replacements for the most common - utilities you would usually find on your desktop system (i.e., ls, cp, mv, - mount, tar, etc.). The utilities in BusyBox generally have fewer options than - their full-featured GNU cousins; however, the options that are included - provide the expected functionality and behave very much like their GNU - counterparts. - . - BusyBox-static provides you with a statically linked simple stand alone shell - that provides all the utilities available in BusyBox. This package is - intended to be used as a rescue shell, in the event that you screw up your - system. Invoke "busybox sh" and you have a standalone shell ready to save - your system from certain destruction. Invoke "busybox", and it will list the - available builtin commands. - -Package: busybox-udeb -Architecture: any -Depends: ${shlibs:Depends} -Section: debian-installer -Priority: standard -Description: Tiny utilities for the debian-installer - BusyBox combines tiny versions of many common UNIX utilities into a single - small executable. It provides minimalist replacements for the most common - utilities you would usually find on your desktop system (i.e., ls, cp, mv, - mount, tar, etc.). The utilities in BusyBox generally have fewer options than - their full-featured GNU cousins; however, the options that are included - provide the expected functionality and behave very much like their GNU - counterparts. - . - busybox-udeb is used by the debian-installer, so unless you are working - on the debian-installer, this package is not for you. Installing this - on your Debian system is a very, very bad idea. You have been warned. - diff --git a/busybox/debian/copyright b/busybox/debian/copyright deleted file mode 100644 index 68a96e68b..000000000 --- a/busybox/debian/copyright +++ /dev/null @@ -1,7 +0,0 @@ -This package was debianized by Erik Andersen on -Sun, 18 Jun 2000 23:31:02 -0600 - -It was downloaded from ftp://ftp.lineo.com/pub/busybox -HomePage is at: http://busybox.lineo.com/ - -Copyright: GPL diff --git a/busybox/debian/rules b/busybox/debian/rules deleted file mode 100755 index 1d7413c35..000000000 --- a/busybox/debian/rules +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/make -f - -# This is a bit unusual, in that I have to completely recompile everything -# for each package I build (obviously static and dynamic builds require -# things to be recompiled...) - -# This is the debhelper compatability version to use. -#export DH_COMPAT=1 - -bbbd=debian/busybox_builddir -bb=debian/tmp -bbsbd=debian/busybox_static_builddir -bbs=debian/busybox-static -bbubd=debian/busybox_udeb_builddir -bbu=debian/busybox-udeb - -clean: - dh_testdir - dh_testroot - rm -f debian/build-stamp-busybox debian/build-stamp-busybox-static debian/build-stamp-busybox-udeb - -$(MAKE) clean - -rm -rf $(bb) $(bbbd) $(bbs) $(bbsbd) $(bbubd) $(bbu) - dh_clean - -build: debian/build-stamp-busybox -debian/build-stamp-busybox: - dh_testdir - mkdir -p $(bbbd) - cp Makefile $(bbbd) - cp debian/Config.h-deb $(bbbd)/Config.h - -(cd $(bbbd); $(MAKE) "BB_SRC_DIR=../../" applet_source_list) - (cd $(bbbd); $(MAKE) USE_SYSTEM_PWD_GRP=false "BB_SRC_DIR=../../") - touch debian/build-stamp-busybox - -install: build - dh_testdir - dh_testroot - dh_clean -k - dh_installdirs - # Do not run 'make install', since we do not want all the symlinks. - # This just installes the busybox binary... - #(cd $(bbbd); $(MAKE) "BB_SRC_DIR=../../" "PREFIX=../../$(bb)" install) - mkdir -p $(bb)/bin/ - cp $(bbbd)/busybox $(bb)/bin/busybox - mkdir -p $(bb)/usr/share/doc/busybox/busybox.lineo.com - cp $(bbbd)/docs/busybox.lineo.com/BusyBox.html $(bb)/usr/share/doc/busybox/busybox.lineo.com/ - mkdir -p $(bb)/usr/share/man/man1 - cp $(bbbd)/docs/BusyBox.1 $(bb)/usr/share/man/man1/busybox.1 - -# Now for the statically linked stuff -build-static: debian/build-stamp-busybox-static -debian/build-stamp-busybox-static: - dh_testdir - mkdir -p $(bbsbd) - cp Makefile $(bbsbd) - cp debian/Config.h-static $(bbsbd)/Config.h - (cd $(bbsbd); $(MAKE) DOSTATIC=true USE_SYSTEM_PWD_GRP=false "BB_SRC_DIR=../../") - touch debian/build-stamp-busybox-static - -install-static: build - dh_testdir - dh_testroot - dh_clean -k - dh_installdirs - # Do not run 'make install', since we do not want all the symlinks. - # This just installes the busybox binary... - #(cd $(bbsbd); $(MAKE) "BB_SRC_DIR=../../" "PREFIX=../../$(bbs)" install) - mkdir -p $(bbs)/bin/ - cp $(bbsbd)/busybox $(bbs)/bin/busybox - mkdir -p $(bbs)/usr/share/doc/busybox-static/busybox.lineo.com - cp $(bbsbd)/docs/busybox.lineo.com/BusyBox.html $(bbs)/usr/share/doc/busybox-static/busybox.lineo.com/ - mkdir -p $(bbs)/usr/share/man/man1/ - cp $(bbsbd)/docs/BusyBox.1 $(bbs)/usr/share/man/man1/busybox.1 - -half_clean: - dh_testdir - dh_testroot - rm -rf $(bbs) debian/build-stamp-busybox-static - -$(MAKE) clean - -do_static: half_clean build-static install-static - - - -# Now for the .udeb stuff -PACKAGE=busybox-udeb -VERSION=$(shell dpkg-parsechangelog | grep ^Version: | cut -d ' ' -f 2 | sed -e s/[0-9]://g) -ARCH=$(shell dpkg --print-architecture) -FILENAME=$(PACKAGE)_$(VERSION)_$(ARCH).udeb - -build-udeb: debian/build-stamp-busybox-udeb -debian/build-stamp-busybox-udeb: - dh_testdir - mkdir -p $(bbubd) - cp Makefile $(bbubd) - cp debian/Config.h-udeb $(bbubd)/Config.h - (cd $(bbubd); $(MAKE) USE_SYSTEM_PWD_GRP=false "BB_SRC_DIR=../../") - touch debian/build-stamp-busybox-udeb - -install-udeb: build - dh_testdir - dh_testroot - dh_clean -k - dh_installdirs - (cd $(bbubd); $(MAKE) "BB_SRC_DIR=../../" "PREFIX=../../$(bbu)" install) - mkdir -p $(bbu)/usr/share/man/man1/ - cp $(bbubd)/docs/BusyBox.1 $(bbu)/usr/share/man/man1/busybox.1 - -three_quarter_clean: - dh_testdir - dh_testroot - rm -rf $(bbu) debian/build-stamp-busybox-udeb - -$(MAKE) clean - -do_udeb: three_quarter_clean build-udeb install-udeb - - - -# Build architecture-independent files here. -binary-indep: -# We have nothing to do by default. - -# Build architecture-dependent files here. -binary-arch: busybox busybox-static busybox-udeb - -busybox: install - @echo "--- Building: $@" - dh_testdir - dh_testroot - dh_installdirs - dh_installdocs -p$@ $(bbbd)/docs/BusyBox.txt \ - $(bbbd)/docs/BusyBox.html docs/style-guide.txt \ - docs/busybox.lineo.com AUTHORS README TODO - rm -rf `find $(bb) -name CVS` - rm -f `find $(bb) -name .cvsignore` - dh_installchangelogs -p$@ Changelog - dh_undocumented -p$@ - dh_strip -p$@ - dh_compress -p$@ - dh_fixperms -p$@ - dh_installdeb -p$@ - dh_shlibdeps -p$@ - dh_gencontrol -p$@ - dh_md5sums -p$@ - dh_builddeb -p$@ - - -busybox-static: do_static - @echo "--- Building: $@" - dh_testdir - dh_testroot - dh_installdirs - dh_installdocs -p$@ $(bbsbd)/docs/BusyBox.txt \ - $(bbsbd)/docs/BusyBox.html docs/style-guide.txt \ - docs/busybox.lineo.com AUTHORS README TODO - rm -rf `find $(bbs) -name CVS` - rm -f `find $(bbs) -name .cvsignore` - dh_installchangelogs -p$@ Changelog - dh_undocumented -p$@ - dh_strip -p$@ - dh_compress -p$@ - dh_fixperms -p$@ - dh_installdeb -p$@ - dh_shlibdeps -p$@ - dh_gencontrol -p$@ - dh_md5sums -p$@ - dh_builddeb -p$@ - - -# Note that this builds a .udeb, which is not policy compliant or anything. -# -busybox-udeb: do_udeb - @echo "--- Building: $@" - dh_testdir - dh_testroot - dh_installdirs - dh_strip -p$@ - dh_compress -p$@ - dh_fixperms -p$@ - dh_installdeb -p$@ - dh_shlibdeps -p$@ - #Make _very_ sure there are no docs lurking about. - rm -rf $(bbu)/usr/share/man - #dh_gencontrol -p$@ - # Don't write your stupid guesses to debian/files. - dh_gencontrol -p$@ -- -fdebian/files~ - # Register file manually. - dpkg-distaddfile $(FILENAME) debian-installer standard - dh_md5sums -p$@ - dh_builddeb -p$@ --filename=$(FILENAME) - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install diff --git a/busybox/df.c b/busybox/df.c deleted file mode 100644 index 8cb13fa6d..000000000 --- a/busybox/df.c +++ /dev/null @@ -1,158 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini df implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -extern const char mtab_file[]; /* Defined in utility.c */ -#ifdef BB_FEATURE_HUMAN_READABLE -static unsigned long df_disp_hr = KILOBYTE; -#endif - -static int do_df(char *device, const char *mount_point) -{ - struct statfs s; - long blocks_used; - long blocks_percent_used; - - if (statfs(mount_point, &s) != 0) { - perror_msg("%s", mount_point); - return FALSE; - } - - if (s.f_blocks > 0) { - blocks_used = s.f_blocks - s.f_bfree; - if(blocks_used == 0) - blocks_percent_used = 0; - else { - blocks_percent_used = (long) - (blocks_used * 100.0 / (blocks_used + s.f_bavail) + 0.5); - } - if (strcmp(device, "/dev/root") == 0) { - /* Adjusts device to be the real root device, - * or leaves device alone if it can't find it */ - device = find_real_root_device_name(device); - if(device==NULL) - return FALSE; - } -#ifdef BB_FEATURE_HUMAN_READABLE - printf("%-20s %9s ", device, - make_human_readable_str(s.f_blocks, s.f_bsize, df_disp_hr)); - - printf("%9s ", - make_human_readable_str( (s.f_blocks - s.f_bfree), s.f_bsize, df_disp_hr)); - - printf("%9s %3ld%% %s\n", - make_human_readable_str(s.f_bavail, s.f_bsize, df_disp_hr), - blocks_percent_used, mount_point); -#else - printf("%-20s %9ld %9ld %9ld %3ld%% %s\n", - device, - (long) (s.f_blocks * (s.f_bsize / (double)KILOBYTE)), - (long) ((s.f_blocks - s.f_bfree)*(s.f_bsize/(double)KILOBYTE)), - (long) (s.f_bavail * (s.f_bsize / (double)KILOBYTE)), - blocks_percent_used, mount_point); -#endif - } - - return TRUE; -} - -extern int df_main(int argc, char **argv) -{ - int status = EXIT_SUCCESS; - int opt = 0; - int i = 0; - char disp_units_hdr[80] = "1k-blocks"; /* default display is kilobytes */ - - while ((opt = getopt(argc, argv, "k" -#ifdef BB_FEATURE_HUMAN_READABLE - "hm" -#endif -)) > 0) - { - switch (opt) { -#ifdef BB_FEATURE_HUMAN_READABLE - case 'h': - df_disp_hr = 0; - strcpy(disp_units_hdr, " Size"); - break; - case 'm': - df_disp_hr = MEGABYTE; - strcpy(disp_units_hdr, "1M-blocks"); - break; -#endif - case 'k': - /* default display is kilobytes */ - break; - default: - show_usage(); - } - } - - printf("%-20s %-14s %s %s %s %s\n", "Filesystem", disp_units_hdr, - "Used", "Available", "Use%", "Mounted on"); - - if(optind < argc) { - struct mntent *mount_entry; - for(i = optind; i < argc; i++) - { - if ((mount_entry = find_mount_point(argv[i], mtab_file)) == 0) { - error_msg("%s: can't find mount point.", argv[i]); - status = EXIT_FAILURE; - } else if (!do_df(mount_entry->mnt_fsname, mount_entry->mnt_dir)) - status = EXIT_FAILURE; - } - } else { - FILE *mount_table; - struct mntent *mount_entry; - - mount_table = setmntent(mtab_file, "r"); - if (mount_table == 0) { - perror_msg("%s", mtab_file); - return EXIT_FAILURE; - } - - while ((mount_entry = getmntent(mount_table))) { - if (!do_df(mount_entry->mnt_fsname, mount_entry->mnt_dir)) - status = EXIT_FAILURE; - } - endmntent(mount_table); - } - - return status; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/dirname.c b/busybox/dirname.c deleted file mode 100644 index b534e6950..000000000 --- a/busybox/dirname.c +++ /dev/null @@ -1,40 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini dirname implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -/* getopt not needed */ - -#include -#include -#include -#include "busybox.h" - -extern int dirname_main(int argc, char **argv) -{ - if ((argc < 2) || (**(argv + 1) == '-')) - show_usage(); - argv++; - - puts (dirname (argv[0])); - - return EXIT_SUCCESS; -} diff --git a/busybox/dmesg.c b/busybox/dmesg.c deleted file mode 100644 index 73de6d1ae..000000000 --- a/busybox/dmesg.c +++ /dev/null @@ -1,95 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* dmesg.c -- Print out the contents of the kernel ring buffer - * Created: Sat Oct 9 16:19:47 1993 - * Revised: Thu Oct 28 21:52:17 1993 by faith@cs.unc.edu - * Copyright 1993 Theodore Ts'o (tytso@athena.mit.edu) - * This program comes with ABSOLUTELY NO WARRANTY. - * Modifications by Rick Sladkey (jrs@world.std.com) - * Larger buffersize 3 June 1998 by Nicolai Langfeldt, based on a patch - * by Peeter Joot. This was also suggested by John Hudson. - * 1999-02-22 Arkadiusz Mi¶kiewicz - * - added Native Language Support - * - * from util-linux -- adapted for busybox by - * Erik Andersen . I ripped out Native Language - * Support, replaced getopt, added some gotos for redundant stuff. - */ - -#include -#include -#include - -#if __GNU_LIBRARY__ < 5 -# ifdef __alpha__ -# define klogctl syslog -# endif -#else -# include -#endif - -#include "busybox.h" - -int dmesg_main(int argc, char **argv) -{ - char *buf; - int c; - int bufsize = 8196; - int i; - int n; - int level = 0; - int lastc; - int cmd = 3; - - while ((c = getopt(argc, argv, "cn:s:")) != EOF) { - switch (c) { - case 'c': - cmd = 4; - break; - case 'n': - cmd = 8; - if (optarg == NULL) - show_usage(); - level = atoi(optarg); - break; - case 's': - if (optarg == NULL) - show_usage(); - bufsize = atoi(optarg); - break; - default: - show_usage(); - } - } - - if (optind < argc) { - show_usage(); - } - - if (cmd == 8) { - if (klogctl(cmd, NULL, level) < 0) - perror_msg_and_die("klogctl"); - return EXIT_SUCCESS; - } - - if (bufsize < 4096) - bufsize = 4096; - buf = (char *) xmalloc(bufsize); - if ((n = klogctl(cmd, buf, bufsize)) < 0) - perror_msg_and_die("klogctl"); - - lastc = '\n'; - for (i = 0; i < n; i++) { - if (lastc == '\n' && buf[i] == '<') { - i++; - while (buf[i] >= '0' && buf[i] <= '9') - i++; - if (buf[i] == '>') - i++; - } - lastc = buf[i]; - putchar(lastc); - } - if (lastc != '\n') - putchar('\n'); - return EXIT_SUCCESS; -} diff --git a/busybox/docs/.cvsignore b/busybox/docs/.cvsignore deleted file mode 100644 index ec9e94b27..000000000 --- a/busybox/docs/.cvsignore +++ /dev/null @@ -1,8 +0,0 @@ -BusyBox.txt -BusyBox.1 -BusyBox.html -busybox.txt -busybox.ps -busybox.pdf -busybox -busybox.pod diff --git a/busybox/docs/autodocifier.pl b/busybox/docs/autodocifier.pl deleted file mode 100755 index d753300c1..000000000 --- a/busybox/docs/autodocifier.pl +++ /dev/null @@ -1,287 +0,0 @@ -#!/usr/bin/perl -w - -use strict; -use Getopt::Long; - -# collect lines continued with a '\' into an array -sub continuation { - my $fh = shift; - my @line; - - while (<$fh>) { - my $s = $_; - $s =~ s/\\\s*$//; - #$s =~ s/#.*$//; - push @line, $s; - last unless (/\\\s*$/); - } - return @line; -} - -# regex && eval away unwanted strings from documentation -sub beautify { - my $text = shift; - $text =~ s/USAGE_NOT\w+\(.*?"\s*\)//sxg; - $text =~ s/USAGE_\w+\(\s*?(.*?)"\s*\)/$1"/sxg; - $text =~ s/"\s*"//sg; - my @line = split("\n", $text); - $text = join('', - map { - s/^\s*"//; - s/"\s*$//; - s/%/%%/g; - s/\$/\\\$/g; - eval qq[ sprintf(qq{$_}) ] - } @line - ); - return $text; -} - -# generate POD for an applet -sub pod_for_usage { - my $name = shift; - my $usage = shift; - - # make options bold - my $trivial = $usage->{trivial}; - $trivial =~ s/(?/sxg; - my @f0 = - map { $_ !~ /^\s/ && s/(?/g; $_ } - split("\n", $usage->{full}); - - # add "\n" prior to certain lines to make indented - # lines look right - my @f1; - my $len = @f0; - for (my $i = 0; $i < $len; $i++) { - push @f1, $f0[$i]; - if (($i+1) != $len && $f0[$i] !~ /^\s/ && $f0[$i+1] =~ /^\s/) { - next if ($f0[$i] =~ /^$/); - push(@f1, "") unless ($f0[$i+1] =~ /^\s*$/s); - } - } - my $full = join("\n", @f1); - - # prepare notes if they exist - my $notes = (defined $usage->{notes}) - ? "$usage->{notes}\n\n" - : ""; - - # prepare examples if they exist - my $example = (defined $usage->{example}) - ? - "Example:\n\n" . - join ("\n", - map { "\t$_" } - split("\n", $usage->{example})) . "\n\n" - : ""; - - return - "=item B<$name>". - "\n\n" . - "$name $trivial". - "\n\n" . - $full . - "\n\n" . - $notes . - $example. - "-------------------------------". - "\n\n" - ; -} - -# FIXME | generate SGML for an applet -sub sgml_for_usage { - my $name = shift; - my $usage = shift; - return - "\n". - " $name\n". - "\n" - ; -} - -# the keys are applet names, and -# the values will contain hashrefs of the form: -# -# { -# trivial => "...", -# full => "...", -# notes => "...", -# example => "...", -# } -my %docs; - - -# get command-line options - -my %opt; - -GetOptions( - \%opt, - "help|h", - "sgml|s", - "pod|p", - "verbose|v", -); - -if (defined $opt{help}) { - print - "$0 [OPTION]... [FILE]...\n", - "\t--help\n", - "\t--sgml\n", - "\t--pod\n", - "\t--verbose\n", - ; - exit 1; -} - - -# collect documenation into %docs - -foreach (@ARGV) { - open(USAGE, $_) || die("$0: $_: $!"); - my $fh = *USAGE; - my ($applet, $type, @line); - while (<$fh>) { - if (/^#define (\w+)_(\w+)_usage/) { - $applet = $1; - $type = $2; - @line = continuation($fh); - my $doc = $docs{$applet} ||= { }; - my $text = join("\n", @line); - $doc->{$type} = beautify($text); - } - } -} - - -# generate structured documentation - -my $generator = \&pod_for_usage; -if (defined $opt{sgml}) { - $generator = \&sgml_for_usage; -} - -foreach my $applet (sort keys %docs) { - print $generator->($applet, $docs{$applet}); -} - -exit 0; - -__END__ - -=head1 NAME - -autodocifier.pl - generate docs for busybox based on usage.h - -=head1 SYNOPSIS - -autodocifier.pl [OPTION]... [FILE]... - -Example: - - ( cat docs/busybox_header.pod; \ - docs/autodocifier.pl usage.h; \ - cat docs/busybox_footer.pod ) > docs/busybox.pod - -=head1 DESCRIPTION - -The purpose of this script is to automagically generate documentation -for busybox using its usage.h as the original source for content. -Currently, the same content has to be duplicated in 3 places in -slightly different formats -- F, F, and -F. This is tedious, so Perl has come to the rescue. - -This script was based on a script by Erik Andersen -which was in turn based on a script by Mark Whitley - -=head1 OPTIONS - -=over 4 - -=item B<--help> - -This displays the help message. - -=item B<--pod> - -Generate POD (this is the default) - -=item B<--sgml> - -Generate SGML - -=item B<--verbose> - -Be verbose (not implemented) - -=back - -=head1 FORMAT - -The following is an example of some data this script might parse. - - #define length_trivial_usage \ - "STRING" - #define length_full_usage \ - "Prints out the length of the specified STRING." - #define length_example_usage \ - "$ length Hello\n" \ - "5\n" - -Each entry is a cpp macro that defines a string. The macros are -named systematically in the form: - - $name_$type_usage - -$name is the name of the applet. $type can be "trivial", "full", "notes", -or "example". Every documentation macro must end with "_usage". - -The definition of the types is as follows: - -=over 4 - -=item B - -This should be a brief, one-line description of parameters that -the command expects. This will be displayed when B<-h> is issued to -a command. I - -=item B - -This should contain descriptions of each option. This will also -be displayed along with the trivial help if BB_FEATURE_TRIVIAL_HELP -is disabled. I - -=item B - -This is documentation that is intended to go in the POD or SGML, but -not be printed when a B<-h> is given to a command. To see an example -of notes being used, see init_notes_usage. I - -=item B - -This should be an example of how the command is acutally used. -This will not be printed when a B<-h> is given to a command -- it -is inteded only for the POD or SGML documentation. I - -=back - -=head1 FILES - -F - -=head1 COPYRIGHT - -Copyright (c) 2001 John BEPPU. All rights reserved. This program is -free software; you can redistribute it and/or modify it under the same -terms as Perl itself. - -=head1 AUTHOR - -John BEPPU - -=cut - -# $Id: autodocifier.pl,v 1.21 2001/04/17 17:09:34 beppu Exp $ diff --git a/busybox/docs/busybox.net/.cvsignore b/busybox/docs/busybox.net/.cvsignore deleted file mode 100644 index 88825af14..000000000 --- a/busybox/docs/busybox.net/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -BusyBox.html diff --git a/busybox/docs/busybox.net/busybox-growth.ps b/busybox/docs/busybox.net/busybox-growth.ps deleted file mode 100644 index 123f38114..000000000 --- a/busybox/docs/busybox.net/busybox-growth.ps +++ /dev/null @@ -1,404 +0,0 @@ -%!PS-Adobe-2.0 -%%Title: busybox-growth.ps -%%Creator: gnuplot 3.5 (pre 3.6) patchlevel beta 347 -%%CreationDate: Tue Apr 10 14:03:36 2001 -%%DocumentFonts: (atend) -%%BoundingBox: 50 40 554 770 -%%Orientation: Landscape -%%Pages: (atend) -%%EndComments -/gnudict 120 dict def -gnudict begin -/Color true def -/Solid true def -/gnulinewidth 5.000 def -/userlinewidth gnulinewidth def -/vshift -46 def -/dl {10 mul} def -/hpt_ 31.5 def -/vpt_ 31.5 def -/hpt hpt_ def -/vpt vpt_ def -/M {moveto} bind def -/L {lineto} bind def -/R {rmoveto} bind def -/V {rlineto} bind def -/vpt2 vpt 2 mul def -/hpt2 hpt 2 mul def -/Lshow { currentpoint stroke M - 0 vshift R show } def -/Rshow { currentpoint stroke M - dup stringwidth pop neg vshift R show } def -/Cshow { currentpoint stroke M - dup stringwidth pop -2 div vshift R show } def -/UP { dup vpt_ mul /vpt exch def hpt_ mul /hpt exch def - /hpt2 hpt 2 mul def /vpt2 vpt 2 mul def } def -/DL { Color {setrgbcolor Solid {pop []} if 0 setdash } - {pop pop pop Solid {pop []} if 0 setdash} ifelse } def -/BL { stroke gnulinewidth 2 mul setlinewidth } def -/AL { stroke gnulinewidth 2 div setlinewidth } def -/UL { gnulinewidth mul /userlinewidth exch def } def -/PL { stroke userlinewidth setlinewidth } def -/LTb { BL [] 0 0 0 DL } def -/LTa { AL [1 dl 2 dl] 0 setdash 0 0 0 setrgbcolor } def -/LT0 { PL [] 1 0 0 DL } def -/LT1 { PL [4 dl 2 dl] 0 1 0 DL } def -/LT2 { PL [2 dl 3 dl] 0 0 1 DL } def -/LT3 { PL [1 dl 1.5 dl] 1 0 1 DL } def -/LT4 { PL [5 dl 2 dl 1 dl 2 dl] 0 1 1 DL } def -/LT5 { PL [4 dl 3 dl 1 dl 3 dl] 1 1 0 DL } def -/LT6 { PL [2 dl 2 dl 2 dl 4 dl] 0 0 0 DL } def -/LT7 { PL [2 dl 2 dl 2 dl 2 dl 2 dl 4 dl] 1 0.3 0 DL } def -/LT8 { PL [2 dl 2 dl 2 dl 2 dl 2 dl 2 dl 2 dl 4 dl] 0.5 0.5 0.5 DL } def -/Pnt { stroke [] 0 setdash - gsave 1 setlinecap M 0 0 V stroke grestore } def -/Dia { stroke [] 0 setdash 2 copy vpt add M - hpt neg vpt neg V hpt vpt neg V - hpt vpt V hpt neg vpt V closepath stroke - Pnt } def -/Pls { stroke [] 0 setdash vpt sub M 0 vpt2 V - currentpoint stroke M - hpt neg vpt neg R hpt2 0 V stroke - } def -/Box { stroke [] 0 setdash 2 copy exch hpt sub exch vpt add M - 0 vpt2 neg V hpt2 0 V 0 vpt2 V - hpt2 neg 0 V closepath stroke - Pnt } def -/Crs { stroke [] 0 setdash exch hpt sub exch vpt add M - hpt2 vpt2 neg V currentpoint stroke M - hpt2 neg 0 R hpt2 vpt2 V stroke } def -/TriU { stroke [] 0 setdash 2 copy vpt 1.12 mul add M - hpt neg vpt -1.62 mul V - hpt 2 mul 0 V - hpt neg vpt 1.62 mul V closepath stroke - Pnt } def -/Star { 2 copy Pls Crs } def -/BoxF { stroke [] 0 setdash exch hpt sub exch vpt add M - 0 vpt2 neg V hpt2 0 V 0 vpt2 V - hpt2 neg 0 V closepath fill } def -/TriUF { stroke [] 0 setdash vpt 1.12 mul add M - hpt neg vpt -1.62 mul V - hpt 2 mul 0 V - hpt neg vpt 1.62 mul V closepath fill } def -/TriD { stroke [] 0 setdash 2 copy vpt 1.12 mul sub M - hpt neg vpt 1.62 mul V - hpt 2 mul 0 V - hpt neg vpt -1.62 mul V closepath stroke - Pnt } def -/TriDF { stroke [] 0 setdash vpt 1.12 mul sub M - hpt neg vpt 1.62 mul V - hpt 2 mul 0 V - hpt neg vpt -1.62 mul V closepath fill} def -/DiaF { stroke [] 0 setdash vpt add M - hpt neg vpt neg V hpt vpt neg V - hpt vpt V hpt neg vpt V closepath fill } def -/Pent { stroke [] 0 setdash 2 copy gsave - translate 0 hpt M 4 {72 rotate 0 hpt L} repeat - closepath stroke grestore Pnt } def -/PentF { stroke [] 0 setdash gsave - translate 0 hpt M 4 {72 rotate 0 hpt L} repeat - closepath fill grestore } def -/Circle { stroke [] 0 setdash 2 copy - hpt 0 360 arc stroke Pnt } def -/CircleF { stroke [] 0 setdash hpt 0 360 arc fill } def -/C0 { BL [] 0 setdash 2 copy moveto vpt 90 450 arc } bind def -/C1 { BL [] 0 setdash 2 copy moveto - 2 copy vpt 0 90 arc closepath fill - vpt 0 360 arc closepath } bind def -/C2 { BL [] 0 setdash 2 copy moveto - 2 copy vpt 90 180 arc closepath fill - vpt 0 360 arc closepath } bind def -/C3 { BL [] 0 setdash 2 copy moveto - 2 copy vpt 0 180 arc closepath fill - vpt 0 360 arc closepath } bind def -/C4 { BL [] 0 setdash 2 copy moveto - 2 copy vpt 180 270 arc closepath fill - vpt 0 360 arc closepath } bind def -/C5 { BL [] 0 setdash 2 copy moveto - 2 copy vpt 0 90 arc - 2 copy moveto - 2 copy vpt 180 270 arc closepath fill - vpt 0 360 arc } bind def -/C6 { BL [] 0 setdash 2 copy moveto - 2 copy vpt 90 270 arc closepath fill - vpt 0 360 arc closepath } bind def -/C7 { BL [] 0 setdash 2 copy moveto - 2 copy vpt 0 270 arc closepath fill - vpt 0 360 arc closepath } bind def -/C8 { BL [] 0 setdash 2 copy moveto - 2 copy vpt 270 360 arc closepath fill - vpt 0 360 arc closepath } bind def -/C9 { BL [] 0 setdash 2 copy moveto - 2 copy vpt 270 450 arc closepath fill - vpt 0 360 arc closepath } bind def -/C10 { BL [] 0 setdash 2 copy 2 copy moveto vpt 270 360 arc closepath fill - 2 copy moveto - 2 copy vpt 90 180 arc closepath fill - vpt 0 360 arc closepath } bind def -/C11 { BL [] 0 setdash 2 copy moveto - 2 copy vpt 0 180 arc closepath fill - 2 copy moveto - 2 copy vpt 270 360 arc closepath fill - vpt 0 360 arc closepath } bind def -/C12 { BL [] 0 setdash 2 copy moveto - 2 copy vpt 180 360 arc closepath fill - vpt 0 360 arc closepath } bind def -/C13 { BL [] 0 setdash 2 copy moveto - 2 copy vpt 0 90 arc closepath fill - 2 copy moveto - 2 copy vpt 180 360 arc closepath fill - vpt 0 360 arc closepath } bind def -/C14 { BL [] 0 setdash 2 copy moveto - 2 copy vpt 90 360 arc closepath fill - vpt 0 360 arc } bind def -/C15 { BL [] 0 setdash 2 copy vpt 0 360 arc closepath fill - vpt 0 360 arc closepath } bind def -/Rec { newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto - neg 0 rlineto closepath } bind def -/Square { dup Rec } bind def -/Bsquare { vpt sub exch vpt sub exch vpt2 Square } bind def -/S0 { BL [] 0 setdash 2 copy moveto 0 vpt rlineto BL Bsquare } bind def -/S1 { BL [] 0 setdash 2 copy vpt Square fill Bsquare } bind def -/S2 { BL [] 0 setdash 2 copy exch vpt sub exch vpt Square fill Bsquare } bind def -/S3 { BL [] 0 setdash 2 copy exch vpt sub exch vpt2 vpt Rec fill Bsquare } bind def -/S4 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt Square fill Bsquare } bind def -/S5 { BL [] 0 setdash 2 copy 2 copy vpt Square fill - exch vpt sub exch vpt sub vpt Square fill Bsquare } bind def -/S6 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt vpt2 Rec fill Bsquare } bind def -/S7 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt vpt2 Rec fill - 2 copy vpt Square fill - Bsquare } bind def -/S8 { BL [] 0 setdash 2 copy vpt sub vpt Square fill Bsquare } bind def -/S9 { BL [] 0 setdash 2 copy vpt sub vpt vpt2 Rec fill Bsquare } bind def -/S10 { BL [] 0 setdash 2 copy vpt sub vpt Square fill 2 copy exch vpt sub exch vpt Square fill - Bsquare } bind def -/S11 { BL [] 0 setdash 2 copy vpt sub vpt Square fill 2 copy exch vpt sub exch vpt2 vpt Rec fill - Bsquare } bind def -/S12 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt2 vpt Rec fill Bsquare } bind def -/S13 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt2 vpt Rec fill - 2 copy vpt Square fill Bsquare } bind def -/S14 { BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt2 vpt Rec fill - 2 copy exch vpt sub exch vpt Square fill Bsquare } bind def -/S15 { BL [] 0 setdash 2 copy Bsquare fill Bsquare } bind def -/D0 { gsave translate 45 rotate 0 0 S0 stroke grestore } bind def -/D1 { gsave translate 45 rotate 0 0 S1 stroke grestore } bind def -/D2 { gsave translate 45 rotate 0 0 S2 stroke grestore } bind def -/D3 { gsave translate 45 rotate 0 0 S3 stroke grestore } bind def -/D4 { gsave translate 45 rotate 0 0 S4 stroke grestore } bind def -/D5 { gsave translate 45 rotate 0 0 S5 stroke grestore } bind def -/D6 { gsave translate 45 rotate 0 0 S6 stroke grestore } bind def -/D7 { gsave translate 45 rotate 0 0 S7 stroke grestore } bind def -/D8 { gsave translate 45 rotate 0 0 S8 stroke grestore } bind def -/D9 { gsave translate 45 rotate 0 0 S9 stroke grestore } bind def -/D10 { gsave translate 45 rotate 0 0 S10 stroke grestore } bind def -/D11 { gsave translate 45 rotate 0 0 S11 stroke grestore } bind def -/D12 { gsave translate 45 rotate 0 0 S12 stroke grestore } bind def -/D13 { gsave translate 45 rotate 0 0 S13 stroke grestore } bind def -/D14 { gsave translate 45 rotate 0 0 S14 stroke grestore } bind def -/D15 { gsave translate 45 rotate 0 0 S15 stroke grestore } bind def -/DiaE { stroke [] 0 setdash vpt add M - hpt neg vpt neg V hpt vpt neg V - hpt vpt V hpt neg vpt V closepath stroke } def -/BoxE { stroke [] 0 setdash exch hpt sub exch vpt add M - 0 vpt2 neg V hpt2 0 V 0 vpt2 V - hpt2 neg 0 V closepath stroke } def -/TriUE { stroke [] 0 setdash vpt 1.12 mul add M - hpt neg vpt -1.62 mul V - hpt 2 mul 0 V - hpt neg vpt 1.62 mul V closepath stroke } def -/TriDE { stroke [] 0 setdash vpt 1.12 mul sub M - hpt neg vpt 1.62 mul V - hpt 2 mul 0 V - hpt neg vpt -1.62 mul V closepath stroke } def -/PentE { stroke [] 0 setdash gsave - translate 0 hpt M 4 {72 rotate 0 hpt L} repeat - closepath stroke grestore } def -/CircE { stroke [] 0 setdash - hpt 0 360 arc stroke } def -/Opaque { gsave closepath 1 setgray fill grestore 0 setgray closepath } def -/DiaW { stroke [] 0 setdash vpt add M - hpt neg vpt neg V hpt vpt neg V - hpt vpt V hpt neg vpt V Opaque stroke } def -/BoxW { stroke [] 0 setdash exch hpt sub exch vpt add M - 0 vpt2 neg V hpt2 0 V 0 vpt2 V - hpt2 neg 0 V Opaque stroke } def -/TriUW { stroke [] 0 setdash vpt 1.12 mul add M - hpt neg vpt -1.62 mul V - hpt 2 mul 0 V - hpt neg vpt 1.62 mul V Opaque stroke } def -/TriDW { stroke [] 0 setdash vpt 1.12 mul sub M - hpt neg vpt 1.62 mul V - hpt 2 mul 0 V - hpt neg vpt -1.62 mul V Opaque stroke } def -/PentW { stroke [] 0 setdash gsave - translate 0 hpt M 4 {72 rotate 0 hpt L} repeat - Opaque stroke grestore } def -/CircW { stroke [] 0 setdash - hpt 0 360 arc Opaque stroke } def -/BoxFill { gsave Rec 1 setgray fill grestore } def -end -%%EndProlog -%%Page: 1 1 -gnudict begin -gsave -50 50 translate -0.100 0.100 scale -90 rotate -0 -5040 translate -0 setgray -newpath -(Helvetica) findfont 140 scalefont setfont -1.000 UL -LTb -560 420 M -63 0 V -6409 0 R --63 0 V -476 420 M -(0) Rshow -560 1056 M -63 0 V -6409 0 R --63 0 V --6493 0 R -(100) Rshow -560 1692 M -63 0 V -6409 0 R --63 0 V --6493 0 R -(200) Rshow -560 2328 M -63 0 V -6409 0 R --63 0 V --6493 0 R -(300) Rshow -560 2964 M -63 0 V -6409 0 R --63 0 V --6493 0 R -(400) Rshow -560 3600 M -63 0 V -6409 0 R --63 0 V --6493 0 R -(500) Rshow -560 4236 M -63 0 V -6409 0 R --63 0 V --6493 0 R -(600) Rshow -560 4872 M -63 0 V -6409 0 R --63 0 V --6493 0 R -(700) Rshow -1531 420 M -0 63 V -0 4389 R -0 -63 V -0 -4529 R -(400) Cshow -2825 420 M -0 63 V -0 4389 R -0 -63 V -0 -4529 R -(600) Cshow -4120 420 M -0 63 V -0 4389 R -0 -63 V -0 -4529 R -(800) Cshow -5414 420 M -0 63 V -0 4389 R -0 -63 V -0 -4529 R -(1000) Cshow -6708 420 M -0 63 V -0 4389 R -0 -63 V -0 -4529 R -(1200) Cshow -1.000 UL -LTb -560 420 M -6472 0 V -0 4452 V --6472 0 V -560 420 L -0 2646 M -currentpoint gsave translate 90 rotate 0 0 M -(tar.gz size \(Kb\)) Cshow -grestore -3796 140 M -(time \(days since Jan 1, 1998\)) Cshow -1.000 UL -LT0 -696 420 M -0 593 V -1255 0 V -0 15 V -214 0 V -0 6 V -958 0 V -0 1 V --84 0 V -0 37 V -168 0 V -0 262 V -13 0 V -0 56 V -91 0 V -0 33 V -6 0 V -0 1 V -19 0 V -0 11 V -20 0 V -0 13 V -32 0 V -0 104 V -52 0 V -0 27 V -65 0 V -0 15 V -39 0 V -0 126 V -174 0 V -0 103 V -52 0 V -0 49 V -175 0 V -0 56 V -433 0 V -0 661 V -415 0 V -0 857 V -123 0 V -0 -291 V -498 0 V -0 208 V -505 0 V -0 66 V -291 0 V -0 115 V -311 0 V -0 449 V -162 0 V -0 309 V -stroke -grestore -end -showpage -%%Trailer -%%DocumentFonts: Helvetica -%%Pages: 1 diff --git a/busybox/docs/busybox.net/images/busybox.jpeg b/busybox/docs/busybox.net/images/busybox.jpeg deleted file mode 100644 index 37edc9614..000000000 Binary files a/busybox/docs/busybox.net/images/busybox.jpeg and /dev/null differ diff --git a/busybox/docs/busybox.net/images/busybox2.jpg b/busybox/docs/busybox.net/images/busybox2.jpg deleted file mode 100644 index abf8f0610..000000000 Binary files a/busybox/docs/busybox.net/images/busybox2.jpg and /dev/null differ diff --git a/busybox/docs/busybox.net/images/fm.mini.png b/busybox/docs/busybox.net/images/fm.mini.png deleted file mode 100644 index c0883cd34..000000000 Binary files a/busybox/docs/busybox.net/images/fm.mini.png and /dev/null differ diff --git a/busybox/docs/busybox.net/images/gfx_by_gimp.png b/busybox/docs/busybox.net/images/gfx_by_gimp.png deleted file mode 100644 index d58314034..000000000 Binary files a/busybox/docs/busybox.net/images/gfx_by_gimp.png and /dev/null differ diff --git a/busybox/docs/busybox.net/images/ltbutton2.png b/busybox/docs/busybox.net/images/ltbutton2.png deleted file mode 100644 index 556f72a6c..000000000 Binary files a/busybox/docs/busybox.net/images/ltbutton2.png and /dev/null differ diff --git a/busybox/docs/busybox.net/images/sdsmall.png b/busybox/docs/busybox.net/images/sdsmall.png deleted file mode 100644 index b1024501b..000000000 Binary files a/busybox/docs/busybox.net/images/sdsmall.png and /dev/null differ diff --git a/busybox/docs/busybox.net/images/written.in.vi.png b/busybox/docs/busybox.net/images/written.in.vi.png deleted file mode 100644 index 84f59bc15..000000000 Binary files a/busybox/docs/busybox.net/images/written.in.vi.png and /dev/null differ diff --git a/busybox/docs/busybox.net/index.html b/busybox/docs/busybox.net/index.html deleted file mode 100644 index e606238d4..000000000 --- a/busybox/docs/busybox.net/index.html +++ /dev/null @@ -1,394 +0,0 @@ - - - - -BusyBox - - - - - - - -
- - - - -
- - B u s y B o x - -
- BusyBox
- - - - - - - - - - - - - -
- - The Swiss Army Knife of Embedded Linux - -
- -BusyBox combines tiny versions of many common UNIX utilities into a single -small executable. It provides minimalist replacements for most of the utilities -you usually find in fileutils, shellutils, findutils, textutils, grep, gzip, -tar, etc. BusyBox provides a fairly complete POSIX environment for any small or -embedded system. The utilities in BusyBox generally have fewer options than -their full featured GNU cousins; however, the options that are included provide -the expected functionality and behave very much like their GNU counterparts. -

-BusyBox has been written with size-optimization and limited resources in mind. -It is also extremely modular so you can easily include or exclude commands (or -features) at compile time. This makes it easy to customize your embedded -systems. To create a working system, just add /dev, /etc, and a kernel. -

- -BusyBox is now maintained by - -Erik Andersen, and its ongoing development is being sponsored by -Lineo. -

-BusyBox is licensed under the -GNU GENERAL PUBLIC LICENSE. -

- - -

Screenshot

- -

Because everybody loves screenshots, a screenshot of BusyBox -is now available right here. - - -

Mailing List Information

-BusyBox now has a mailing list! -To subscribe, go and visit this page. - - - -
- - - Latest News - - -
- -
    - -
  • 23 August 2001 -- BusyBox 0.60.1 released -
    - - This is a relatively minor bug fixing release that fixes - up the bugs that have shown up in the stable release in - the last few weeks. Fortunately, nothing too - serious has shown up. This release only fixes bugs -- no - new features, no new applets. So without further ado, - here it is. Come and get it. -

    - The - changelog has all - the details. As usual BusyBox 0.60.1 can be downloaded from - ftp://oss.lineo.com/busybox. -

    Have Fun! -

    - - -

  • 2 August 2001 -- BusyBox 0.60.0 released -
    - I am very pleased to announce the immediate availability of - BusyBox 0.60.0. I have personally tested this release with libc5, glibc, - and uClibc on - x86, ARM, and powerpc using linux 2.2 and 2.4, and I know a number - of people using it on everything from ia64 to m68k with great success. - Everything seems to be working very nicely now, so getting a nice - stable bug-free(tm) release out seems to be in order. This releases fixes - a memory leak in syslogd, a number of bugs in the ash and msh shells, and - cleans up a number of things. - -

    - - Those wanting an easy way to test the 0.60.0 release with uClibc can - use User-Mode Linux - to give it a try by downloading and compiling - buildroot.tar.gz. - You don't have to be root or reboot your machine to run test this way. - Preconfigured User-Mode Linux kernel source is also on oss.lineo.com. -

    - Another cool thing is the nifty - BusyBox Tutorial contributed by K Computing. This requires - a ShockWave plugin (or standalone viewer), so you may want to grab the - the GPLed shockwave viewer from here - to view the tutorial. -

    - - Finally, In case you didn't notice anything odd about the - version number of this release, let me point out that this release - is not 0.53, because I bumped the version number up a - bit. This reflects the fact that this release is intended to form - a new stable BusyBox release series. If you need to rely on a - stable version of BusyBox, you should plan on using the stable - 0.60.x series. If bugs show up then I will release 0.60.1, then - 0.60.2, etc... This is also intended to deal with the fact that - the BusyBox build system will be getting a major overhaul for the - next release and I don't want that to break products that people - are shipping. To avoid that, the new build system will be - released as part of a new BusyBox development series that will - have some not-yet-decided-on odd version number. Once things - stabilize and the new build system is working for everyone, then - I will release that as a new stable release series. - -

    - The - changelog has all - the details. As usual BusyBox 0.60.0 can be downloaded from - ftp://oss.lineo.com/busybox. -

    Have Fun! -

    - - -

  • 7 July 2001 -- BusyBox 0.52 released -
    - - I am very pleased to announce the immediate availability of - BusyBox 0.52 (the "new-and-improved rock-solid release"). This - release is the result of many hours of work and has tons - of bugfixes, optimizations, and cleanups. This release adds - several new applets, including several new shells (such as hush, msh, - and ash). - -

    - The - changelog covers - some of the more obvious details, but there are many many things that - are not mentioned, but have been improved in subtle ways. As usual, - BusyBox 0.52 can be downloaded from - ftp://oss.lineo.com/busybox. -

    Have Fun! -

    - - -

  • 10 April 2001 - Graph of Busybox Growth -
    - The illustrious Larry Doolittle has made a PostScript chart of the growth - of the Busybox tarball size over time. It is available for downloading / - viewing right here. - -

    (Note that while the number of applets in Busybox has increased, you - can still configure Busybox to be as small as you want by selectively - turning off whichever applets you don't need.) -

    - - - -

  • Old News -
    - For the old news, visit the old news page. -
- - - - -
- - Download - -
-
    - -
  • Source for the latest release can always be downloaded from - ftp://oss.lineo.com/busybox. - -
  • A new snapshot of the source is made daily and is available as a GNU - gzipped tarball right here. - -
  • BusyBox now has its own publically browsable - CVS tree, - anonymous - CVS access, and - for those that are actively contributing there is even - CVS write access. - -
- - - - -
- - Documentation - -
-Current documentation for BusyBox includes: -
    -
  • BusyBox.html. - This is a list of the all the available commands in BusyBox with - complete usage information and examples of how to use each app. I - have spent a lot of time updating these docs and trying to - make them fairly comprehensive. If you find any errors (factual, - grammatical, whatever) please let me know. -
  • README. - This is the README file included in the busybox source release. -
  • BusyBox Bugs. - Need to report a bug? Need to check if a bug has been filed? -
  • If you need more help, the BusyBox - mailing list is - a good place to start. -
- - - - -
- - - Important Links - - -
- - - - - - -
- - Products/Projects Using BusyBox - -
- -

I know of the following products and/or projects that use BusyBox -- -listed in the order I happen to add them to the web page: - -

- -

Do you use BusyBox? I'd love to know about it and I'd be happy to link to -you. - - - - - -

- - - - -
- - - - - - - - - - - - - - - -
- - Mail all comments, insults, suggestions and bribes to - Erik Andersen
- The Busybox logo is copyright 1999,2000,2001, Erik Andersen. -
-
- This site created with the vi editor - - Graphics by GIMP - - Linux Today - -

Slashdot -

- Freshmeat -
- - -
- - - diff --git a/busybox/docs/busybox.net/oldnews.html b/busybox/docs/busybox.net/oldnews.html deleted file mode 100644 index d97bb2684..000000000 --- a/busybox/docs/busybox.net/oldnews.html +++ /dev/null @@ -1,465 +0,0 @@ - - - - -BusyBox - - - - - - - -
- - - - -
- - B u s y B o x - -
- BusyBox
- - - - - - - - - -
- - - Older BusyBox News - - -
- -
    - -

  • Take me back to the BusyBox web site. -
    - -
  • 10 April 2001 -- BusyBox 0.51 released -
    - - BusyBox 0.51 (the "rock-solid release") is now out there. This - release adds only 2 new applets: env and vi. The vi applet, - contributed by Sterling Huxley, is very functional, and is only - 22k. This release fixes 3 critical bugs in the 0.50 release. - There were 2 potential segfaults in lash (the busybox shell) in - the 0.50 release which are now fixed. Another critical bug in - 0.50 which is now fixed: syslogd from 0.50 could potentially - deadlock the init process and thereby break your entire system. -

    - - There are a number of improvements in this release as well. For - one thing, the wget applet is greatly improved. Dmitry Zakharov - added FTP support, and Laurence Anderson make wget fully RFC - compliant for HTTP 1.1. The mechanism for including utility - functions in previous releases was clumsy and error prone. Now - all utility functions are part of a new libbb library, which makes - maintaining utility functions much simpler. And BusyBox now - compiles on itanium systems (thanks to the Debian itanium porters - for letting me use their system!). -

    - You can read the - changelog for - complete details. BusyBox 0.51 can be downloaded from - ftp://oss.lineo.com/busybox. -

    Have Fun! -

    - -

  • Busybox Boot-Floppy Image - -

    Because you asked for it, we have made available a Busybox boot floppy - image. Here's how you use it: - -

      - -
    1. - Download the image - -
    2. dd it onto a floppy like so: dd if=busybox.floppy.img - of=/dev/fd0 ; sync - -
    3. Pop it in a machine and boot up. - -
    - -

    If you want to look at the contents of the initrd image, do this: - -

    -	    mount ./busybox.floppy.img /mnt -o loop -t msdos        
    -	    cp /mnt/initrd.gz /tmp                          
    -	    umount /mnt           
    -	    gunzip /tmp/initrd.gz
    -	    mount /tmp/initrd /mnt -o loop -t minix
    -    
    - - -
  • 15 March 2001 -- BusyBox 0.50 released -
    - - This release adds several new applets including ifconfig, route, pivot_root, stty, - and tftp, and also fixes tons of bugs. Tab completion in the - shell is now working very well, and the shell's environment variable - expansion was fixed. Tons of other things were fixed or made - smaller. For a fairly complete overview, see the - changelog. -

    - lash (the busybox shell) is still with us, fixed up a bit so it - now behaves itself quite nicely. It really is quite usable as - long as you don't expect it to provide Bourne shell grammer. - Standard things like pipes, redirects, command line editing, and - environment variable expansion work great. But we have found that - this shell, while very usable, does not provide an extensible - framework for adding in full Bourne shell behavior. So the first order of - business as we begin working on the next BusyBox release will be to merge in the new shell - currently in progress at - Larry Doolittle's website. -

    - - -

  • 27 January 2001 -- BusyBox 0.49 released -
    - - Several new applets, lots of bug fixes, cleanups, and many smaller - things made nicer. Several cleanups and improvements to the shell. - For a list of the most interesting changes - you might want to look at the changelog. -

    - Special thanks go out to Matt Kraai and Larry Doolittle for all their - work on this release, and for keeping on top of things while I've been - out of town. -

    - Special Note
    - - BusyBox 0.49 was supposed to have replaced lash, the BusyBox - shell, with a new shell that understands full Bourne shell/Posix shell grammer. - Well, that simply didn't happen in time for this release. A new - shell that will eventually replace lash is already under - construction. This new shell is being developed by Larry - Doolittle, and could use all of our help. Please see the work in - progress on Larry's website - and help out if you can. This shell will be included in the next - release of BusyBox. -

    - -

  • 13 December 2000 -- BusyBox 0.48 released -
    - - This release fixes lots and lots of bugs. This has had some very - rigorous testing, and looks very, very clean. The usual tar - update of course: tar no longer breaks hardlinks, tar -xzf is - optionally supported, and the LRP folks will be pleased to know - that 'tar -X' and 'tar --exclude' are both now in. Applets are - now looked up using a binary search making lash (the busybox - shell) much faster. For the new debian-installer (for Debian - woody) a .udeb can now be generated. -

    - The curious can get a list of some of the more interesting changes by reading - the changelog. -

    - Many thanks go out to the many many people that have contributed to - this release, especially Matt Kraai, Larry Doolittle, and Kent Robotti. -

    -

  • 26 September 2000 -- BusyBox 0.47 released -
    - - This release fixes lots of bugs (including an ugly bug in 0.46 - syslogd that could fork-bomb your system). Added several new - apps: rdate, wget, getopt, dos2unix, unix2dos, reset, unrpm, - renice, xargs, and expr. syslogd now supports network logging. - There are the usual tar updates. Most apps now use getopt for - more correct option parsing. - See the changelog - for complete details. - - -

  • 11 July 2000 -- BusyBox 0.46 released -
    - - This release fixes several bugs (including a ugly bug in tar, - and fixes for NFSv3 mount support). Added a dumpkmap to allow - people to dump a binary keymaps for use with 'loadkmap', and a - completely reworked 'grep' and 'sed' which should behave better. - BusyBox shell can now also be used as a login shell. - See the changelog - for complete details. - - -

  • 21 June 2000 -- BusyBox 0.45 released -
    - - This release has been slow in coming, but is very solid at this - point. BusyBox now supports libc5 as well as GNU libc. This - release provides the following new apps: cut, tr, insmod, ar, - mktemp, setkeycodes, md5sum, uuencode, uudecode, which, and - telnet. There are bug fixes for just about every app as well (see - the changelog for - details). -

    - Also, some exciting infrastructure news! Busybox now has its own - mailing list, - publically browsable - CVS tree, - anonymous - CVS access, and - for those that are actively contributing there is even - CVS write access. - I think this will be a huge help to the ongoing development of BusyBox. -

    - Also, for the curious, there is no 0.44 release. Somehow 0.44 got announced - a few weeks ago prior to its actually being released. To avoid any confusion - we are just skipping 0.44. -

    - Many thanks go out to the many people that have contributed to this release - of BusyBox (esp. Pavel Roskin)! - - -

  • 19 April 2000 -- syslogd bugfix -
    - Turns out that there was still a bug in busybox syslogd. - For example, with the following test app: -
    -	#include <syslog.h>
    -
    -	int do_log(char* msg, int delay)
    -	{
    -	    openlog("testlog", LOG_PID, LOG_DAEMON);
    -	    while(1) {
    -	        syslog(LOG_ERR, "%s: testing one, two, three\n", msg);
    -	        sleep(delay);
    -	    }
    -	    closelog();
    -	    return(0);
    -	};
    -
    -	int main(void)
    -	{
    -	    if (fork()==0)
    -	        do_log("A", 2);
    -	    do_log("B", 3);
    -	}
    -
    - it should be logging stuff from both "A" and "B". As released in 0.43 only stuff - from "A" would have been logged. This means that if init tries to log something - while say ppp has the syslog open, init would block (which is bad, bad, bad). -

    - Karl M. Hegbloom has created a - fix for the problem. - Thanks Karl! - - -

  • 18 April 2000 -- BusyBox 0.43 released (finally!) -
    - I have finally gotten everything into a state where I feel pretty - good about things. This is definitely the most stable, solid release - so far. A lot of bugs have been fixed, and the following new apps - have been added: sh, basename, dirname, killall, uptime, - freeramdisk, tr, echo, test, and usleep. Tar has been completely - rewritten from scratch. Bss size has also been greatly reduced. - More details are available in the - changelog. - Oh, and as a special bonus, I wrote some fairly comprehensive - documentation, complete with examples and full usage information. - -

    - Many thanks go out to the fine people that have helped by submitting patches - and bug reports; particularly instrumental in helping for this release were - Karl Hegbloom, Pavel Roskin, Friedrich Vedder, Emanuele Caratti, - Bob Tinsley, Nicolas Pitre, Avery Pennarun, Arne Bernin, John Beppu, and Jim Gleason. - There were others so if I somehow forgot to mention you, I'm very sorry. -

    - - You can grab BusyBox 0.43 tarballs here. - -

  • 9 April 2000 -- BusyBox 0.43 pre release -
    - Unfortunately, I have not yet finished all the things I want to - do for BusyBox 0.43, so I am posting this pre-release for people - to poke at. This contains my complete rewrite of tar, which now weighs in at - 5k (7k with all options turned on) and works for reading and writing - tarballs (which it does correctly for everything I have been able to throw - at it). Tar also (optionally) supports the "--exclude" option (mainly because - the Linux Router Project folks asked for it). This also has a pre-release - of the micro shell I have been writing. This pre-release should be stable - enough for production use -- it just isn't a release since I have some structural - changes I still want to make. -

    - The pre-release can be found here. - Please let me know ASAP if you find any bugs. - -

  • 28 March 2000 -- Andersen Baby Boy release -
    - I am pleased to announce that on Tuesday March 28th at 5:48pm, weighing in at 7 - lbs. 12 oz, Micah Erik Andersen was born at LDS Hospital here in Salt Lake City. - He was born in the emergency room less then 5 minutes after we arrived -- and - it was such a relief that we even made it to the hospital at all. Despite the - fact that I was driving at an amazingly unlawful speed and honking at everybody - and thinking decidedly unkind thoughts about the people in our way, my wife - (inconsiderate of my feelings and complete lack of medical training) was lying - down in the back seat saying things like "I think I need to start pushing now" - (which she then proceeded to do despite my best encouraging statements to the - contrary). -

    - Anyway, I'm glad to note that despite the much-faster-than-we-were-expecting - labor, both Shaunalei and our new baby boy are doing wonderfully. -

    - So now that I am done with my excuse for the slow release cycle... - Progress on the next release of BusyBox has been slow but steady. I expect - to have a release sometime during the first week of April. This release will - include a number of important changes, including the addition of a shell, a - re-write of tar (to accommodate the Linux Router Project), and syslogd can now - accept multiple concurrent connections, fixing lots of unexpected blocking - problems. - - -

  • 11 February 2000 -- BusyBox 0.42 released -
    - - This is the most solid BusyBox release so far. Many, many - bugs have been fixed. See the -changelog for details. - - Of particular interest, init will now cleanly unmount - filesystems on reboot, cp and mv have been rewritten and - behave much better, and mount and umount no longer leak - loop devices. Many thanks go out to Randolph Chung, - Karl M. Hegbloom, Taketoshi Sano, and Pavel Roskin for - their hard work on this release of BusyBox. Please pound - on it and let me know if you find any bugs. - -

  • 19 January 2000 -- BusyBox 0.41 released -
    - - This release includes bugfixes to cp, mv, logger, true, false, - mkdir, syslogd, and init. New apps include wc, hostid, - logname, tty, whoami, and yes. New features include loop device - support in mount and umount, and better TERM handling by init. - The changelog can be found here. - -

  • 7 January 2000 -- BusyBox 0.40 released -
    - - This release includes bugfixes to init (now includes inittab support), - syslogd, head, logger, du, grep, cp, mv, sed, dmesg, ls, kill, gunzip, and mknod. - New apps include sort, uniq, lsmod, rmmod, fbset, and loadacm. - In particular, this release fixes an important bug in tar which - in some cases produced serious security problems. - As always, the changelog can be found here. - -

  • 11 December 1999 -- BusyBox Website -
    - I have received permission from Bruce Perens (the original author of BusyBox) - to set up this site as the new primary website for BusyBox. This website - will always contain pointers to the latest and greatest, and will also - contain the latest documentation on how to use BusyBox, what it can do, - what arguments its apps support, etc. - -

  • 10 December 1999 -- BusyBox 0.39 released -
    - This release includes fixes to init, reboot, halt, kill, and ls, and contains - the new apps ping, hostname, mkfifo, free, tail, du, tee, and head. A full - changelog can be found here. -

  • 5 December 1999 -- BusyBox 0.38 released -
    - This release includes fixes to tar, cat, ls, dd, rm, umount, find, df, - and make install, and includes new apps syslogd/klogd and logger. -
- - - - -
- - - Important Links - - -
- - - - - - -
-

- - - - -
- - - - - - - - - - - - - - - -
- - Mail all comments, insults, suggestions and bribes to - Erik Andersen
- The Busybox logo is copyright 1999,2000, Erik Andersen. -
-
- This site created with the vi editor - - Graphics by GIMP - - Linux Today - -

Slashdot -

- Freshmeat -
- - - - - diff --git a/busybox/docs/busybox.net/screenshot.html b/busybox/docs/busybox.net/screenshot.html deleted file mode 100644 index 8424fcef6..000000000 --- a/busybox/docs/busybox.net/screenshot.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - Busybox Screenshot! - - - - - - - - -

Busybox Screenshot!

- - - -
- - -
-
-
-$ ./busybox
-BusyBox v0.49 (2001.01.30-17:35+0000) multi-call binary -- GPL2
-
-Usage: busybox [function] [arguments]...
-   or: [function] [arguments]...
-
-        BusyBox is a multi-call binary that combines many common Unix
-        utilities into a single executable.  Most people will create a
-        link to busybox for each function they wish to use, and BusyBox
-        will act like whatever it was invoked as.
-
-Currently defined functions:
-        basename, busybox, cat, chgrp, chmod, chown, chroot, chvt, clear,
-        cp, cut, date, dd, df, dirname, dmesg, du, echo, false, find,
-        free, grep, gunzip, gzip, halt, head, id, init, kill, killall,
-        ln, logger, ls, lsmod, mkdir, mknod, mkswap, more, mount, mv,
-        poweroff, ps, pwd, reboot, reset, rm, rmdir, sed, sh, sleep, sort,
-        swapoff, swapon, sync, syslogd, tail, tar, touch, true, tty, umount,
-        uname, uniq, uptime, wc, which, whoami, xargs, yes, zcat
-
-$ _
-
-
- -
- - - - - diff --git a/busybox/docs/busybox.sgml b/busybox/docs/busybox.sgml deleted file mode 100644 index 2d372506b..000000000 --- a/busybox/docs/busybox.sgml +++ /dev/null @@ -1,3974 +0,0 @@ - - - - BusyBox - The Swiss Army Knife of Embedded Linux - - - - This documentation 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 - - - - For more details see the file COPYING in the source - distribution of Linux. - - - - - - - Introduction - - - BusyBox combines tiny versions of many common UNIX utilities into a single - small executable. It provides minimalist replacements for most of the - utilities you usually find in fileutils, shellutils, findutils, textutils, - grep, gzip, tar, etc. BusyBox provides a fairly complete POSIX environment - for any small or embedded system. The utilities in BusyBox generally have - fewer options than their full-featured GNU cousins; however, the options - that are included provide the expected functionality and behave very much - like their GNU counterparts. - - - - BusyBox has been written with size-optimization and limited resources in - mind. It is also extremely modular so you can easily include or exclude - commands (or features) at compile time. This makes it easy to customize - your embedded systems. To create a working system, just add a kernel, a - shell (such as ash), and an editor (such as elvis-tiny or ae). - - - - - How to use BusyBox - - Syntax - - - - BusyBox <function> [arguments...] # or - - - - - - <function> [arguments...] # if symlinked - - - - - - Invoking BusyBox - - - When you create a link to BusyBox for the function you wish to use, when - BusyBox is called using that link it will behave as if the command itself - has been invoked. - - - - For example, entering - - - - - ln -s ./BusyBox ls - ./ls - - - - - will cause BusyBox to behave as 'ls' (if the 'ls' command has been compiled - into BusyBox). - - - - You can also invoke BusyBox by issuing the command as an argument on the - command line. For example, entering - - - - - ./BusyBox ls - - - - - will also cause BusyBox to behave as 'ls'. - - - - - - Common options - - - Most BusyBox commands support the --help option to provide - a terse runtime description of their behavior. - - - - - - BusyBox Commands - - Available BusyBox Commands - - Currently defined functions include: - - - - ar, basename, cat, chgrp, chmod, chown, chroot, chvt, clear, - cp, cut, date, dc, dd, deallocvt, df, dirname, dmesg, dpkg-deb, - du, dumpkmap, dutmp, echo, false, fbset, fdflush, find, free, - freeramdisk, fsck.minix, grep, gunzip, gzip, halt, head, - hostid, hostname, id, init, insmod, kill, killall, length, ln, - loadacm, loadfont, loadkmap, logger, logname, ls, lsmod, - makedevs, mkdir, mkfifo, mkfs.minix, mknod, mkswap, mktemp, - more, mount, mt, mv, nc, nslookup, ping, poweroff, printf, ps, - pwd, reboot, renice, reset, rm, rmdir, rmmod, sed, setkeycodes, sh, sleep, - sort, swapoff, swapon, sync, syslogd, tail, tar, tee, telnet, - test, touch, tr, true, tty, umount, uname, uniq, update, - uptime, usleep, uudecode, uuencode, wc, which, whoami, yes, - zcat, [ - - - - - ar - - - Usage: ar [OPTION] archive [FILENAME]... - - - - Extract or list files from an ar archive. - - - - Options: - - - - - o Preserve original dates - p Extract to stdout - t List - x Extract - v Verbosely list files processed - - - - - - basename - - Usage: basename FILE [SUFFIX] - - - - Strip directory path and suffixes from FILE. If specified, also removes - any trailing SUFFIX. - - - - Example: - - - - - $ basename /usr/local/bin/foo - foo - $ basename /usr/local/bin/ - bin - $ basename /foo/bar.txt .txt - bar - - - - - - cat - - - Usage: cat [FILE]... - - - - Concatenate FILE(s) and prints them to the standard - output. - - - - Example: - - - - - $ cat /proc/uptime - 110716.72 17.67 - - - - - - chgrp - - - Usage: chgrp [OPTION]... GROUP FILE... - - - - Change the group membership of each FILE to GROUP. - - - - Options: - - - - - -R Change files and directories recursively - - - - - Example: - - - - - $ ls -l /tmp/foo - -r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo - $ chgrp root /tmp/foo - $ ls -l /tmp/foo - -r--r--r-- 1 andersen root 0 Apr 12 18:25 /tmp/foo - - - - - - chmod - - - Usage: chmod [-R] MODE[,MODE]... FILE... - - - - Change file access permissions for the specified - FILE(s) (or directories). Each MODE is defined by - combining the letters for WHO has access to the file, an OPERATOR for - selecting how the permissions should be changed, and a PERMISSION for - FILE(s) (or directories). - - - - WHO may be chosen from - - - - - u User who owns the file - g Users in the file's Group - o Other users not in the file's group - a All users - - - - - OPERATOR may be chosen from - - - - - + Add a permission - - Remove a permission - = Assign a permission - - - - - PERMISSION may be chosen from - - - - - r Read - w Write - x Execute (or access for directories) - s Set user (or group) ID bit - t Sticky bit (for directories prevents removing files by non-owners) - - - - - Alternately, permissions can be set numerically where the first three - numbers are calculated by adding the octal values, such as - - - - - 4 Read - 2 Write - 1 Execute - - - - - An optional fourth digit can also be used to specify - - - - - 4 Set user ID - 2 Set group ID - 1 Sticky bit - - - - - Options: - - - - - -R Change files and directories recursively. - - - - - Example: - - - - - $ ls -l /tmp/foo - -rw-rw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo - $ chmod u+x /tmp/foo - $ ls -l /tmp/foo - -rwxrw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo* - $ chmod 444 /tmp/foo - $ ls -l /tmp/foo - -r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo - - - - - - chown - - Usage: chown [OPTION]... OWNER[<.|:>[GROUP] FILE... - - - - Change the owner and/or group of each FILE to OWNER and/or GROUP. - - - - Options: - - - - - -R Change files and directories recursively - - - - - Example: - - - - - $ ls -l /tmp/foo - -r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo - $ chown root /tmp/foo - $ ls -l /tmp/foo - -r--r--r-- 1 root andersen 0 Apr 12 18:25 /tmp/foo - $ chown root.root /tmp/foo - ls -l /tmp/foo - -r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo - - - - - - chroot - - Usage: chroot NEWROOT [COMMAND...] - - - - Run COMMAND with root directory set to NEWROOT. - - - - Example: - - - - - $ ls -l /bin/ls - lrwxrwxrwx 1 root root 12 Apr 13 00:46 /bin/ls -> /BusyBox - $ mount /dev/hdc1 /mnt -t minix - $ chroot /mnt - $ ls -l /bin/ls - -rwxr-xr-x 1 root root 40816 Feb 5 07:45 /bin/ls* - - - - - - chvt - - Usage: chvt N - - - - Change the foreground virtual terminal to /dev/ttyN - - - - - clear - - - Usage: clear - - - - Clear the screen. - - - - - cp - - - Usage: cp [OPTION]... SOURCE DEST - - - - - or: cp [OPTION]... SOURCE... DIRECTORY - - - - - Copy SOURCE to DEST, or multiple SOURCE(s) to - DIRECTORY. - - - - Options: - - - - - -a Same as -dpR - -d Preserve links - -p Preserve file attributes if possible - -R Copy directories recursively - - - - - - cut - - - Usage: cut [OPTION]... [FILE]... - - - - Print selected fields from each input FILE to standard output. - - - - Options: - - - - - -b LIST Output only bytes from LIST - -c LIST Output only characters from LIST - -d CHAR Use CHAR instead of tab as the field delimiter - -s Output only the lines containing delimiter - -f N Print only these fields - -n Ignored - - - - - Example: - - - - - $ echo "Hello world" | cut -f 1 -d ' ' - Hello - $ echo "Hello world" | cut -f 2 -d ' ' - world - - - - - - date - - - Usage: date [OPTION]... [+FORMAT] - - - - - or: date [OPTION] [MMDDhhmm[[CC]YY][.ss]] - - - - - Display the current time in the given FORMAT, or set the system date. - - - - Options: - - - - - -R Output RFC-822 compliant date string - -s Set time described by STRING - -u Print or set Coordinated Universal Time - - - - - Example: - - - - - $ date - Wed Apr 12 18:52:41 MDT 2000 - - - - - - dc - - - Usage: dc [EXPRESSION] - - - - This is a Tiny RPN calculator that understands the - following operations: +, -, /, *, and, or, not, eor. If - no arguments are given, dc will process input from - stdin. - - - - The behaviour of BusyBox/dc deviates (just a little ;-) - from GNU/dc, but this will be remedied in the future. - - - - Example: - - - - - $ dc 2 2 + - 4 - $ dc 8 8 \* 2 2 + / - 16 - $ dc 0 1 and - 0 - $ dc 0 1 or - 1 - $ echo 72 9 div 8 mul | dc - 64 - - - - - - dd - - - Usage: dd [OPTION]... - - - - Copy a file, converting and formatting according to - options. - - - - Options: - - - - - if=FILE Read from FILE instead of stdin - of=FILE Write to FILE instead of stdout - bs=N Read and write N bytes at a time - count=N Copy only N input blocks - skip=N Skip N input blocks - seek=N Skip N output blocks - - - - - Numbers may be suffixed by w (x2), k (x1024), b (x512), - or M (x1024^2). - - - - Example: - - - - - $ dd if=/dev/zero of=/dev/ram1 bs=1M count=4 - 4+0 records in - 4+0 records out - - - - - - deallocvt - - - Usage: deallocvt N - - - - Deallocate unused virtual terminal /dev/ttyN. - - - - - df - - - Usage: df [FILE]... - - - - Print the filesystem space used and space available. - - - - Example: - - - - - $ df - Filesystem 1k-blocks Used Available Use% Mounted on - /dev/sda3 8690864 8553540 137324 98% / - /dev/sda1 64216 36364 27852 57% /boot - $ df /dev/sda3 - Filesystem 1k-blocks Used Available Use% Mounted on - /dev/sda3 8690864 8553540 137324 98% / - - - - - - dirname - - - Usage: dirname NAME - - - - Strip non-directory suffix from NAME. - - - - Example: - - - - - $ dirname /tmp/foo - /tmp - $ dirname /tmp/foo/ - /tmp - - - - - - dmesg - - - Usage: dmesg [OPTION]... - - - - Print or control the kernel ring buffer. - - - - Options: - - - - - -c Clear the ring buffer after printing - -n LEVEL Set the console logging level to LEVEL - -s BUFSIZE Query ring buffer using a buffer of BUFSIZE - - - - - - dos2unix - - - Usage: dos2unix < dosfile > unixfile - - - - Converts a text file from dos format to unix format. - - - - - - dpkg-deb - - - Usage: dpkg-deb [OPTION] archive [directory] - - - - Debian package archive (.deb) manipulation tool - - - - Options: - - - - - -c List the contents of the filesystem tree archive portion of the package - -e Extracts the control information files from a package archive into the specified directory. - If no directory is specified then a subdirectory DEBIAN in the current directory is used. - -x Silently extracts the filesystem tree from a package archive into the specified directory. - -X Extracts the filesystem tree from a package archive into the specified directory, listing the files as it goes. - If required the specified directory (but not its parents) will be created. - - - - - Example: - - - - - dpkg-deb -e ./busybox_0.48-1_i386.deb - dpkg-deb -x ./busybox_0.48-1_i386.deb ./unpack_dir - - - - - - du - - - Usage: du [OPTION]... [FILE]... - - - - Summarize the disk space used for each FILE or current - directory. Disk space printed in units of 1k (i.e., - 1024 bytes). - - - - Options: - - - - - -l Count sizes many times if hard linked - -s Display only a total for each argument - - - - - Example: - - - - - $ du - 16 ./CVS - 12 ./kernel-patches/CVS - 80 ./kernel-patches - 12 ./tests/CVS - 36 ./tests - 12 ./scripts/CVS - 16 ./scripts - 12 ./docs/CVS - 104 ./docs - 2417 . - - - - - - dumpkmap - - - Usage: dumpkmap - - - - Prints out a binary keyboard translation table to standard output. - - - - Example: - - - - - $ dumpkmap < keymap - - - - - - dutmp - - - Usage: dutmp [FILE] - - - - Dump utmp file format (pipe delimited) from FILE or - stdin to stdout. - - - - Example: - - - - - $ dutmp /var/run/utmp - 8|7||si|||0|0|0|955637625|760097|0 - 2|0|~|~~|reboot||0|0|0|955637625|782235|0 - 1|20020|~|~~|runlevel||0|0|0|955637625|800089|0 - 8|125||l4|||0|0|0|955637629|998367|0 - 6|245|tty1|1|LOGIN||0|0|0|955637630|998974|0 - 6|246|tty2|2|LOGIN||0|0|0|955637630|999498|0 - 7|336|pts/0|vt00andersen|andersen|:0.0|0|0|0|955637763|0|0 - - - - - - echo - - - Usage: echo [OPTION]... [ARG]... - - - - Print ARGs to stdout. - - - - Options: - - - - - -n Suppress trailing newline - -e Enable interpretation of escaped characters - -E Disable interpretation of escaped characters - - - - - Example: - - - - - $ echo "Erik is cool" - Erik is cool - $ echo -e "Erik\nis\ncool" - Erik - is - cool - $ echo "Erik\nis\ncool" - Erik\nis\ncool - - - - - - expr - - - Usage: expr EXPRESSION - - - - Prints the value of EXPRESSION to standard output. - - - - EXPRESSION may be: - - - - - ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2 - ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0 - ARG1 < ARG2 ARG1 is less than ARG2 - ARG1 <= ARG2 ARG1 is less than or equal to ARG2 - ARG1 = ARG2 ARG1 is equal to ARG2 - ARG1 != ARG2 ARG1 is unequal to ARG2 - ARG1 >= ARG2 ARG1 is greater than or equal to ARG2 - ARG1 > ARG2 ARG1 is greater than ARG2 - ARG1 + ARG2 arithmetic sum of ARG1 and ARG2 - ARG1 - ARG2 arithmetic difference of ARG1 and ARG2 - ARG1 * ARG2 arithmetic product of ARG1 and ARG2 - ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2 - ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2 - STRING : REGEXP anchored pattern match of REGEXP in STRING - match STRING REGEXP same as STRING : REGEXP - substr STRING POS LENGTH substring of STRING, POS counted from 1 - index STRING CHARS index in STRING where any CHARS is found, or 0 - length STRING length of STRING - quote TOKEN interpret TOKEN as a string, even if it is a - keyword like `match' or an operator like `/' - ( EXPRESSION ) value of EXPRESSION - - - - - Beware that many operators need to be escaped or quoted for shells. - Comparisons are arithmetic if both ARGs are numbers, else - lexicographical. Pattern matches return the string matched between - \( and \) or null; if \( and \) are not used, they return the number - of characters matched or 0. - - - - - - - false - - - Usage: false - - - - Return an exit code of FALSE (1). - - - - Example: - - - - - $ false - $ echo $? - 1 - - - - - - fbset - - - Usage: fbset [OPTION]... [MODE] - - - - Show and modify frame buffer device settings. - - - - Options: - - - - - -h Display option summary - -fb DEVICE Operate on DEVICE - -db FILE Use FILE for mode database - -g XRES YRES VXRES VYRES DEPTH Set all geometry parameters - -t PIXCLOCK LEFT RIGHT UPPER LOWER HSLEN VSLEN Set all timing parameters - -xres RES Set visible horizontal resolution - -yres RES Set visible vertical resolution - - - - - Example: - - - - - $ fbset - mode "1024x768-76" - # D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz - geometry 1024 768 1024 768 16 - timings 12714 128 32 16 4 128 4 - accel false - rgba 5/11,6/5,5/0,0/0 - endmode - - - - - - fdflush - - - Usage: fdflush DEVICE - - - - Force floppy disk drive to detect disk change on DEVICE. - - - - - find - - - Usage: find [PATH]... [EXPRESSION] - - - - Search for files in a directory hierarchy. The default - PATH is the current directory; default EXPRESSION is - '-print'. - - - - EXPRESSION may consist of: - - - - - -follow Dereference symbolic links - -name PATTERN File name (leading directories removed) matches PATTERN - -type X Filetype matches X (where X is one of: f,d,l,b,c,...) - -perm PERMS Permissions match any of (+NNN); all of (-NNN); or exactly (NNN) - -mtime TIME Modified time is greater than (+N); less than (-N); or exactly (N) days - - - - - Example: - - - - - $ find / -name /etc/passwd - /etc/passwd - - - - - - free - - - Usage: free - - - - Displays the amount of free and used system memory. - - - - Example: - - - - - $ free - total used free shared buffers - Mem: 257628 248724 8904 59644 93124 - Swap: 128516 8404 120112 - Total: 386144 257128 129016 - - - - - - freeramdisk - - - Usage: freeramdisk DEVICE - - - - Free all memory used by the ramdisk DEVICE. - - - - Example: - - - - - $ freeramdisk /dev/ram2 - - - - - - fsck.minix - - - Usage: fsck.minix [OPTION]... DEVICE - - - - Perform a consistency check on the MINIX filesystem on - DEVICE. - - - - Options: - - - - - -l List all filenames - -r Perform interactive repairs - -a Perform automatic repairs - -v Verbose - -s Output super-block information - -m Activate MINIX-like "mode not cleared" warnings - -f Force file system check. - - - - - - getopt - - - Usage: getopt [OPTIONS]... - - - - Parse command options - - - - - -a, --alternative Allow long options starting with single -\n" - -l, --longoptions=longopts Long options to be recognized\n" - -n, --name=progname The name under which errors are reported\n" - -o, --options=optstring Short options to be recognized\n" - -q, --quiet Disable error reporting by getopt(3)\n" - -Q, --quiet-output No normal output\n" - -s, --shell=shell Set shell quoting conventions\n" - -T, --test Test for getopt(1) version\n" - -u, --unqote Do not quote the output\n" - - - - - - Example: - - - - - $ cat getopt.test - #!/bin/sh - GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \ - -n 'example.busybox' -- "$@"` - if [ $? != 0 ] ; then exit 1 ; fi - eval set -- "$GETOPT" - while true ; do - case $1 in - -a|--a-long) echo "Option a" ; shift ;; - -b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;; - -c|--c-long) - case "$2" in - "") echo "Option c, no argument"; shift 2 ;; - *) echo "Option c, argument \`$2'" ; shift 2 ;; - esac ;; - --) shift ; break ;; - *) echo "Internal error!" ; exit 1 ;; - esac - done - - - - - - grep - - - Usage: grep [OPTIONS]... PATTERN [FILE]... - - - - Search for PATTERN in each FILE or stdin. - - - - Options: - - - - - -h Suppress the prefixing filename on output - -i Ignore case distinctions - -n Print line number with output lines - -q Be quiet. Returns 0 if result was found, 1 otherwise - -v Select non-matching lines - - - - - This version of grep matches full regular expressions. - - - - Example: - - - - - $ grep root /etc/passwd - root:x:0:0:root:/root:/bin/bash - $ grep ^[rR]oo. /etc/passwd - root:x:0:0:root:/root:/bin/bash - - - - - - gunzip - - - Usage: gunzip [OPTION]... FILE - - - - Uncompress FILE (or stdin if FILE is '-'). - - - - Options: - - - - - -c Write output to standard output - -t Test compressed file integrity - - - - - Example: - - - - - $ ls -la /tmp/BusyBox* - -rw-rw-r-- 1 andersen andersen 557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz - $ gunzip /tmp/BusyBox-0.43.tar.gz - $ ls -la /tmp/BusyBox* - -rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar - - - - - - gzip - - - Usage: gzip [OPTION]... FILE - - - - Compress FILE (or stdin if FILE is '-') with maximum - compression to FILE.gz (or stdout if FILE is '-'). - - - - Options: - - - - - -c Write output to standard output - -d decompress - - - - - Example: - - - - - $ ls -la /tmp/BusyBox* - -rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar - $ gzip /tmp/BusyBox-0.43.tar - $ ls -la /tmp/BusyBox* - -rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/BusyBox-0.43.tar.gz - - - - - - halt - - - Usage: halt - - - - Halt the system. - - - - - head - - - Usage: head [OPTION] FILE... - - - - Print first 10 lines of each FILE to standard output. - With more than one FILE, precede each with a header - giving the file name. With no FILE, or when FILE is -, - read standard input. - - - - Options: - - - - - -n NUM Print first NUM lines instead of first 10 - - - - - Example: - - - - - $ head -n 2 /etc/passwd - root:x:0:0:root:/root:/bin/bash - daemon:x:1:1:daemon:/usr/sbin:/bin/sh - - - - - - hostid - - - Usage: hostid - - - - Prints out a unique 32-bit identifier for the current - machine. The 32-bit identifier is intended to be unique - among all UNIX systems in existence. - - - - - hostname - - - Usage: hostname [OPTION]... [HOSTNAME|-F FILE] - - - - Get or set the hostname or DNS domain name. If a - hostname is given (or a file with the -F parameter), the - host name will be set. - - - - Options: - - - - - -s Short - -i Addresses for the hostname - -d DNS domain name - -F, --file FILE Use the contents of FILE to specify the hostname - - - - - Example: - - - - - $ hostname - slag - - - - - - id - - - Usage: id [OPTION]... [USERNAME] - - - - Print information for USERNAME or the current user. - - - - Options: - - - - - -g Print only the group ID - -u Print only the user ID - -n print a name instead of a number (with for -ug) - -r Print the real user ID instead of the effective ID (with -ug) - - - - - Example: - - - - - $ id - uid=1000(andersen) gid=1000(andersen) - - - - - - init - - - Usage: init - - - - Init is the parent of all processes. - - - - This version of init is designed to be run only by the - kernel. - - - - BusyBox init doesn't support multiple runlevels. The - runlevels field of the /etc/inittab file is completely - ignored by BusyBox init. If you want runlevels, use - sysvinit. - - - - BusyBox init works just fine without an inittab. If no - inittab is found, it has the following default behavior: - - - - - ::sysinit:/etc/init.d/rcS - ::askfirst:/bin/sh - - - - - If it detects that /dev/console is _not_ a serial - console, it will also run: - - - - - tty2::askfirst:/bin/sh - - - - - If you choose to use an /etc/inittab file, the inittab - entry format is as follows: - - - - - <id>:<runlevels>:<action>:<process> - - - - - id - - - WARNING: This field has a non-traditional meaning for BusyBox init! - The id field is used by BusyBox init to specify the controlling tty - for the specified process to run on. The contents of this field - are appended to "/dev/" and used as-is. There is no need for this - field to be unique, although if it isn't you may have strange - results. If this field is left blank, the controlling tty is set - to the console. Also note that if BusyBox detects that a serial - console is in use, then only entries whose controlling tty is - either the serial console or /dev/null will be run. BusyBox init - does nothing with utmp. We don't need no stinkin' utmp. - - - - - - runlevels - - - The runlevels field is completely ignored. - - - - - action - - - - Valid actions include: sysinit, respawn, askfirst, wait, - once, and ctrlaltdel. - - - - - The available actions can be classified into two groups: actions - that are run only once, and actions that are re-run when the specified - process exits. - - - - Run only-once actions: - - - - 'sysinit' is the first item run on boot. init waits until all - sysinit actions are completed before continuing. Following the - completion of all sysinit actions, all 'wait' actions are run. - 'wait' actions, like 'sysinit' actions, cause init to wait until - the specified task completes. 'once' actions are asyncronous, - therefore, init does not wait for them to complete. 'ctrlaltdel' - actions are run immediately before init causes the system to reboot - (unmounting filesystems with a 'ctrlaltdel' action is a very good - idea). - - - - Run repeatedly actions: - - - - 'respawn' actions are run after the 'once' actions. When a process - started with a 'respawn' action exits, init automatically restarts - it. Unlike sysvinit, BusyBox init does not stop processes from - respawning out of control. The 'askfirst' actions acts just like - respawn, except that before running the specified process it - displays the line "Please press Enter to activate this console." - and then waits for the user to press enter before starting the - specified process. - - - - Unrecognized actions (like initdefault) will cause init to emit an - error message, and then go along with its business. All actions are - run in the reverse order from how they appear in /etc/inittab. - - - - - - process - - - Specifies the process to be executed and its - command line. - - - - - Example /etc/inittab file - - - - # This is run first except when booting in single-user mode. - # - ::sysinit:/etc/init.d/rcS - - # /bin/sh invocations on selected ttys - # - # Start an "askfirst" shell on the console (whatever that may be) - ::askfirst:-/bin/sh - # Start an "askfirst" shell on /dev/tty2-4 - tty2::askfirst:-/bin/sh - tty2::askfirst:-/bin/sh - tty2::askfirst:-/bin/sh - - # /sbin/getty invocations for selected ttys - # - tty4::respawn:/sbin/getty 38400 tty5 - tty5::respawn:/sbin/getty 38400 tty6 - - # Example of how to put a getty on a serial line (for a terminal) - # - #::respawn:/sbin/getty -L ttyS0 9600 vt100 - #::respawn:/sbin/getty -L ttyS1 9600 vt100 - # - # Example how to put a getty on a modem line. - #::respawn:/sbin/getty 57600 ttyS2 - - # Stuff to do before rebooting - ::ctrlaltdel:/bin/umount -a -r - ::ctrlaltdel:/sbin/swapoff - - - - - - - insmod - - - Usage: insmod [OPTION]... MODULE [symbol=value]... - - - - Load MODULE into the kernel. - - - - Options: - - - - - -f Force module to load into the wrong kernel version. - -k Make module autoclean-able. - -v Verbose output - -x Do not export externs - -L Prevent simultaneous loads of the same module - - - - - - kill - - - Usage: kill [OPTION] PID... - - - - Send a signal (default is SIGTERM) to the specified - PID(s). - - - - Options: - - - - - -l List all signal names and numbers - -SIG Send signal SIG - - - - - Example: - - - - - $ ps | grep apache - 252 root root S [apache] - 263 www-data www-data S [apache] - 264 www-data www-data S [apache] - 265 www-data www-data S [apache] - 266 www-data www-data S [apache] - 267 www-data www-data S [apache] - $ kill 252 - - - - - - killall - - - Usage: killall [OPTION] NAME... - - - - Send a signal (default is SIGTERM) to the specified - NAME(s). - - - - Options: - - - - - -l List all signal names and numbers - -SIG Send signal SIG - - - - - Example: - - - - - $ killall apache - - - - - - length - - - Usage: length STRING - - - - Print the length of STRING. - - - - Example: - - - - - $ length "Hello" - 5 - - - - - - ln - - - Usage: ln [OPTION]... TARGET FILE|DIRECTORY - - - - Create a link named FILE or DIRECTORY to the specified - TARGET. You may use '--' to indicate that all following - arguments are non-options. - - - - Options: - - - - - -s Make symbolic link instead of hard link - -f Remove existing destination file - - - - - Example: - - - - - $ ln -s BusyBox /tmp/ls - $ ls -l /tmp/ls - lrwxrwxrwx 1 root root 7 Apr 12 18:39 ls -> BusyBox* - - - - - - loadacm - - - Usage: loadacm - - - - Load an acm from stdin. - - - - Example: - - - - - $ loadacm < /etc/i18n/acmname - - - - - - loadfont - - - Usage: loadfont - - - - Load a console font from stdin. - - - - Example: - - - - - $ loadfont < /etc/i18n/fontname - - - - - - loadkmap - - - Usage: loadkmap - - - - Load a binary keyboard translation table from stdin. - - - - Example: - - - - - $ loadkmap < /etc/i18n/lang-keymap - - - - - - logger - - - Usage: logger [OPTION]... [MESSAGE] - - - - Write MESSAGE to the system log. If MESSAGE is omitted, log - stdin. - - - - Options: - - - - - -s Log to stderr as well as the system log - -t Log using the specified tag (defaults to user name) - -p Enter the message with the specified priority - This may be numerical or a ``facility.level'' pair - - - - - Example: - - - - - $ logger "hello" - - - - - - logname - - - Usage: logname - - - - Print the name of the current user. - - - - Example: - - - - - $ logname - root - - - - - - ls - - - Usage: ls [OPTION]... [FILE]... - - - - - - - - Options: - - - - - -a Do not hide entries starting with . - -c With -l: show ctime (the time of last - modification of file status information) - -d List directory entries instead of contents - -e List both full date and full time - -l Use a long listing format - -n List numeric UIDs and GIDs instead of names - -p Append indicator (one of /=@|) to entries - -u With -l: show access time (the time of last - access of the file) - -x List entries by lines instead of by columns - -A Do not list implied . and .. - -C List entries by columns - -F Append indicator (one of */=@|) to entries - -L list entries pointed to by symbolic links - -R List subdirectories recursively - - - - - Example: - - - - - - - - - - lsmod - - - Usage: lsmod - - - - List currently loaded kernel modules. - - - - - makedevs - - - Usage: makedevsf NAME TYPE MAJOR MINOR FIRST LAST [s] - - - - Create a range of block or character special files. - - - - TYPE may be: - - - - - b Make a block (buffered) device - c or u Make a character (un-buffered) device - p Make a named pipe. MAJOR and MINOR are ignored for named pipes - - - - - FIRST specifies the number appended to NAME to create - the first device. LAST specifies the number of the last - item that should be created. If 's' is the last - argument, the base device is created as well. - - - - Example: - - - - - $ makedevs /dev/ttyS c 4 66 2 63 - [creates ttyS2-ttyS63] - $ makedevs /dev/hda b 3 0 0 8 s - [creates hda,hda1-hda8] - - - - - - md5sum - - - Usage: md5sum [OPTION]... FILE... - - - - Print or check MD5 checksums. - - - - Options: - - - - - -b Read files in binary mode - -c Check MD5 sums against given list - -t Read files in text mode (default) - -g Read a string - - - - - The following two options are useful only when verifying - checksums: - - - - - -s Don't output anything, status code shows success - -w Warn about improperly formated MD5 checksum lines - - - - - Example: - - - - - $ md5sum busybox - 6fd11e98b98a58f64ff3398d7b324003 busybox - $ md5sum -c - 6fd11e98b98a58f64ff3398d7b324003 busybox - 6fd11e98b98a58f64ff3398d7b324002 busybox - md5sum: MD5 check failed for 'busybox' - ^D - - - - - - mkdir - - - Usage: mkdir [OPTION]... DIRECTORY... - - - - Create the DIRECTORY(s), if they do not already exist. - - - - Options: - - - - - -m Set permission mode (as in chmod), not rwxrwxrwx - umask - -p No error if directory exists, make parent directories as needed - - - - - Example: - - - - - $ mkdir /tmp/foo - $ mkdir /tmp/foo - /tmp/foo: File exists - $ mkdir /tmp/foo/bar/baz - /tmp/foo/bar/baz: No such file or directory - $ mkdir -p /tmp/foo/bar/baz - - - - - - mkfifo - - - Usage: mkfifo [OPTION] NAME - - - - Create a named pipe (identical to 'mknod NAME p'). - - - - Options: - - - - - -m MODE Create the pipe using the specified mode (default a=rw) - - - - - - mkfs.minix - - - Usage: mkfs.minix [OPTION]... NAME [BLOCKS] - - - - Make a MINIX filesystem. - - - - Options: - - - - - -c Check the device for bad blocks - -n [14|30] Specify the maximum length of filenames - -i Specify the number of inodes for the filesystem - -l FILENAME Read the bad blocks list from FILENAME - -v Make a Minix version 2 filesystem - - - - - - mknod - - - Usage: mknod [OPTION]... NAME TYPE MAJOR MINOR - - - - Create a special file (block, character, or pipe). - - - - Options: - - - - - -m Create the special file using the specified mode (default a=rw) - - - - - TYPE may be: - - - - - b Make a block (buffered) device - c or u Make a character (un-buffered) device - p Make a named pipe. MAJOR and MINOR are ignored for named pipes - - - - - Example: - - - - - $ mknod /dev/fd0 b 2 0 - $ mknod -m 644 /tmp/pipe p - - - - - - mkswap - - - Usage: mkswap [OPTION]... DEVICE [BLOCKS] - - - - Prepare a disk partition to be used as a swap partition. - - - - Options: - - - - - -c Check for read-ability. - -v0 Make version 0 swap [max 128 Megs]. - -v1 Make version 1 swap [big!] (default for kernels > 2.1.117). - BLOCKS Number of block to use (default is entire partition). - - - - - - mktemp - - - Usage: mktemp TEMPLATE - - - - Creates a temporary file with its name based on - TEMPLATE. TEMPLATE is any name with six `Xs' (i.e., - /tmp/temp.XXXXXX). - - - - Example: - - - - - $ mktemp /tmp/temp.XXXXXX - /tmp/temp.mWiLjM - $ ls -la /tmp/temp.mWiLjM - -rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM - - - - - - more - - - Usage: more [FILE]... - - - - Page through text one screenful at a time. - - - - Example: - - - - - $ dmesg | more - - - - - - mount - - - Usage: mount [OPTION]... - - - - - or: mount [OPTION]... DEVICE DIRECTORY - - - - - Mount filesystems. - - - - Options: - - - - - -a Mount all filesystems in /etc/fstab - -o One of the many filesystem options listed below - -r Mount the filesystem read-only - -t TYPE Specify the filesystem type - -w Mount the filesystem read-write - - - - - Options for use with the -o flag: - - - - - async/sync Writes are asynchronous / synchronous - atime/noatime Enable / disable updates to inode access times - dev/nodev Allow / disallow use of special device files - exec/noexec Allow / disallow use of executable files - loop Mount a file via loop device - suid/nosuid Allow / disallow set-user-id-root programs - remount Remount a currently mounted filesystem - ro/rw Mount filesystem read-only / read-write - - - - - There are even more flags that are filesystem specific. - You'll have to see the written documentation for those. - - - - Example: - - - - - $ mount - /dev/hda3 on / type minix (rw) - proc on /proc type proc (rw) - devpts on /dev/pts type devpts (rw) - $ mount /dev/fd0 /mnt -t msdos -o ro - $ mount /tmp/diskimage /opt -t ext2 -o loop - - - - - - mt - - - Usage: mt [OPTION] OPCODE VALUE - - - - Control magnetic tape drive operation. - - - - Options: - - - - - -f DEVICE Control DEVICE - - - - - - mv - - - Usage: mv SOURCE DEST - - - - - or: mv SOURCE... DIRECTORY - - - - - Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY. - - - - Example: - - - - - $ mv /tmp/foo /bin/bar - - - - - - nc - - - Usage: nc HOST PORT - - - - or: nc -p PORT -l - - - - - Open a pipe to HOST:PORT or listen for a connection on PORT. - - - - Example: - - - - - $ nc foobar.somedomain.com 25 - 220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600 - help - 214-Commands supported: - 214- HELO EHLO MAIL RCPT DATA AUTH - 214 NOOP QUIT RSET HELP - quit - 221 foobar closing connection - - - - - - nslookup - - - Usage: nslookup [HOST] - - - - Query the nameserver for the IP address of the given - HOST. - - - - Example: - - - - - $ nslookup localhost - Server: default - Address: default - - Name: debian - Address: 127.0.0.1 - - - - - - ping - - - Usage: ping [OPTION]... HOST - - - - Send ICMP ECHO_REQUEST packets to HOST. - - - - Options: - - - - - -c COUNT Send only COUNT pings - -s SIZE Send SIZE data bytes in packets (default=56) - -q Quiet mode, only displays output at start and when finished - - - - - Example: - - - - - $ ping localhost - PING slag (127.0.0.1): 56 data bytes - 64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms - - --- debian ping statistics --- - 1 packets transmitted, 1 packets received, 0% packet loss - round-trip min/avg/max = 20.1/20.1/20.1 ms - - - - - - poweroff - - - Usage: poweroff - - - - Shut down the system, and request that the kernel turn - off power upon halting. - - - - - printf - - - Usage: printf FORMAT [ARGUMENT]... - - - - Format and print the given data in a manner similar to - the C printf command. - - - - Example: - - - - - $ printf "Val=%d\n" 5 - Val=5 - - - - - - ps - - - Usage: ps - - - - Report process status. This version of ps accepts no - options. - - - - Options: - - - - - - - - - Example: - - - - - $ ps - PID Uid Gid State Command - 1 root root S init - 2 root root S [kflushd] - 3 root root S [kupdate] - 4 root root S [kpiod] - 5 root root S [kswapd] - 742 andersen andersen S [bash] - 743 andersen andersen S -bash - 745 root root S [getty] - 2990 andersen andersen R ps - - - - - - pwd - - - Usage: pwd - - - - Print the full filename of the current working - directory. - - - - Example: - - - - - $ pwd - /root - - - - - - rdate - - - Usage: rdate [OPTION] HOST - - - - Get and possibly set the system date and time from a remote HOST. - - - - Options: - - - - - -s Set the system date and time (default). - -p Print the date and time. - - - - - - reboot - - - Usage: reboot - - - - Reboot the system. - - - - - renice - - - Usage: renice priority pid [pid ...] - - - - Changes priority of running processes. Allowed priorities range - from 20 (the process runs only when nothing else is running) to 0 - (default priority) to -20 (almost nothing else ever gets to run). - - - - - reset - - - Usage: reset - - - - Resets the screen. - - - - - rm - - - Usage: rm [OPTION]... FILE... - - - - Remove (unlink) the FILE(s). You may use '--' to - indicate that all following arguments are non-options. - - - - Options: - - - - - -i Always prompt before removing each destinations - -f Remove existing destinations, never prompt - -r or -R Remove the contents of directories recursively - - - - - Example: - - - - - $ rm -rf /tmp/foo - - - - - - rmdir - - - Usage: rmdir DIRECTORY... - - - - Remove DIRECTORY(s) if they are empty. - - - - Example: - - - - - $ rmdir /tmp/foo - - - - - - rmmod - - - Usage: rmmod [OPTION]... [MODULE]... - - - - Unload MODULE(s) from the kernel. - - - - Options: - - - - - -a Try to remove all unused kernel modules - - - - - Example: - - - - - $ rmmod tulip - - - - - - sed - - - Usage: sed [OPTION]... SCRIPT [FILE]... - - - - Allowed sed scripts come in the following form: - - - - - ADDR [!] COMMAND - - - - - ADDR can be: - - - - - NUMBER Match specified line number - $ Match last line - /REGEXP/ Match specified regexp - - - - - ! inverts the meaning of the match - - - - COMMAND can be: - - - - - s/regexp/replacement/[igp] - which attempt to match regexp against the pattern space - and if successful replaces the matched portion with replacement. - aTEXT - which appends TEXT after the pattern space - - - - - This version of sed matches full regular expressions. - - - - Options: - - - - - -e Add the script to the commands to be executed - -n Suppress automatic printing of pattern space - - - - - Example: - - - - - $ echo "foo" | sed -e 's/f[a-zA-Z]o/bar/g' - bar - - - - - - setkeycodes - - - Usage: setkeycodes SCANCODE KEYCODE ... - - - - Set entries into the kernel's scancode-to-keycode map, - allowing unusual keyboards to generate usable keycodes. - - - - SCANCODE may be either xx or e0xx (hexadecimal), and - KEYCODE is given in decimal. - - - - Example: - - - - - $ setkeycodes e030 127 - - - - - - - sh - - - Usage: sh - - - - lash -- the BusyBox LAme SHell (command interpreter) - - - - This command does not yet have proper documentation. - - - - Use lash just as you would use any other shell. It - properly handles pipes, redirects, job control, can be - used as the shell for scripts (#!/bin/sh), and has a - sufficient set of builtins to do what is needed. It does - not (yet) support Bourne Shell syntax. If you need - things like ``if-then-else'', ``while'', and such, use - ash or bash. If you just need a very simple and - extremely small shell, this will do the job. - - - - - sleep - - - Usage: sleep N - - - - Pause for N seconds. - - - - Example: - - - - - $ sleep 2 - [2 second delay results] - - - - - - sort - - - Usage: sort [OPTION]... [FILE]... - - - - Sort lines of text in FILE(s). - - - - Options: - - - - - -n Compare numerically - -r Reverse after sorting - - - - - Example: - - - - - $ echo -e "e\nf\nb\nd\nc\na" | sort - a - b - c - d - e - f - - - - - - swapoff - - - Usage: swapoff [OPTION] [DEVICE] - - - - Stop swapping virtual memory pages on DEVICE. - - - - Options: - - - - - -a Stop swapping on all swap devices - - - - - - swapon - - - Usage: swapon [OPTION] [DEVICE] - - - - Start swapping virtual memory pages on the given device. - - - - Options: - - - - - -a Start swapping on all swap devices - - - - - - sync - - - Usage: sync - - - - Write all buffered filesystem blocks to disk. - - - - - syslogd - - - Usage: syslogd [OPTION]... - - - - Linux system and kernel (provides klogd) logging - utility. Note that this version of syslogd/klogd ignores - /etc/syslog.conf. - - - - Options: - - - - - -m NUM Interval between MARK lines (default=20min, 0=off) - -n Run as a foreground process - -K Do not start up the klogd process - -O FILE Use an alternate log file (default=/var/log/messages) - -R HOST[:PORT] Log remotely to IP or hostname on PORT (default PORT=514/UDP) - -L Log locally as well as network logging (default is network only) - - - - - Example: - - - - - $ syslogd -R masterlog:514 - $ syslogd -R 192.168.1.1:601 - - - - - - tail - - - Usage: tail [OPTION] [FILE]... - - - - Print last 10 lines of each FILE to standard output. - With more than one FILE, precede each with a header - giving the file name. With no FILE, or when FILE is -, - read stdin. - - - - Options: - - - - - -n NUM Print last NUM lines instead of last 10 - -f Output data as the file grows. This version - of 'tail -f' supports only one file at a time. - - - - - Example: - - - - - $ tail -n 1 /etc/resolv.conf - nameserver 10.0.0.1 - - - - - - tar - - - Usage: tar [MODE] [OPTION] [FILE]... - - - - - - - - MODE may be chosen from - - - - - c Create - x Extract - t List - - - - - Options: - - - - - f FILE Use FILE for tarfile (or stdin if '-') - O Extract to stdout - exclude FILE File to exclude - v List files processed - - - - - Example: - - - - - $ zcat /tmp/tarball.tar.gz | tar -xf - - $ tar -cf /tmp/tarball.tar /usr/local - - - - - - tee - - - Usage: tee [OPTION]... [FILE]... - - - - Copy stdin to FILE(s), and also to stdout. - - - - Options: - - - - - -a Append to the given FILEs, do not overwrite - - - - - Example: - - - - - $ echo "Hello" | tee /tmp/foo - Hello - $ cat /tmp/foo - Hello - - - - - - telnet - - - Usage: telnet HOST [PORT] - - - - Establish interactive communication with another - computer over a network using the TELNET protocol. - - - - - test, [ - - - Usage: test EXPRESSION - - - - or: [ EXPRESSION ] - - - - Check file types and compare values returning an exit - code determined by the value of EXPRESSION. - - - - Example: - - - - - $ test 1 -eq 2 - $ echo $? - 1 - $ test 1 -eq 1 - $ echo $? - 0 - $ [ -d /etc ] - $ echo $? - 0 - $ [ -d /junk ] - $ echo $? - 1 - - - - - - touch - - - Usage: touch [OPTION]... FILE... - - - - Update the last-modified date on (or create) FILE(s). - - - - Options: - - - - - -c Do not create files - - - - - Example: - - - - - $ ls -l /tmp/foo - /bin/ls: /tmp/foo: No such file or directory - $ touch /tmp/foo - $ ls -l /tmp/foo - -rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo - - - - - - tr - - - Usage: tr [OPTION]... STRING1 [STRING2] - - - - Translate, squeeze, and/or delete characters from stdin, - writing to stdout. - - - - Options: - - - - - -c Take complement of STRING1 - -d Delete input characters coded STRING1 - -s Squeeze multiple output characters of STRING2 into one character - - - - - Example: - - - - - $ echo "gdkkn vnqkc" | tr [a-y] [b-z] - hello world - - - - - - true - - - Usage: true - - - - Return an exit code of TRUE (1). - - - - Example: - - - - - $ true - $ echo $? - 0 - - - - - - tty - - - Usage: tty - - - - Print the file name of the terminal connected to stdin. - - - - Options: - - - - - -s Print nothing, only return an exit status - - - - - Example: - - - - - $ tty - /dev/tty2 - - - - - - umount - - - Usage: umount [OPTION]... DEVICE|DIRECTORY - - - - - - - - Options: - - - - - -a Unmount all file systems - -r Try to remount devices as read-only if mount is busy - -f Force filesystem umount (i.e., unreachable NFS server) - -l Do not free loop device (if a loop device has been used) - - - - - Example: - - - - - $ umount /dev/hdc1 - - - - - - uname - - - Usage: uname [OPTION]... - - - - Print certain system information. With no OPTION, same - as -s. - - - - Options: - - - - - -a Print all information - -m Print the machine (hardware) type - -n Print the machine's network node hostname - -r Print the operating system release - -s Print the operating system name - -p Print the host processor type - -v Print the operating system version - - - - - Example: - - - - - $ uname -a - Linux debian 2.2.15pre13 #5 Tue Mar 14 16:03:50 MST 2000 i686 unknown - - - - - - uniq - - - Usage: uniq [INPUT [OUTPUT]] - - - - Discard all but one of successive identical lines from - INPUT (or stdin), writing to OUTPUT (or stdout). - - - - Options: - - - - - -c prefix lines by the number of occurrences - -d only print duplicate lines - -u only print unique lines - - - - - Example: - - - - - $ echo -e "a\na\nb\nc\nc\na" | sort | uniq - a - b - c - - - - - - unix2dos - - - Usage: unix2dos < unixfile > dosfile - - - - Converts a text file from unix format to dos format. - - - - - - unrpm - - - Usage: unrpm < package.rpm | gzip -d | cpio -idmuv - - - - Extracts an rpm archive. - - - - - - update - - - Usage: update [OPTION]... - - - - Periodically flush filesystem buffers. - - - - Options: - - - - - -S Force use of sync(2) instead of flushing - -s SECS Call sync this often (default 30) - -f SECS Flush some buffers this often (default 5) - - - - - - uptime - - - Usage: uptime - - - - Display how long the system has been running since boot. - - - - Example: - - - - - $ uptime - 1:55pm up 2:30, load average: 0.09, 0.04, 0.00 - - - - - - usleep - - - Usage: usleep N - - - - Pause for N microseconds. - - - - Example: - - - - - $ usleep 1000000 - [pauses for 1 second] - - - - - - uudecode - - - Usage: uudecode [OPTION] [FILE] - - - - Uudecode a uuencoded file. - - - - Options: - - - - - -o FILE Direct output to FILE - - - - - Example: - - - - - $ uudecode -o busybox busybox.uu - $ ls -l busybox - -rwxr-xr-x 1 ams ams 245264 Jun 7 21:35 busybox - - - - - - uuencode - - - Usage: uuencode [OPTION] [INFILE] OUTFILE - - - - Uuencode a file. - - - - Options: - - - - - -m Use base64 encoding as of RFC1521 - - - - - Example: - - - - - $ uuencode busybox busybox - begin 755 busybox - M?T5,1@$!`0````````````(``P`!````L+@$"#0```!0N@,``````#0`(``& - ..... - $ uudecode busybox busybox > busybox.uu - $ - - - - - - watchdog - - - Usage: watchdog device - - - - Periodically writes to watchdog device B. - - - - - wc - - - Usage: wc [OPTION]... [FILE]... - - - - Print line, word, and byte counts for each FILE, and a - total line if more than one FILE is specified. With no - FILE, read stdin. - - - - Options: - - - - - -c Print the byte counts - -l Print the newline counts - -L Print the length of the longest line - -w Print the word counts - - - - - Example: - - - - - $ wc /etc/passwd - 31 46 1365 /etc/passwd - - - - - - which - - - Usage: which [COMMAND]... - - - - Locate COMMAND(s). - - - - Example: - - - - - $ which login - /bin/login - - - - - - whoami - - - Usage: whoami - - - - Print the user name associated with the current - effective user id. - - - - Example: - - - - - $ whoami - andersen - - - - - - xargs - - - Usage: xargs [OPTIONS] [COMMAND] [ARGS...] - - - - Executes COMMAND on every item given by standard input. - - - - Options: - - - - - -t Print the command just before it is run - - - - - - Example: - - - - - $ ls | xargs gzip - $ find . -name '*.c' -print | xargs rm - - - - - - yes - - - Usage: yes [STRING]... - - - - Repeatedly output a line with all specified STRING(s), - or `y'. - - - - - zcat - - - Usage: zcat [OPTION]... FILE - - - - Uncompress FILE (or stdin if FILE is '-') to stdout. - - - - Options: - - - - - -t Test compressed file integrity - - - - - Example: - - - - - - - - - - - LIBC NSS - - - GNU Libc uses the Name Service Switch (NSS) to configure the - behavior of the C library for the local environment, and to - configure how it reads system data, such as passwords and group - information. BusyBox has made it Policy that it will never use - NSS, and will never use libc calls that make use of NSS. This - allows you to run an embedded system without the need for - installing an /etc/nsswitch.conf file and without /lib/libnss_* - libraries installed. - - - - If you are using a system that is using a remote LDAP server for - authentication via GNU libc NSS, and you want to use BusyBox, - then you will need to adjust the BusyBox source. Chances are - though, that if you have enough space to install of that stuff - on your system, then you probably want the full GNU utilities. - - - - - SEE ALSO - - - textutils(1), - shellutils(1), - etc... - - - - - MAINTAINER - - - Erik Andersen <andersee@debian.org> <andersen@lineo.com> - - - - - AUTHORS - - - The following people have made significant contributions to - BusyBox -- whether they know it or not. - - - - Erik Andersen <andersee@debian.org> - - - - Edward Betts <edward@debian.org> - - - - John Beppu <beppu@lineo.com> - - - - Brian Candler <B.Candler@pobox.com> - - - - Randolph Chung <tausq@debian.org> - - - - Dave Cinege <dcinege@psychosis.com> - - - - Karl M. Hegbloom <karlheg@debian.org> - - - - Daniel Jacobowitz <dan@debian.org> - - - - Matt Kraai <kraai@alumni.carnegiemellon.edu> - - - - John Lombardo <john@deltanet.com> - - - - Glenn McGrath <bug1@netconnect.com.au> - - - - Bruce Perens <bruce@perens.com> - - - - Chip Rosenthal <chip@unicom.com>, <crosenth@covad.com> - - - - Pavel Roskin <proski@gnu.org> - - - - Gyepi Sam <gyepi@praxis-sw.com> - - - - Linus Torvalds <torvalds@transmeta.com> - - - - Mark Whitley <markw@lineo.com> - - - - Charles P. Wright <cpwright@villagenet.com> - - - - Enrique Zanardi <ezanardi@ull.es> - - - - - diff --git a/busybox/docs/busybox_footer.pod b/busybox/docs/busybox_footer.pod deleted file mode 100644 index 2ab4e166e..000000000 --- a/busybox/docs/busybox_footer.pod +++ /dev/null @@ -1,169 +0,0 @@ -=back - -=head1 LIBC NSS - -GNU Libc uses the Name Service Switch (NSS) to configure the behavior of the C -library for the local environment, and to configure how it reads system data, -such as passwords and group information. BusyBox has made it Policy that it -will never use NSS, and will never use and libc calls that make use of NSS. -This allows you to run an embedded system without the need for installing an -/etc/nsswitch.conf file and without and /lib/libnss_* libraries installed. - -If you are using a system that is using a remote LDAP server for authentication -via GNU libc NSS, and you want to use BusyBox, then you will need to adjust the -BusyBox source. Chances are though, that if you have enough space to install -of that stuff on your system, then you probably want the full GNU utilities. - -=head1 SEE ALSO - -textutils(1), shellutils(1), etc... - -=head1 MAINTAINER - -Erik Andersen - -=head1 AUTHORS - -The following people have contributed code to BusyBox whether -they know it or not. - - -=for html
- -Erik Andersen , - - Tons of new stuff, major rewrite of most of the - core apps, tons of new apps as noted in header files. - -=for html
- -John Beppu - - du, head, nslookup, sort, tee, uniq (so Kraai could rewrite them ;-), - documentation - -=for html
- -Edward Betts - - expr, hostid, logname, tty, wc, whoami, yes - -=for html
- -Brian Candler - - tiny-ls(ls) - -=for html
- -Randolph Chung - - fbset, ping, hostname, and mkfifo - -=for html
- -Dave Cinege - - more(v2), makedevs, dutmp, modularization, auto links file, - various fixes, Linux Router Project maintenance - -=for html
- -Larry Doolittle - - various fixes, shell rewrite - -=for html
- -Karl M. Hegbloom - - cp_mv.c, the test suite, various fixes to utility.c, &c. - -=for html
- -Sterling Huxley - - vi (!!!) - -=for html
- -Daniel Jacobowitz - - mktemp.c - -=for html
- -Matt Kraai - - documentation, bugfixes - -=for html
- -John Lombardo - - dirname, tr - -=for html
- -Glenn McGrath - - ar.c - -=for html
- -Vladimir Oleynik - - cmdedit, stty-port, locale, various fixes - and irreconcilable critic of everything not perfect. - -=for html
- -Bruce Perens - - Original author of BusyBox. His code is still in many apps. - -=for html
- -Chip Rosenthal , - - wget - Contributed by permission of Covad Communications - -=for html
- -Pavel Roskin - - Lots of bugs fixes and patches. - -=for html
- -Gyepi Sam - - Remote logging feature for syslogd - -=for html
- -Linus Torvalds - - mkswap, fsck.minix, mkfs.minix - -=for html
- -Mark Whitley - - sed remix, bug fixes, style-guide, etc. - -=for html
- -Charles P. Wright - - gzip, mini-netcat(nc) - -=for html
- -Enrique Zanardi - - tarcat (since removed), loadkmap, various fixes, Debian maintenance - -=cut - -# $Id: busybox_footer.pod,v 1.4 2001/04/17 17:09:34 beppu Exp $ diff --git a/busybox/docs/busybox_header.pod b/busybox/docs/busybox_header.pod deleted file mode 100644 index b80b63143..000000000 --- a/busybox/docs/busybox_header.pod +++ /dev/null @@ -1,73 +0,0 @@ -# vi: set sw=4 ts=4: - -=head1 NAME - -BusyBox - The Swiss Army Knife of Embedded Linux - -=head1 SYNTAX - - BusyBox [arguments...] # or - - [arguments...] # if symlinked - -=head1 DESCRIPTION - -BusyBox combines tiny versions of many common UNIX utilities into a single -small executable. It provides minimalist replacements for most of the utilities -you usually find in fileutils, shellutils, findutils, textutils, grep, gzip, -tar, etc. BusyBox provides a fairly complete POSIX environment for any small -or embedded system. The utilities in BusyBox generally have fewer options than -their full-featured GNU cousins; however, the options that are included provide -the expected functionality and behave very much like their GNU counterparts. - -BusyBox has been written with size-optimization and limited resources in mind. -It is also extremely modular so you can easily include or exclude commands (or -features) at compile time. This makes it easy to customize your embedded -systems. To create a working system, just add a kernel, a shell (such as ash), -and an editor (such as elvis-tiny or ae). - -=head1 USAGE - -When you create a link to BusyBox for the function you wish to use, when BusyBox -is called using that link it will behave as if the command itself has been invoked. - -For example, entering - - ln -s ./BusyBox ls - ./ls - -will cause BusyBox to behave as 'ls' (if the 'ls' command has been compiled -into BusyBox). - -You can also invoke BusyBox by issuing the command as an argument on the -command line. For example, entering - - ./BusyBox ls - -will also cause BusyBox to behave as 'ls'. - -=head1 COMMON OPTIONS - -Most BusyBox commands support the B<-h> option to provide a -terse runtime description of their behavior. - -=head1 COMMANDS - -Currently defined functions include: - -adjtimex, ar, basename, busybox, cat, chgrp, chmod, chown, chroot, chvt, clear, -cmp, cp, cpio, cut, date, dc, dd, deallocvt, df, dirname, dmesg, dos2unix, dpkg, -dpkg-deb, du, dumpkmap, dutmp, echo, expr, false, fbset, fdflush, find, free, -freeramdisk, fsck.minix, getopt, grep, gunzip, gzip, halt, head, hostid, -hostname, id, ifconfig, init, insmod, kill, killall, klogd, length, ln, -loadacm, loadfont, loadkmap, logger, logname, ls, lsmod, makedevs, md5sum, -mkdir, mkfifo, mkfs.minix, mknod, mkswap, mktemp, more, mount, mt, mv, nc, -nslookup, ping, pivot_root, poweroff, printf, ps, pwd, rdate, readlink, reboot, -renice, reset, rm, rmdir, rmmod, route, rpm2cpio, sed, setkeycodes, -sh, sleep, sort, stty, swapoff, swapon, sync, syslogd, tail, tar, tee, telnet, -test, tftp, touch, tr, true, tty, umount, uname, uniq, unix2dos, update, uptime, -usleep, uudecode, uuencode, watchdog, wc, wget, which, whoami, xargs, yes, zcat, -[ - -=over 4 - diff --git a/busybox/docs/contributing.txt b/busybox/docs/contributing.txt deleted file mode 100644 index 2e0049289..000000000 --- a/busybox/docs/contributing.txt +++ /dev/null @@ -1,476 +0,0 @@ -Contributing To Busybox -======================= - -This document describes what you need to do to contribute to Busybox, where -you can help, guidelines on testing, and how to submit a well-formed patch -that is more likely to be accepted. - -The Busybox home page is at: http://busybox.lineo.com - - - -Pre-Contribution Checklist --------------------------- - -So you want to contribute to Busybox, eh? Great, wonderful, glad you want to -help. However, before you dive in, headlong and hotfoot, there are some things -you need to do: - - -Checkout the Latest Code from CVS -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This is a necessary first step. Please do not try to work with the last -released version, as there is a good chance that somebody has already fixed -the bug you found. Somebody might have even added the feature you had in mind. -Don't make your work obsolete before you start! - -For information on how to check out Busybox from CVS, please look at the -following links: - - http://oss.lineo.com/cvs_anon.html - http://oss.lineo.com/cvs_howto.html - - -Read the Mailing List -~~~~~~~~~~~~~~~~~~~~~ - -No one is required to read the entire archives of the mailing list, but you -should at least read up on what people have been talking about lately. If -you've recently discovered a problem, chances are somebody else has too. If -you're the first to discover a problem, post a message and let the rest of us -know. - -Archives can be found here: - - http://opensource.lineo.com/lists/busybox/ - -If you have a serious interest in Busybox, i.e., you are using it day-to-day or -as part of an embedded project, it would be a good idea to join the mailing -list. - -A web-based sign-up form can be found here: - - http://opensource.lineo.com/mailman/listinfo/busybox - - -Coordinate with the Applet Maintainer -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Some (not all) of the applets in Busybox are "owned" by a maintainer who has -put significant effort into it and is probably more familiar with it than -others. To find the maintainer of an applet, look at the top of the .c file -for a name following the word 'Copyright' or 'Written by' or 'Maintainer'. - -Before plunging ahead, it's a good idea to send a message to the mailing list -that says: "Hey, I was thinking about adding the 'transmogrify' feature to the -'foo' applet. Would this be useful? Is anyone else working on it?" You might -want to CC the maintainer (if any) with your question. - - - -Areas Where You Can Help ------------------------- - -Busybox can always use improvement! If you're looking for ways to help, there -there are a variety of areas where you could help. - - -What Busybox Doesn't Need -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Before listing the areas where you _can_ help, it's worthwhile to mention the -areas where you shouldn't bother. While Busybox strives to be the "Swiss Army -Knife" of embedded Linux, there are some applets that will not be accepted: - - - Any filesystem manipulation tools: Busybox is filesystem independent and - we do not want to start adding mkfs/fsck tools for every (or any) - filesystem under the sun. (fsck_minix.c and mkfs_minix.c are living on - borrowed time.) There are far too many of these tools out there. Use - the upstream version. Not everything has to be part of Busybox. - - - Any partitioning tools: Partitioning a device is typically done once and - only once, and tools which do this generally do not need to reside on the - target device (esp a flash device). If you need a partitioning tool, grab - one (such as fdisk, sfdisk, or cfdisk from util-linux) and use that, but - don't try to merge it into busybox. These are nasty and complex and we - don't want to maintain them. - - - Any disk, device, or media-specific tools: Use the -utils or -tools package - that was designed for your device; don't try to shoehorn them into Busybox. - - - Any architecture specific tools: Busybox is (or should be) architecture - independent. Do not send us tools that cannot be used across multiple - platforms / arches. - - - Any daemons that are not essential to basic system operation. To date, only - syslogd and klogd meet this requirement. We do not need a web server, an - ftp daemon, a dhcp server, a mail transport agent or a dns resolver. If you - need one of those, you are welcome to ask the folks on the mailing list for - recommendations, but please don't bloat up Busybox with any of these. - - -Bug Reporting -~~~~~~~~~~~~~ - -If you find a bug in Busybox, you can send a bug report to our bug tracking -system (homepage: http://bugs.lineo.com). Instructions on how to send a bug -report to the tracking system can be found at: - - http://bugs.lineo.com/Reporting.html - -The README file that comes with Busybox also describes how to submit a bug. - -A well-written bug report should include a transcript of a shell session that -demonstrates the bad behavior and enables anyone else to duplicate the bug on -their own machine. The following is such an example: - - When I execute Busybox 'date' it produces unexpected results. - - This is using GNU date: - $ date - Wed Mar 21 14:19:41 MST 2001 - - This is using Busybox date: - $ date - codswaddle - - -Bug Triage -~~~~~~~~~~ - -Validating and confirming bugs is nearly as important as reporting them in the -first place. It is valuable to know if a bug can be duplicated on a different -machine, on a different filesystem, on a different architecture, with a -different C library, and so forth. - -To see a listing of all the bugs currently filed against Busybox, look here: - - http://bugs.lineo.com/db/pa/lbusybox.html - -If you have comments to add to a bug (can / can't duplicate, think a bug -should be closed / reopened), please send it to [bugnumber]@bugs.lineo.com. -The message you send will automatically be forwarded to the mailing list for -all to see. - - -Write Documentation -~~~~~~~~~~~~~~~~~~~ - -Chances are, documentation in Busybox is either missing or needs improvement. -Either way, help is welcome. - -Work is being done to automatically generate documentation from sources, -especially from the usage.h file. If you want to correct the documentation, -please make changes to the pre-generation parts, rather than the generated -documentation. [More to come on this later...] - -It is preferred that modifications to documentation be submitted in patch -format (more on this below), but we're a little more lenient when it comes to -docs. You could, for example, just say "after the listing of the mount -options, the following example would be helpful..." - - -Consult Existing Sources -~~~~~~~~~~~~~~~~~~~~~~~~ - -For a quick listing of "needs work" spots in the sources, cd into the Busybox -directory and run the following: - - for i in TODO FIXME XXX; do grep $i *.[ch]; done - -This will show all of the trouble spots or 'questionable' code. Pick a spot, -any spot, these are all invitations for you to contribute. - - -Consult The Bug-Tracking System -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Head to: http://bugs.lineo.com/db/pa/lBusybox.html and look at the bugs on -there. Pick one you think you can fix, and fix it. If it's a wishlist item and -someone's requesting a new feature, take a stab at adding it. Everything -previously said about "reading the mailing list" and "coordinating with the -applet maintainer" still applies. - - -Add a New Applet -~~~~~~~~~~~~~~~~ - -If you want to add a new applet to Busybox, we'd love to see it. However, -before you write any code, please ask beforehand on the mailing list something -like "Do you think applet 'foo' would be useful in Busybox?" or "Would you -guys accept applet 'foo' into Busybox if I were to write it?" If the answer is -"no" by the folks on the mailing list, then you've saved yourself some time. -Conversely, you could get some positive responses from folks who might be -interested in helping you implement it, or can recommend the best approach. -Perhaps most importantly, this is your way of calling "dibs" on something and -avoiding duplication of effort. - -Also, before you write a line of code, please read the 'new-applet-HOWTO.txt' -file in the docs/ directory. - - -Janitorial Work -~~~~~~~~~~~~~~~ - -These are dirty jobs, but somebody's gotta do 'em. - - - Converting applets to use getopt() for option processing. Type 'grep -L - getopt *.c' to get a listing of the applets that currently don't use - getopt. If a .c file processes no options, it should have a line that - reads: /* no options, no getopt */ somewhere in the file. - - - Replace any "naked" calls to malloc, calloc, realloc, str[n]dup, fopen with - the x* equivalents found in utility.c. - - - Security audits: - http://www.securityfocus.com/frames/?content=/forums/secprog/secure-programming.html - - - Synthetic code removal: http://www.perl.com/pub/2000/06/commify.html - This - is very Perl-specific, but the advice given in here applies equally well to - C. - - - C library funciton use audits: Verifying that functions are being used - properly (called with the right args), replacing unsafe library functions - with safer versions, making sure return codes are being checked, etc. - - - Where appropriate, replace preprocessor defined macros and values with - compile-time equivalents. - - - Style guide compliance. See: docs/style-guide.txt - - - Add testcases to tests/testcases. - - - Makefile improvements: - http://www.canb.auug.org.au/~millerp/rmch/recu-make-cons-harm.html - (I think the recursive problems are pretty much taken care of at this point, non?) - - - "Ten Commandments" compliance: (this is a "maybe", certainly not as - important as any of the previous items.) - http://web.onetelnet.ch/~twolf/tw/c/ten_commandments.html - -Other useful links: - - - the comp.lang.c FAQ: http://web.onetelnet.ch/~twolf/tw/c/index.html#Sources - - - -Submitting Patches To Busybox ------------------------------ - -Here are some guidelines on how to submit a patch to Busybox. - - -Making A Patch -~~~~~~~~~~~~~~ - -If you've got anonymous CVS access set up, making a patch is simple. Just make -sure you're in the busybox/ directory and type 'cvs diff -bwu > mychanges.patch'. -You can send the resulting .patch file to the mailing list with a description -of what it does. (But not before you test it! See the next section for some -guidelines.) It is preferred that patches be sent as attachments, but it is -not required. - -Also, feel free to help test other people's patches and reply to them with -comments. You can apply a patch by saving it into your busybox/ directory and -typing 'patch < mychanges.patch'. Then you can recompile, see if it runs, test -if it works as advertised, and post your findings to the mailing list. - -NOTE: Please do not include extraneous or irrelevant changes in your patches. -Please do not try to "bundle" two patches together into one. Make single, -discreet changes on a per-patch basis. Sometimes you need to make a patch that -touches code in many places, but these kind of patches are rare and should be -coordinated with a maintainer. - - -Testing Guidelines -~~~~~~~~~~~~~~~~~~ - -It's considered good form to test your new feature before you submit a patch -to the mailing list, and especially before you commit a change to CVS. Here -are some guidelines on how to test your changes. - - - Always test Busybox applets against GNU counterparts and make sure the - behavior / output is identical between the two. - - - Try several different permutations and combinations of the features you're - adding (i.e., different combinations of command-line switches) and make sure - they all work; make sure one feature does not interfere with another. - - - Make sure you test compiling against the source both with the feature - turned on and turned off in Config.h and make sure Busybox compiles cleanly - both ways. - - - Run the multibuild.pl script in the tests directory and make sure - everything checks out OK. (Do this from within the busybox/ directory by - typing: 'tests/multibuild.pl'.) - - -Making Sure Your Patch Doesn't Get Lost -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If you don't want your patch to be lost or forgotten, send it to the bug -tracking system (http://bugs.lineo.com). You do this by emailing your patch in -a message to submit@bugs.lineo.com with a subject line something like this: - - [PATCH] - Adds "transmogrify" feature to "foo" - -In the body, you should have a pseudo-header that looks like the following: - - Package: busybox - Version: v0.50pre (or whatever the current version is) - Severity: wishlist - -The remainder of the body should read along these lines: - - This patch adds the "transmogrify" feature to the "foo" applet. I have - tested this on [arch] system(s) and it works. I have tested it against the - GNU counterparts and the outputs are identical. I have run the scripts in - the 'tests' directory and nothing breaks. - -Detailed instructions on how to submit a bug to the tracking system are at: - - http://bugs.lineo.com/Reporting.html - -If you have a patch that will fix and close a reported bug, please send a -message to [bugnumber]@bugs.lineo.com with your patch attached. It will catch -people's attention if you have a subject line like the following: - - [PATCH INCLUDED] - Fix attached, please apply and close this bug - - - -Improving Your Chances of Patch Acceptance ------------------------------------------- - -Even after you send a brilliant patch to the mailing list, sometimes it can go -unnoticed, un-replied-to, and sometimes (sigh) even lost. This is an -unfortunate fact of life, but there are steps you can take to help your patch -get noticed and convince a maintainer that it should be added: - - -Be Succinct -~~~~~~~~~~~ - -A patch that includes small, isolated, obvious changes is more likely to be -accepted than a patch that touches code in lots of different places or makes -sweeping, dubious changes. - - -Back It Up -~~~~~~~~~~ - -Hard facts on why your patch is better than the existing code will go a long -way toward convincing maintainers that your patch should be included. -Specifically, patches are more likely to be accepted if they are provably more -correct, smaller, faster, simpler, or more maintainable than the existing -code. - -Conversely, any patch that is supported with nothing more than "I think this -would be cool" or "this patch is good because I say it is and I've got a Phd -in Computer Science" will likely be ignored. - - -Follow The Style Guide -~~~~~~~~~~~~~~~~~~~~~~ - -It's considered good form to abide by the established coding style used in a -project; Busybox is no exception. We have gone so far as to delineate the -"elements of Busybox style" in the file docs/style-guide.txt. Please follow -them. - - -Work With Someone Else -~~~~~~~~~~~~~~~~~~~~~~ - -Working on a patch in isolation is less effective than working with someone -else for a variety of reasons. If another Busybox user is interested in what -you're doing, then it's two (or more) voices instead of one that can petition -for inclusion of the patch. You'll also have more people that can test your -changes, or even offer suggestions on better approaches you could take. - -Getting other folks interested follows as a natural course if you've received -responses from queries to applet maintainer or positive responses from folks -on the mailing list. - -We've made strident efforts to put a useful "collaboration" infrastructure in -place in the form of mailing lists, the bug tracking system, and CVS. Please -use these resources. - - -Send Patches to the Bug Tracking System -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This was mentioned above in the "Making Sure Your Patch Doesn't Get Lost" -section, but it is worth mentioning again. A patch sent to the mailing list -might be unnoticed and forgotten. A patch sent to the bug tracking system will -be stored and closely connected to the bug it fixes. - - -Be Polite -~~~~~~~~~ - -The old saying "You'll catch more flies with honey than you will with vinegar" -applies when submitting patches to the mailing list for approval. The way you -present your patch is sometimes just as important as the actual patch itself -(if not more so). Being rude to the maintainers is not an effective way to -convince them that your patch should be included; it will likely have the -opposite effect. - - - -Committing Changes to CVS -------------------------- - -If you submit several patches that demonstrate that you are a skilled and wise -coder, you may be invited to become a committer, thus enabling you to commit -changes directly to CVS. This is nice because you don't have to wait for -someone else to commit your change for you, you can just do it yourself. - -But note that this is a priviledge that comes with some responsibilities. You -should test your changes before you commit them. You should also talk to an -applet maintainer before you make any kind of sweeping changes to somebody -else's code. Big changes should still go to the mailing list first. Remember, -being wise, polite, and discreet is more important than being clever. - - -When To Commit -~~~~~~~~~~~~~~ - -Generally, you should feel free to commit a change if: - - - Your changes are small and don't touch many files - - You are fixing a bug - - Somebody has told you that it's okay - - It's obviously the Right Thing - -The more of the above are true, the better it is to just commit a change -directly to CVS. - - -When Not To Commit -~~~~~~~~~~~~~~~~~~ - -Even if you have commit rights, you should probably still post a patch to the -mailing list if: - - - Your changes are broad and touch many different files - - You are adding a feature - - Your changes are speculative or experimental (i.e., trying a new algorithm) - - You are not the maintainer and your changes make the maintainer cringe - -The more of the above are true, the better it is to post a patch to the -mailing list instead of committing. - - - -Final Words ------------ - -If all of this seems complicated, don't panic, it's really not that tough. If -you're having difficulty following some of the steps outlined in this -document don't worry, the folks on the Busybox mailing list are a fairly -good-natured bunch and will work with you to help get your patches into shape -or help you make contributions. - - diff --git a/busybox/docs/new-applet-HOWTO.txt b/busybox/docs/new-applet-HOWTO.txt deleted file mode 100644 index 1f5c3ebd5..000000000 --- a/busybox/docs/new-applet-HOWTO.txt +++ /dev/null @@ -1,138 +0,0 @@ -How to Add a New Applet to BusyBox -================================== - -This document details the steps you must take to add a new applet to BusyBox. - -Credits: -Matt Kraai - initial writeup -Mark Whitley - the remix - - -Initial Write -------------- - -First, write your applet. Be sure to include copyright information at the -top, such as who you stole the code from and so forth. Also include the -mini-GPL boilerplate. Be sure to name the main function _main instead -of main. And be sure to put it in .c. For a new applet mu, here is -the code that would go in mu.c: - -----begin example code------ - -/* vi: set sw=4 ts=4: */ -/* - * Mini mu implementation for busybox - * - * - * Copyright (C) [YEAR] by [YOUR NAME] - * - * 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 "busybox.h" - -int mu_main(int argc, char **argv) -{ - int fd; - char mu; - - if ((fd = open("/dev/random", O_RDONLY)) < 0) - perror_msg_and_die("/dev/random"); - - if ((n = safe_read(fd, &mu, 1)) < 1) - perror_msg_and_die("/dev/random"); - - return mu; -} - -----end example code------ - - -Coding Style ------------- - -Before you submit your applet for inclusion in BusyBox, (or better yet, before -you _write_ your applet) please read through the style guide in the docs -directory and make your program compliant. - - -Some Words on libbb -------------------- - -As you are writing your applet, please be aware of the body of pre-existing -useful functions in libbb. Use these instead of reinventing the wheel. - -Additionally, if you have any useful, general-purpose functions in your -program that could be useful in another program, consider putting them in -libbb. - - -Usage String(s) ---------------- - -Next, add usage information for you applet to usage.h. This should look like -the following: - - #define mu_trivial_usage \ - "-[abcde] FILES" - #define mu_full_usage \ - "Returns an indeterminate value.\n\n" \ - "Options:\n" \ - "\t-a\t\tfirst function\n" \ - "\t-b\t\tsecond function\n" \ - -If your program supports flags, the flags should be mentioned on the first -line (-[abcde]) and a detailed description of each flag should go in the -mu_full_usage section, one flag per line. (Numerous examples of this -currently exist in usage.h.) - - -Header Files ------------- - -Next, add an entry to applets.h. Be *sure* to keep the list in alphabetical -order, or else it will break the binary-search lookup algorithm in busybox.c -and the Gods of BusyBox smite you. Yea, verily: - - /* all programs above here are alphabetically "less than" 'mu' */ - #ifdef BB_MU - APPLET("mu", mu_main, _BB_DIR_USR_BIN, mu_usage) - #endif - /* all programs below here are alphabetically "greater than" 'mu' */ - - -Finally, add a define for your applet to Config.h: - - #define BB_MU - - -Documentation -------------- - -If you're feeling especially nice, you should also document your applet in the -docs directory (but nobody ever does that). - - -The Grand Announcement ----------------------- - -Then create a diff -urN of the files you added (.c, usage.c, -applets.h, Config.h) and send it to the mailing list: -busybox@opensource.lineo.com. Sending patches as attachments is preferred, but -not required. - - diff --git a/busybox/docs/style-guide.txt b/busybox/docs/style-guide.txt deleted file mode 100644 index c71f1e609..000000000 --- a/busybox/docs/style-guide.txt +++ /dev/null @@ -1,680 +0,0 @@ -Busybox Style Guide -=================== - -This document describes the coding style conventions used in Busybox. If you -add a new file to Busybox or are editing an existing file, please format your -code according to this style. If you are the maintainer of a file that does -not follow these guidelines, please -- at your own convenience -- modify the -file(s) you maintain to bring them into conformance with this style guide. -Please note that this is a low priority task. - -To help you format the whitespace of your programs, an ".indent.pro" file is -included in the main Busybox source directory that contains option flags to -format code as per this style guide. This way you can run GNU indent on your -files by typing 'indent myfile.c myfile.h' and it will magically apply all the -right formatting rules to your file. Please _do_not_ run this on all the files -in the directory, just your own. - - - -Declaration Order ------------------ - -Here is the order in which code should be laid out in a file: - - - commented program name and one-line description - - commented author name and email address(es) - - commented GPL boilerplate - - commented longer description / notes for the program (if needed) - - #includes of .h files with angle brackets (<>) around them - - #includes of .h files with quotes ("") around them - - #defines (if any, note the section below titled "Avoid the Preprocessor") - - const and global variables - - function declarations (if necessary) - - function implementations - - - -Whitespace and Formatting -------------------------- - -This is everybody's favorite flame topic so let's get it out of the way right -up front. - - -Tabs vs. Spaces in Line Indentation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The preference in Busybox is to indent lines with tabs. Do not indent lines -with spaces and do not indents lines using a mixture of tabs and spaces. (The -indentation style in the Apache and Postfix source does this sort of thing: -\s\s\s\sif (expr) {\n\tstmt; --ick.) The only exception to this rule is -multi-line comments that use an asterisk at the beginning of each line, i.e.: - - /t/* - /t * This is a block comment. - /t * Note that it has multiple lines - /t * and that the beginning of each line has a tab plus a space - /t * except for the opening '/*' line where the slash - /t * is used instead of a space. - /t */ - -Furthermore, The preference is that tabs be set to display at four spaces -wide, but the beauty of using only tabs (and not spaces) at the beginning of -lines is that you can set your editor to display tabs at *whatever* number of -spaces is desired and the code will still look fine. - - -Operator Spacing -~~~~~~~~~~~~~~~~ - -Put spaces between terms and operators. Example: - - Don't do this: - - for(i=0;i 0) - - -Bracket Spacing -~~~~~~~~~~~~~~~ - -If an opening bracket starts a function, it should be on the -next line with no spacing before it. However, if a bracket follows an opening -control block, it should be on the same line with a single space (not a tab) -between it and the opening control block statement. Examples: - - Don't do this: - - while (!done) - { - - do - { - - Don't do this either: - - while (!done){ - - do{ - - And for heaven's sake, don't do this: - - while (!done) - { - - do - { - - Do this instead: - - while (!done) { - - do { - - -Spacing around Parentheses -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Put a space between C keywords and left parens, but not between function names -and the left paren that starts it's parameter list (whether it is being -declared or called). Examples: - - Don't do this: - - while(foo) { - for(i = 0; i < n; i++) { - - Do this instead: - - while (foo) { - for (i = 0; i < n; i++) { - - But do functions like this: - - static int my_func(int foo, char bar) - ... - baz = my_func(1, 2); - -Also, don't put a space between the left paren and the first term, nor between -the last arg and the right paren. - - Don't do this: - - if ( x < 1 ) - strcmp( thisstr, thatstr ) - - Do this instead: - - if (x < 1) - strcmp(thisstr, thatstr) - - -Cuddled Elses -~~~~~~~~~~~~~ - -Also, please "cuddle" your else statements by putting the else keyword on the -same line after the right bracket that closes an 'if' statement. - - Don't do this: - - if (foo) { - stmt; - } - else { - stmt; - } - - Do this instead: - - if (foo) { - stmt; - } else { - stmt; - } - -The exception to this rule is if you want to include a comment before the else -block. Example: - - if (foo) { - stmts... - } - /* otherwise, we're just kidding ourselves, so re-frob the input */ - else { - other_stmts... - } - - - -Variable and Function Names ---------------------------- - -Use the K&R style with names in all lower-case and underscores occasionally -used to separate words (e.g., "variable_name" and "numchars" are both -acceptable). Using underscores makes variable and function names more readable -because it looks like whitespace; using lower-case is easy on the eyes. - - Frowned upon: - - hitList - TotalChars - szFileName - pf_Nfol_TriState - - Preferred: - - hit_list - total_chars - file_name - sensible_name - -Exceptions: - - - Enums, macros, and constant variables are occasionally written in all - upper-case with words optionally seperatedy by underscores (i.e. FIFOTYPE, - ISBLKDEV()). - - - Nobody is going to get mad at you for using 'pvar' as the name of a - variable that is a pointer to 'var'. - - -Converting to K&R -~~~~~~~~~~~~~~~~~ - -The Busybox codebase is very much a mixture of code gathered from a variety of -sources. This explains why the current codebase contains such a hodge-podge of -different naming styles (Java, Pascal, K&R, just-plain-weird, etc.). The K&R -guideline explained above should therefore be used on new files that are added -to the repository. Furthermore, the maintainer of an existing file that uses -alternate naming conventions should, at his own convenience, convert those -names over to K&R style. Converting variable names is a very low priority -task. - -If you want to do a search-and-replace of a single variable name in different -files, you can do the following in the busybox directory: - - $ perl -pi -e 's/\bOldVar\b/new_var/g' *.[ch] - -If you want to convert all the non-K&R vars in your file all at once, follow -these steps: - - - In the busybox directory type 'scripts/mk2knr.pl files-to-convert'. This - does not do the actual conversion, rather, it generates a script called - 'convertme.pl' that shows what will be converted, giving you a chance to - review the changes beforehand. - - - Review the 'convertme.pl' script that gets generated in the busybox - directory and remove / edit any of the substitutions in there. Please - especially check for false positives (strings that should not be - converted). - - - Type './convertme.pl same-files-as-before' to perform the actual - conversion. - - - Compile and see if everything still works. - -Please be aware of changes that have cascading effects into other files. For -example, if you're changing the name of something in, say utility.c, you -should probably run 'scripts/mk2knr.pl utility.c' at first, but when you run -the 'convertme.pl' script you should run it on _all_ files like so: -'./convertme.pl *.[ch]'. - - - -Avoid The Preprocessor ----------------------- - -At best, the preprocessor is a necessary evil, helping us account for platform -and architecture differences. Using the preprocessor unnecessarily is just -plain evil. - - -The Folly of #define -~~~~~~~~~~~~~~~~~~~~ - -Use 'const var' for declaring constants. - - Don't do this: - - #define var 80 - - Do this instead, when the variable is in a header file and will be used in - several source files: - - const int var = 80; - - Or do this when the variable is used only in a single source file: - - static const int var = 80; - -Declaring variables as '[static] const' gives variables an actual type and -makes the compiler do type checking for you; the preprocessor does _no_ type -checking whatsoever, making it much more error prone. Declaring variables with -'[static] const' also makes debugging programs much easier since the value of -the variable can be easily queried and displayed. - - -The Folly of Macros -~~~~~~~~~~~~~~~~~~~ - -Use 'static inline' instead of a macro. - - Don't do this: - - #define mini_func(param1, param2) (param1 << param2) - - Do this instead: - - static inline int mini_func(int param1, param2) - { - return (param1 << param2); - } - -Static inline functions are greatly preferred over macros. They provide type -safety, have no length limitations, no formatting limitations, have an actual -return value, and under gcc they are as cheap as macros. Besides, really long -macros with backslashes at the end of each line are ugly as sin. - - -The Folly of #ifdef -~~~~~~~~~~~~~~~~~~~ - -Code cluttered with ifdefs is difficult to read and maintain. Don't do it. -Instead, put your ifdefs at the top of your .c file (or in a header), and -conditionally define 'static inline' functions, (or *maybe* macros), which are -used in the code. - - Don't do this: - - ret = my_func(bar, baz); - if (!ret) - return -1; - #ifdef BB_FEATURE_FUNKY - maybe_do_funky_stuff(bar, baz); - #endif - - Do this instead: - - (in .h header file) - - #ifdef BB_FEATURE_FUNKY - static inline void maybe_do_funky_stuff (int bar, int baz) - { - /* lotsa code in here */ - } - #else - static inline void maybe_do_funky_stuff (int bar, int baz) {} - #endif - - (in the .c source file) - - ret = my_func(bar, baz); - if (!ret) - return -1; - maybe_do_funky_stuff(bar, baz); - -The great thing about this approach is that the compiler will optimize away -the "no-op" case (the empty function) when the feature is turned off. - -Note also the use of the word 'maybe' in the function name to indicate -conditional execution. - - - -Notes on Strings ----------------- - -Strings in C can get a little thorny. Here's some guidelines for dealing with -strings in Busybox. (There is surely more that could be added to this -section.) - - -String Files -~~~~~~~~~~~~ - -Put all help/usage messages in usage.c. Put other strings in messages.c. -Putting these strings into their own file is a calculated decision designed to -confine spelling errors to a single place and aid internationalization -efforts, if needed. (Side Note: we might want to use a single file - maybe -called 'strings.c' - instead of two, food for thought). - - -Testing String Equivalence -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -There's a right way and a wrong way to test for sting equivalence with -strcmp(): - - The wrong way: - - if (!strcmp(string, "foo")) { - ... - - The right way: - - if (strcmp(string, "foo") == 0){ - ... - -The use of the "equals" (==) operator in the latter example makes it much more -obvious that you are testing for equivalence. The former example with the -"not" (!) operator makes it look like you are testing for an error. In a more -perfect world, we would have a streq() function in the string library, but -that ain't the world we're living in. - - -Avoid Dangerous String Functions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Unfortunately, the way C handles strings makes them prone to overruns when -certain library functions are (mis)used. The following table offers a summary -of some of the more notorious troublemakers: - -function overflows preferred ----------------------------------------- -strcpy dest string strncpy -strcat dest string strncat -gets string it gets fgets -getwd buf string getcwd -[v]sprintf str buffer [v]snprintf -realpath path buffer use with pathconf -[vf]scanf its arguments just avoid it - - -The above is by no means a complete list. Be careful out there. - - - -Avoid Big Static Buffers ------------------------- - -First, some background to put this discussion in context: Static buffers look -like this in code: - - /* in a .c file outside any functions */ - static char *buffer[BUFSIZ]; /* happily used by any function in this file, - but ick! big! */ - -The problem with these is that any time any busybox app is run, you pay a -memory penalty for this buffer, even if the applet that uses said buffer is -not run. This can be fixed, thusly: - - static char *buffer; - ... - other_func() - { - strcpy(buffer, lotsa_chars); /* happily uses global *buffer */ - ... - foo_main() - { - buffer = xmalloc(sizeof(char)*BUFSIZ); - ... - -However, this approach trades bss segment for text segment. Rather than -mallocing the buffers (and thus growing the text size), buffers can be -declared on the stack in the *_main() function and made available globally by -assigning them to a global pointer thusly: - - static char *pbuffer; - ... - other_func() - { - strcpy(pbuffer, lotsa_chars); /* happily uses global *pbuffer */ - ... - foo_main() - { - char *buffer[BUFSIZ]; /* declared locally, on stack */ - pbuffer = buffer; /* but available globally */ - ... - -This last approach has some advantages (low code size, space not used until -it's needed), but can be a problem in some low resource machines that have -very limited stack space (e.g., uCLinux). - -A macro is declared in busybox.h that implements compile-time selection -between xmalloc() and stack creation, so you can code the line in question as - - RESERVE_BB_BUFFER(buffer, BUFSIZ); - -and the right thing will happen, based on your configuration. - - - -Miscellaneous Coding Guidelines -------------------------------- - -The following are important items that don't fit into any of the above -sections. - - -Model Busybox Applets After GNU Counterparts -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -When in doubt about the proper behavior of a Busybox program (output, -formatting, options, etc.), model it after the equivalent GNU program. -Doesn't matter how that program behaves on some other flavor of *NIX; doesn't -matter what the POSIX standard says or doesn't say, just model Busybox -programs after their GNU counterparts and it will make life easier on (nearly) -everyone. - -The only time we deviate from emulating the GNU behavior is when: - - - We are deliberately not supporting a feature (such as a command line - switch) - - Emulating the GNU behavior is prohibitively expensive (lots more code - would be required, lots more memory would be used, etc.) - - The difference is minor or cosmetic - -A note on the 'cosmetic' case: Output differences might be considered -cosmetic, but if the output is significant enough to break other scripts that -use the output, it should really be fixed. - - -Scope -~~~~~ - -If a const variable is used only in a single source file, put it in the source -file and not in a header file. Likewise, if a const variable is used in only -one function, do not make it global to the file. Instead, declare it inside -the function body. Bottom line: Make a conscious effort to limit declarations -to the smallest scope possible. - -Inside applet files, all functions should be declared static so as to keep the -global name space clean. The only exception to this rule is the "applet_main" -function which must be declared extern. - -If you write a function that performs a task that could be useful outside the -immediate file, turn it into a general-purpose function with no ties to any -applet and put it in the utility.c file instead. - - -Brackets Are Your Friends -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Please use brackets on all if and else statements, even if it is only one -line. Example: - - Don't do this: - - if (foo) - stmt1; - stmt2 - stmt3; - - Do this instead: - - if (foo) { - stmt1; - } - stmt2 - stmt3; - -The "bracketless" approach is error prone because someday you might add a line -like this: - - if (foo) - stmt1; - new_line(); - stmt2 - stmt3; - -And the resulting behavior of your program would totally bewilder you. (Don't -laugh, it happens to us all.) Remember folks, this is C, not Python. - - -Function Declarations -~~~~~~~~~~~~~~~~~~~~~ - -Do not use old-style function declarations that declare variable types between -the parameter list and opening bracket. Example: - - Don't do this: - - int foo(parm1, parm2) - char parm1; - float parm2; - { - .... - - Do this instead: - - int foo(char parm1, float parm2) - { - .... - -The only time you would ever need to use the old declaration syntax is to -support ancient, antediluvian compilers. To our good fortune, we have access -to more modern compilers and the old declaration syntax is neither necessary -nor desired. - - -Emphasizing Logical Blocks -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Organization and readability are improved by putting extra newlines around -blocks of code that perform a single task. These are typically blocks that -begin with a C keyword, but not always. - -Furthermore, you should put a single comment (not necessarily one line, just -one comment) before the block, rather than commenting each and every line. -There is an optimal ammount of commenting that a program can have; you can -comment too much as well as too little. - -A picture is really worth a thousand words here, the following example -illustrates how to emphasize logical blocks: - - while (line = get_line_from_file(fp)) { - - /* eat the newline, if any */ - chomp(line); - - /* ignore blank lines */ - if (strlen(file_to_act_on) == 0) { - continue; - } - - /* if the search string is in this line, print it, - * unless we were told to be quiet */ - if (strstr(line, search) && !be_quiet) { - puts(line); - } - - /* clean up */ - free(line); - } - - -Processing Options with getopt -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If your applet needs to process command-line switches, please use getopt() to -do so. Numerous examples can be seen in many of the existing applets, but -basically it boils down to two things: at the top of the .c file, have this -line in the midst of your #includes: - - #include - -And a code block similar to the following near the top of your applet_main() -routine: - - while ((opt = getopt(argc, argv, "abc")) > 0) { - switch (opt) { - case 'a': - do_a_opt = 1; - break; - case 'b': - do_b_opt = 1; - break; - case 'c': - do_c_opt = 1; - break; - default: - show_usage(); /* in utility.c */ - } - } - -If your applet takes no options (such as 'init'), there should be a line -somewhere in the file reads: - - /* no options, no getopt */ - -That way, when people go grepping to see which applets need to be converted to -use getopt, they won't get false positives. - -Additional Note: Do not use the getopt_long library function and do not try to -hand-roll your own long option parsing. Busybox applets should only support -short options. Explanations and examples of the short options should be -documented in usage.h. diff --git a/busybox/dos2unix.c b/busybox/dos2unix.c deleted file mode 100644 index cb30c568b..000000000 --- a/busybox/dos2unix.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * dos2unix for BusyBox - * - * dos2unix '\n' convertor 0.5.0 - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - - -/* 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) -{ - int c, fd; - struct timeval tv; - char tempFn[BUFSIZ]; - static bb_uint64_t value=0; - FILE *in = stdin, *out = stdout; - - if (fn != NULL) { - if ((in = wfopen(fn, "rw")) == NULL) { - return -1; - } - strcpy(tempFn, fn); - c = strlen(tempFn); - tempFn[c] = '.'; - while(1) { - if (c >=BUFSIZ) - 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; - } - } - - 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) { - perror_msg(NULL); - 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)) { - perror_msg(NULL); - return -2; - } - return 0; - } - if (!ConvType) { - ConvType = CT_UNIX2DOS; - } - if (ConvType == 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); - } - - if (fn != NULL) { - if (fclose(in) < 0 || fclose(out) < 0) { - perror_msg(NULL); - 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) { - perror_msg("unable to rename '%s' as '%s'", tempFn, fn); - return -1; - } - } - - return 0; -} - -int dos2unix_main(int argc, char *argv[]) -{ - int ConvType = CT_AUTO; - int o; - - //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; - } - - // process parameters - while ((o = getopt(argc, argv, "du")) != EOF) { - switch (o) { - case 'd': - ConvType = CT_UNIX2DOS; - break; - case 'u': - ConvType = CT_DOS2UNIX; - break; - default: - show_usage(); - } - } - - if (optind < argc) { - while(optind < argc) - if ((o = convert(argv[optind++], ConvType)) < 0) - break; - } - else - o = convert(NULL, ConvType); - - return o; -} - diff --git a/busybox/dpkg.c b/busybox/dpkg.c deleted file mode 100644 index 48c392894..000000000 --- a/busybox/dpkg.c +++ /dev/null @@ -1,1445 +0,0 @@ -/* - * Mini dpkg implementation for busybox. - * This is not meant as a replacemnt for dpkg - * - * Copyright (C) 2001 by Glenn McGrath - * - * Started life as a busybox implementation of udpkg - * - * 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. - */ - -/* - * Known difference between busybox dpkg and the official dpkg that i dont - * consider important, its worth keeping a note of differences anyway, just to - * make it easier to maintain. - * - The first value for the Confflile: field isnt placed on a new line. - * - The .control file is extracted and kept in the info dir. - * - When installing a package the Status: field is placed at the end of the - * section, rather than just after the Package: field. - * - Packages with previously unknown status are inserted at the begining of - * the status file - * - * Bugs that need to be fixed - * - (unknown, please let me know when you find any) - * - */ - -#include -#include -#include -#include -#include "busybox.h" - -/* NOTE: If you vary HASH_PRIME sizes be aware, - * 1) Tweaking these will have a big effect on how much memory this program uses. - * 2) For computational efficiency these hash tables should be at least 20% - * larger than the maximum number of elements stored in it. - * 3) All _HASH_PRIME's must be a prime number or chaos is assured, if your looking - * for a prime, try http://www.utm.edu/research/primes/lists/small/10000.txt - * 4) If you go bigger than 15 bits you may get into trouble (untested) as its - * sometimes cast to an unsigned int, if you go to 16 bit you will overlap - * int's and chaos is assured, 16381 is the max prime for 14 bit field - */ - -/* NAME_HASH_PRIME, Stores package names and versions, - * I estimate it should be at least 50% bigger than PACKAGE_HASH_PRIME, - * as there a lot of duplicate version numbers */ -#define NAME_HASH_PRIME 16381 -char *name_hashtable[NAME_HASH_PRIME + 1]; - -/* PACKAGE_HASH_PRIME, Maximum number of unique packages, - * It must not be smaller than STATUS_HASH_PRIME, - * Currently only packages from status_hashtable are stored in here, but in - * future this may be used to store packages not only from a status file, - * but an available_hashtable, and even multiple packages files. - * Package can be stored more than once if they have different versions. - * e.g. The same package may have different versions in the status file - * and available file */ -#define PACKAGE_HASH_PRIME 10007 -typedef struct edge_s { - unsigned int operator:3; - unsigned int type:4; - unsigned int name:14; - unsigned int version:14; -} edge_t; - -typedef struct common_node_s { - unsigned int name:14; - unsigned int version:14; - unsigned int num_of_edges:14; - edge_t **edge; -} common_node_t; -common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1]; - -/* Currently it doesnt store packages that have state-status of not-installed - * So it only really has to be the size of the maximum number of packages - * likely to be installed at any one time, so there is a bit of leaway here */ -#define STATUS_HASH_PRIME 8191 -typedef struct status_node_s { - unsigned int package:14; /* has to fit PACKAGE_HASH_PRIME */ - unsigned int status:14; /* has to fit STATUS_HASH_PRIME */ -} status_node_t; -status_node_t *status_hashtable[STATUS_HASH_PRIME + 1]; - -/* Even numbers are for 'extras', like ored dependecies or null */ -enum edge_type_e { - EDGE_NULL = 0, - EDGE_PRE_DEPENDS = 1, - EDGE_OR_PRE_DEPENDS = 2, - EDGE_DEPENDS = 3, - EDGE_OR_DEPENDS = 4, - EDGE_REPLACES = 5, - EDGE_PROVIDES = 7, - EDGE_CONFLICTS = 9, - EDGE_SUGGESTS = 11, - EDGE_RECOMMENDS = 13, - EDGE_ENHANCES = 15 -}; -enum operator_e { - VER_NULL = 0, - VER_EQUAL = 1, - VER_LESS = 2, - VER_LESS_EQUAL = 3, - VER_MORE = 4, - VER_MORE_EQUAL = 5, - VER_ANY = 6 -}; - -enum dpkg_opt_e { - dpkg_opt_purge = 1, - dpkg_opt_remove = 2, - dpkg_opt_unpack = 4, - dpkg_opt_configure = 8, - dpkg_opt_install = 16, - dpkg_opt_package_name = 32, - dpkg_opt_filename = 64, - dpkg_opt_list_installed = 128, - dpkg_opt_force_ignore_depends = 256 -}; - -typedef struct deb_file_s { - char *control_file; - char *filename; - unsigned int package:14; -} deb_file_t; - - -void make_hash(const char *key, unsigned int *start, unsigned int *decrement, const int hash_prime) -{ - unsigned long int hash_num = key[0]; - int len = strlen(key); - int i; - - /* Maybe i should have uses a "proper" hashing algorithm here instead - * of making one up myself, seems to be working ok though. */ - for(i = 1; i < len; i++) { - /* shifts the ascii based value and adds it to previous value - * shift amount is mod 24 because long int is 32 bit and data - * to be shifted is 8, dont want to shift data to where it has - * no effect*/ - hash_num += ((key[i] + key[i-1]) << ((key[i] * i) % 24)); - } - *start = (unsigned int) hash_num % hash_prime; - *decrement = (unsigned int) 1 + (hash_num % (hash_prime - 1)); -} - -/* this adds the key to the hash table */ -int search_name_hashtable(const char *key) -{ - unsigned int probe_address = 0; - unsigned int probe_decrement = 0; -// char *temp; - - make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME); - while(name_hashtable[probe_address] != NULL) { - if (strcmp(name_hashtable[probe_address], key) == 0) { - return(probe_address); - } else { - probe_address -= probe_decrement; - if ((int)probe_address < 0) { - probe_address += NAME_HASH_PRIME; - } - } - } - name_hashtable[probe_address] = xstrdup(key); - return(probe_address); -} - -/* this DOESNT add the key to the hashtable - * TODO make it consistent with search_name_hashtable - */ -unsigned int search_status_hashtable(const char *key) -{ - unsigned int probe_address = 0; - unsigned int probe_decrement = 0; - - make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME); - while(status_hashtable[probe_address] != NULL) { - if (strcmp(key, name_hashtable[package_hashtable[status_hashtable[probe_address]->package]->name]) == 0) { - break; - } else { - probe_address -= probe_decrement; - if ((int)probe_address < 0) { - probe_address += STATUS_HASH_PRIME; - } - } - } - return(probe_address); -} - -/* Need to rethink version comparison, maybe the official dpkg has something i can use ? */ -int version_compare_part(const char *version1, const char *version2) -{ - int upstream_len1 = 0; - int upstream_len2 = 0; - char *name1_char; - char *name2_char; - int len1 = 0; - int len2 = 0; - int tmp_int; - int ver_num1; - int ver_num2; - int ret; - - if (version1 == NULL) { - version1 = xstrdup(""); - } - if (version2 != NULL) { - version2 = xstrdup(""); - } - upstream_len1 = strlen(version1); - upstream_len2 = strlen(version2); - - while ((len1 < upstream_len1) || (len2 < upstream_len2)) { - /* Compare non-digit section */ - tmp_int = strcspn(&version1[len1], "0123456789"); - name1_char = xstrndup(&version1[len1], tmp_int); - len1 += tmp_int; - tmp_int = strcspn(&version2[len2], "0123456789"); - name2_char = xstrndup(&version2[len2], tmp_int); - len2 += tmp_int; - tmp_int = strcmp(name1_char, name2_char); - free(name1_char); - free(name2_char); - if (tmp_int != 0) { - ret = tmp_int; - goto cleanup_version_compare_part; - } - - /* Compare digits */ - tmp_int = strspn(&version1[len1], "0123456789"); - name1_char = xstrndup(&version1[len1], tmp_int); - len1 += tmp_int; - tmp_int = strspn(&version2[len2], "0123456789"); - name2_char = xstrndup(&version2[len2], tmp_int); - len2 += tmp_int; - ver_num1 = atoi(name1_char); - ver_num2 = atoi(name2_char); - free(name1_char); - free(name2_char); - if (ver_num1 < ver_num2) { - ret = -1; - goto cleanup_version_compare_part; - } - else if (ver_num1 > ver_num2) { - ret = 1; - goto cleanup_version_compare_part; - } - } - ret = 0; -cleanup_version_compare_part: - return(ret); -} - -/* if ver1 < ver2 return -1, - * if ver1 = ver2 return 0, - * if ver1 > ver2 return 1, - */ -int version_compare(const unsigned int ver1, const unsigned int ver2) -{ - char *ch_ver1 = name_hashtable[ver1]; - char *ch_ver2 = name_hashtable[ver2]; - - char epoch1, epoch2; - char *deb_ver1, *deb_ver2; - char *ver1_ptr, *ver2_ptr; - char *upstream_ver1; - char *upstream_ver2; - int result; - - /* Compare epoch */ - if (ch_ver1[1] == ':') { - epoch1 = ch_ver1[0]; - ver1_ptr = strchr(ch_ver1, ':') + 1; - } else { - epoch1 = '0'; - ver1_ptr = ch_ver1; - } - if (ch_ver2[1] == ':') { - epoch2 = ch_ver2[0]; - ver2_ptr = strchr(ch_ver2, ':') + 1; - } else { - epoch2 = '0'; - ver2_ptr = ch_ver2; - } - if (epoch1 < epoch2) { - return(-1); - } - else if (epoch1 > epoch2) { - return(1); - } - - /* Compare upstream version */ - upstream_ver1 = xstrdup(ver1_ptr); - upstream_ver2 = xstrdup(ver2_ptr); - - /* Chop off debian version, and store for later use */ - deb_ver1 = strrchr(upstream_ver1, '-'); - deb_ver2 = strrchr(upstream_ver2, '-'); - if (deb_ver1) { - deb_ver1[0] = '\0'; - deb_ver1++; - } - if (deb_ver2) { - deb_ver2[0] = '\0'; - deb_ver2++; - } - result = version_compare_part(upstream_ver1, upstream_ver2); - - free(upstream_ver1); - free(upstream_ver2); - - if (result != 0) { - return(result); - } - - /* Compare debian versions */ - return(version_compare_part(deb_ver1, deb_ver2)); -} - -int test_version(const unsigned int version1, const unsigned int version2, const unsigned int operator) -{ - const int version_result = version_compare(version1, version2); - switch(operator) { - case (VER_ANY): - return(TRUE); - case (VER_EQUAL): - if (version_result == 0) { - return(TRUE); - } - break; - case (VER_LESS): - if (version_result < 0) { - return(TRUE); - } - break; - case (VER_LESS_EQUAL): - if (version_result <= 0) { - return(TRUE); - } - break; - case (VER_MORE): - if (version_result > 0) { - return(TRUE); - } - break; - case (VER_MORE_EQUAL): - if (version_result >= 0) { - return(TRUE); - } - break; - } - return(FALSE); -} - - -int search_package_hashtable(const unsigned int name, const unsigned int version, const unsigned int operator) -{ - unsigned int probe_address = 0; - unsigned int probe_decrement = 0; - - make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME); - while(package_hashtable[probe_address] != NULL) { - if (package_hashtable[probe_address]->name == name) { - if (operator == VER_ANY) { - return(probe_address); - } - if (test_version(package_hashtable[probe_address]->version, version, operator)) { - return(probe_address); - } - } - probe_address -= probe_decrement; - if ((int)probe_address < 0) { - probe_address += PACKAGE_HASH_PRIME; - } - } - return(probe_address); -} - -/* - * Create one new node and one new edge for every dependency. - */ -void add_split_dependencies(common_node_t *parent_node, const char *whole_line, unsigned int edge_type) -{ - char *line = xstrdup(whole_line); - char *line2; - char *line_ptr1 = NULL; - char *line_ptr2 = NULL; - char *field; - char *field2; - char *version; - edge_t *edge; - int offset_ch; - int type; - - field = strtok_r(line, ",", &line_ptr1); - do { - line2 = xstrdup(field); - field2 = strtok_r(line2, "|", &line_ptr2); - if ((edge_type == EDGE_DEPENDS) && (strcmp(field, field2) != 0)) { - type = EDGE_OR_DEPENDS; - } - else if ((edge_type == EDGE_PRE_DEPENDS) && (strcmp(field, field2) != 0)) { - type = EDGE_OR_PRE_DEPENDS; - } else { - type = edge_type; - } - - do { - edge = (edge_t *) xmalloc(sizeof(edge_t)); - edge->type = type; - - /* Skip any extra leading spaces */ - field2 += strspn(field2, " "); - - /* Get dependency version info */ - version = strchr(field2, '('); - if (version == NULL) { - edge->operator = VER_ANY; - /* Get the versions hash number, adding it if the number isnt already in there */ - edge->version = search_name_hashtable("ANY"); - } else { - /* Skip leading ' ' or '(' */ - version += strspn(field2, " "); - version += strspn(version, "("); - /* Calculate length of any operator charactors */ - offset_ch = strspn(version, "<=>"); - /* Determine operator */ - if (offset_ch > 0) { - if (strncmp(version, "=", offset_ch) == 0) { - edge->operator = VER_EQUAL; - } - else if (strncmp(version, "<<", offset_ch) == 0) { - edge->operator = VER_LESS; - } - else if (strncmp(version, "<=", offset_ch) == 0) { - edge->operator = VER_LESS_EQUAL; - } - else if (strncmp(version, ">>", offset_ch) == 0) { - edge->operator = VER_MORE; - } - else if (strncmp(version, ">=", offset_ch) == 0) { - edge->operator = VER_MORE_EQUAL; - } else { - error_msg_and_die("Illegal operator\n"); - } - } - /* skip to start of version numbers */ - version += offset_ch; - version += strspn(version, " "); - - /* Truncate version at trailing ' ' or ')' */ - version[strcspn(version, " )")] = '\0'; - /* Get the versions hash number, adding it if the number isnt already in there */ - edge->version = search_name_hashtable(version); - } - - /* Get the dependency name */ - field2[strcspn(field2, " (")] = '\0'; - edge->name = search_name_hashtable(field2); - - /* link the new edge to the current node */ - parent_node->num_of_edges++; - parent_node->edge = xrealloc(parent_node->edge, sizeof(edge_t) * (parent_node->num_of_edges + 1)); - parent_node->edge[parent_node->num_of_edges - 1] = edge; - } while ((field2 = strtok_r(NULL, "|", &line_ptr2)) != NULL); - free(line2); - } while ((field = strtok_r(NULL, ",", &line_ptr1)) != NULL); - free(line); - - return; -} - -void free_package(common_node_t *node) -{ - int i; - if (node != NULL) { - for (i = 0; i < node->num_of_edges; i++) { - if (node->edge[i] != NULL) { - free(node->edge[i]); - } - } - if (node->edge != NULL) { - free(node->edge); - } - if (node != NULL) { - free(node); - } - } -} - -unsigned int fill_package_struct(char *control_buffer) -{ - common_node_t *new_node = (common_node_t *) xcalloc(1, sizeof(common_node_t)); - - char **field_name = xmalloc(sizeof(char *)); - char **field_value = xmalloc(sizeof(char *)); - int field_start = 0; - int num = -1; - int buffer_length = strlen(control_buffer); - - new_node->version = search_name_hashtable("unknown"); - while (field_start < buffer_length) { - field_start += read_package_field(&control_buffer[field_start], field_name, field_value); - - if (*field_name == NULL) { - goto fill_package_struct_cleanup; // Oh no, the dreaded goto statement !! - } - - if (strcmp(*field_name, "Package") == 0) { - new_node->name = search_name_hashtable(*field_value); - } - else if (strcmp(*field_name, "Version") == 0) { - new_node->version = search_name_hashtable(*field_value); - } - else if (strcmp(*field_name, "Pre-Depends") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_PRE_DEPENDS); - } - else if (strcmp(*field_name, "Depends") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_DEPENDS); - } - else if (strcmp(*field_name, "Replaces") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_REPLACES); - } - else if (strcmp(*field_name, "Provides") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_PROVIDES); - } - else if (strcmp(*field_name, "Conflicts") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_CONFLICTS); - } - else if (strcmp(*field_name, "Suggests") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_SUGGESTS); - } - else if (strcmp(*field_name, "Recommends") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_RECOMMENDS); - } - else if (strcmp(*field_name, "Enhances") == 0) { - add_split_dependencies(new_node, *field_value, EDGE_ENHANCES); - } -fill_package_struct_cleanup: - if (*field_name) { - free(*field_name); - } - if (*field_value) { - free(*field_value); - } - } - free(field_name); - free(field_value); - - if (new_node->version == search_name_hashtable("unknown")) { - free_package(new_node); - return(-1); - } - num = search_package_hashtable(new_node->name, new_node->version, VER_EQUAL); - if (package_hashtable[num] == NULL) { - package_hashtable[num] = new_node; - } else { - free_package(new_node); - } - return(num); -} - -/* if num = 1, it returns the want status, 2 returns flag, 3 returns status */ -unsigned int get_status(const unsigned int status_node, const int num) -{ - char *status_string = name_hashtable[status_hashtable[status_node]->status]; - char *state_sub_string; - unsigned int state_sub_num; - int len; - int i; - - /* set tmp_string to point to the start of the word number */ - for (i = 1; i < num; i++) { - /* skip past a word */ - status_string += strcspn(status_string, " "); - /* skip past the seperating spaces */ - status_string += strspn(status_string, " "); - } - len = strcspn(status_string, " \n\0"); - state_sub_string = xstrndup(status_string, len); - state_sub_num = search_name_hashtable(state_sub_string); - free(state_sub_string); - return(state_sub_num); -} - -void set_status(const unsigned int status_node_num, const char *new_value, const int position) -{ - const unsigned int new_value_len = strlen(new_value); - const unsigned int new_value_num = search_name_hashtable(new_value); - unsigned int want = get_status(status_node_num, 1); - unsigned int flag = get_status(status_node_num, 2); - unsigned int status = get_status(status_node_num, 3); - int want_len = strlen(name_hashtable[want]); - int flag_len = strlen(name_hashtable[flag]); - int status_len = strlen(name_hashtable[status]); - char *new_status; - - switch (position) { - case (1): - want = new_value_num; - want_len = new_value_len; - break; - case (2): - flag = new_value_num; - flag_len = new_value_len; - break; - case (3): - status = new_value_num; - status_len = new_value_len; - break; - default: - error_msg_and_die("DEBUG ONLY: this shouldnt happen"); - } - - new_status = (char *) xmalloc(want_len + flag_len + status_len + 3); - sprintf(new_status, "%s %s %s", name_hashtable[want], name_hashtable[flag], name_hashtable[status]); - status_hashtable[status_node_num]->status = search_name_hashtable(new_status); - free(new_status); - return; -} - -void index_status_file(const char *filename) -{ - FILE *status_file; - char *control_buffer; - char *status_line; - status_node_t *status_node = NULL; - unsigned int status_num; - - status_file = xfopen(filename, "r"); - while ((control_buffer = fgets_str(status_file, "\n\n")) != NULL) { - const unsigned int package_num = fill_package_struct(control_buffer); - if (package_num != -1) { - status_node = xmalloc(sizeof(status_node_t)); - /* fill_package_struct doesnt handle the status field */ - status_line = strstr(control_buffer, "Status:"); - if (status_line != NULL) { - status_line += 7; - status_line += strspn(status_line, " \n\t"); - status_line = xstrndup(status_line, strcspn(status_line, "\n\0")); - status_node->status = search_name_hashtable(status_line); - free(status_line); - } - status_node->package = package_num; - status_num = search_status_hashtable(name_hashtable[package_hashtable[status_node->package]->name]); - status_hashtable[status_num] = status_node; - } - free(control_buffer); - } - fclose(status_file); - return; -} - - -char *get_depends_field(common_node_t *package, const int depends_type) -{ - char *depends = NULL; - char *old_sep = (char *)xcalloc(1, 3); - char *new_sep = (char *)xcalloc(1, 3); - int line_size = 0; - int depends_size; - - int i; - - for (i = 0; i < package->num_of_edges; i++) { - if ((package->edge[i]->type == EDGE_OR_PRE_DEPENDS) || - (package->edge[i]->type == EDGE_OR_DEPENDS)) { - } - - if ((package->edge[i]->type == depends_type) || - (package->edge[i]->type == depends_type + 1)) { - /* Check if its the first time through */ - - depends_size = 8 + strlen(name_hashtable[package->edge[i]->name]) - + strlen(name_hashtable[package->edge[i]->version]); - line_size += depends_size; - depends = (char *) xrealloc(depends, line_size + 1); - - /* Check to see if this dependency is the type we are looking for - * +1 to check for 'extra' types, e.g. ored dependecies */ - strcpy(old_sep, new_sep); - if (package->edge[i]->type == depends_type) { - strcpy(new_sep, ", "); - } - else if (package->edge[i]->type == depends_type + 1) { - strcpy(new_sep, "| "); - } - - if (depends_size == line_size) { - strcpy(depends, ""); - } else { - if ((strcmp(old_sep, "| ") == 0) && (strcmp(new_sep, "| ") == 0)) { - strcat(depends, " | "); - } else { - strcat(depends, ", "); - } - } - - strcat(depends, name_hashtable[package->edge[i]->name]); - if (strcmp(name_hashtable[package->edge[i]->version], "NULL") != 0) { - if (package->edge[i]->operator == VER_EQUAL) { - strcat(depends, " (= "); - } - else if (package->edge[i]->operator == VER_LESS) { - strcat(depends, " (<< "); - } - else if (package->edge[i]->operator == VER_LESS_EQUAL) { - strcat(depends, " (<= "); - } - else if (package->edge[i]->operator == VER_MORE) { - strcat(depends, " (>> "); - } - else if (package->edge[i]->operator == VER_MORE_EQUAL) { - strcat(depends, " (>= "); - } else { - strcat(depends, " ("); - } - strcat(depends, name_hashtable[package->edge[i]->version]); - strcat(depends, ")"); - } - } - } - return(depends); -} - -void write_buffer_no_status(FILE *new_status_file, const char *control_buffer) -{ - char *name; - char *value; - int start = 0; - while (1) { - start += read_package_field(&control_buffer[start], &name, &value); - if (name == NULL) { - break; - } - if (strcmp(name, "Status") != 0) { - fprintf(new_status_file, "%s: %s\n", name, value); - } - } - return; -} - -/* This could do with a cleanup */ -void write_status_file(deb_file_t **deb_file) -{ - FILE *old_status_file = xfopen("/var/lib/dpkg/status", "r"); - FILE *new_status_file = xfopen("/var/lib/dpkg/status.udeb", "w"); - char *package_name; - char *status_from_file; - char *control_buffer = NULL; - char *tmp_string; - int status_num; - int field_start = 0; - int write_flag; - int i = 0; - - /* Update previously known packages */ - while ((control_buffer = fgets_str(old_status_file, "\n\n")) != NULL) { - tmp_string = strstr(control_buffer, "Package:") + 8; - tmp_string += strspn(tmp_string, " \n\t"); - package_name = xstrndup(tmp_string, strcspn(tmp_string, "\n\0")); - write_flag = FALSE; - tmp_string = strstr(control_buffer, "Status:"); - if (tmp_string != NULL) { - /* Seperate the status value from the control buffer */ - tmp_string += 7; - tmp_string += strspn(tmp_string, " \n\t"); - status_from_file = xstrndup(tmp_string, strcspn(tmp_string, "\n")); - } else { - status_from_file = NULL; - } - - /* Find this package in the status hashtable */ - status_num = search_status_hashtable(package_name); - if (status_hashtable[status_num] != NULL) { - const char *status_from_hashtable = name_hashtable[status_hashtable[status_num]->status]; - if (strcmp(status_from_file, status_from_hashtable) != 0) { - /* New status isnt exactly the same as old status */ - const int state_status = get_status(status_num, 3); - if ((strcmp("installed", name_hashtable[state_status]) == 0) || - (strcmp("unpacked", name_hashtable[state_status]) == 0)) { - /* We need to add the control file from the package */ - i = 0; - while(deb_file[i] != NULL) { - if (strcmp(package_name, name_hashtable[package_hashtable[deb_file[i]->package]->name]) == 0) { - /* Write a status file entry with a modified status */ - /* remove trailing \n's */ - write_buffer_no_status(new_status_file, deb_file[i]->control_file); - set_status(status_num, "ok", 2); - fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]); - write_flag = TRUE; - break; - } - i++; - } - /* This is temperary, debugging only */ - if (deb_file[i] == NULL) { - error_msg_and_die("ALERT: Couldnt find a control file, your status file may be broken, status may be incorrect for %s", package_name); - } - } - else if (strcmp("not-installed", name_hashtable[state_status]) == 0) { - /* Only write the Package, Status, Priority and Section lines */ - fprintf(new_status_file, "Package: %s\n", package_name); - fprintf(new_status_file, "Status: %s\n", status_from_hashtable); - - while (1) { - char *field_name; - char *field_value; - field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value); - if (field_name == NULL) { - break; - } - if ((strcmp(field_name, "Priority") == 0) || - (strcmp(field_name, "Section") == 0)) { - fprintf(new_status_file, "%s: %s\n", field_name, field_value); - } - } - write_flag = TRUE; - fputs("\n", new_status_file); - } - else if (strcmp("config-files", name_hashtable[state_status]) == 0) { - /* only change the status line */ - while (1) { - char *field_name; - char *field_value; - field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value); - if (field_name == NULL) { - break; - } - /* Setup start point for next field */ - if (strcmp(field_name, "Status") == 0) { - fprintf(new_status_file, "Status: %s\n", status_from_hashtable); - } else { - fprintf(new_status_file, "%s: %s\n", field_name, field_value); - } - } - write_flag = TRUE; - fputs("\n", new_status_file); - } - } - } - /* If the package from the status file wasnt handle above, do it now*/ - if (write_flag == FALSE) { - fprintf(new_status_file, "%s\n\n", control_buffer); - } - - if (status_from_file != NULL) { - free(status_from_file); - } - free(package_name); - free(control_buffer); - } - - /* Write any new packages */ - for(i = 0; deb_file[i] != NULL; i++) { - status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[i]->package]->name]); - if (strcmp("reinstreq", name_hashtable[get_status(status_num, 2)]) == 0) { - write_buffer_no_status(new_status_file, deb_file[i]->control_file); - set_status(status_num, "ok", 2); - fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]); - } - } - fclose(old_status_file); - fclose(new_status_file); - - - /* Create a seperate backfile to dpkg */ - if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) { - struct stat stat_buf; - if (stat("/var/lib/dpkg/status", &stat_buf) == 0) { - error_msg_and_die("Couldnt create backup status file"); - } - /* Its ok if renaming the status file fails becasue status - * file doesnt exist, maybe we are starting from scratch */ - error_msg("No status file found, creating new one"); - } - - if (rename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status") == -1) { - error_msg_and_die("DANGER: Couldnt create status file, you need to manually repair your status file"); - } -} - -int check_deps(deb_file_t **deb_file, int deb_start, int dep_max_count) -{ - int *conflicts = NULL; - int conflicts_num = 0; - int state_status; - int state_flag; - int state_want; - unsigned int status_package_num; - int i = deb_start; - int j, k; - - /* Check for conflicts - * TODO: TEST if conflicts with other packages to be installed - * - * Add install packages and the packages they provide - * to the list of files to check conflicts for - */ - - /* Create array of package numbers to check against - * installed package for conflicts*/ - while (deb_file[i] != NULL) { - const unsigned int package_num = deb_file[i]->package; - conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1)); - conflicts[conflicts_num] = package_num; - conflicts_num++; - /* add provides to conflicts list */ - for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) { - if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) { - const int conflicts_package_num = search_package_hashtable( - package_hashtable[package_num]->edge[j]->name, - package_hashtable[package_num]->edge[j]->version, - package_hashtable[package_num]->edge[j]->operator); - if (package_hashtable[conflicts_package_num] == NULL) { - /* create a new package */ - common_node_t *new_node = (common_node_t *) xmalloc(sizeof(common_node_t)); - new_node->name = package_hashtable[package_num]->edge[j]->name; - new_node->version = package_hashtable[package_num]->edge[j]->version; - new_node->num_of_edges = 0; - new_node->edge = NULL; - package_hashtable[conflicts_package_num] = new_node; - } - conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1)); - conflicts[conflicts_num] = conflicts_package_num; - conflicts_num++; - } - } - i++; - } - - /* Check conflicts */ - for (i = 0; i < conflicts_num; i++) { - /* Check for conflicts */ - for (j = 0; j < STATUS_HASH_PRIME; j++) { - if (status_hashtable[j] == NULL) { - continue; - } - state_flag = get_status(j, 2); - state_status = get_status(j, 3); - if ((state_status != search_name_hashtable("installed")) - && (state_flag != search_name_hashtable("want-install"))) { - continue; - } - status_package_num = status_hashtable[j]->package; - for (k = 0; k < package_hashtable[status_package_num]->num_of_edges; k++) { - const edge_t *package_edge = package_hashtable[status_package_num]->edge[k]; - if (package_edge->type != EDGE_CONFLICTS) { - continue; - } - if (package_edge->name != package_hashtable[conflicts[i]]->name) { - continue; - } - /* There is a conflict against the package name - * check if version conflict as well */ - if (test_version(package_hashtable[deb_file[i]->package]->version, - package_edge->version, package_edge->operator)) { - error_msg_and_die("Package %s conflict with %s", - name_hashtable[package_hashtable[deb_file[i]->package]->name], - name_hashtable[package_hashtable[status_package_num]->name]); - } - } - } - } - - /* Check dependendcies */ - i = 0; - while (deb_file[i] != NULL) { - const common_node_t *package_node = package_hashtable[deb_file[i]->package]; - int status_num = 0; - - for (j = 0; j < package_hashtable[deb_file[i]->package]->num_of_edges; j++) { - const edge_t *package_edge = package_node->edge[j]; - const unsigned int package_num = search_package_hashtable(package_edge->name, - package_edge->version, package_edge->operator); - - status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]); - state_status = get_status(status_num, 3); - state_want = get_status(status_num, 1); - switch (package_edge->type) { - case(EDGE_PRE_DEPENDS): - case(EDGE_OR_PRE_DEPENDS): - /* It must be already installed */ - /* NOTE: This is untested, nothing apropriate in my status file */ - if ((package_hashtable[package_num] == NULL) || (state_status != search_name_hashtable("installed"))) { - error_msg_and_die("Package %s pre-depends on %s, but it is not installed", - name_hashtable[package_node->name], - name_hashtable[package_edge->name]); - } - break; - case(EDGE_DEPENDS): - case(EDGE_OR_DEPENDS): - /* It must be already installed, or to be installed */ - if ((package_hashtable[package_num] == NULL) || - ((state_status != search_name_hashtable("installed")) && - (state_want != search_name_hashtable("want_install")))) { - error_msg_and_die("Package %s depends on %s, but it is not installed, or flaged to be installed", - name_hashtable[package_node->name], - name_hashtable[package_edge->name]); - } - break; - } - } - i++; - } - free(conflicts); - return(TRUE); -} - -char **create_list(const char *filename) -{ - FILE *list_stream; - char **file_list = xmalloc(sizeof(char *)); - char *line = NULL; - char *last_char; - int length = 0; - int count = 0; - - /* dont use [xw]fopen here, handle error ourself */ - list_stream = fopen(filename, "r"); - if (list_stream == NULL) { - *file_list = NULL; - return(file_list); - } - while (getline(&line, &length, list_stream) != -1) { - file_list = xrealloc(file_list, sizeof(char *) * (length + 1)); - last_char = last_char_is(line, '\n'); - if (last_char) { - *last_char = '\0'; - } - file_list[count] = xstrdup(line); - free(line); - count++; - length = 0; - } - fclose(list_stream); - - if (count == 0) { - return(NULL); - } else { - file_list[count] = NULL; - return(file_list); - } -} - -/* maybe i should try and hook this into remove_file.c somehow */ -int remove_file_array(char **remove_names, char **exclude_names) -{ - struct stat path_stat; - int match_flag; - int remove_flag = FALSE; - int i,j; - - if (remove_names == NULL) { - return(FALSE); - } - for (i = 0; remove_names[i] != NULL; i++) { - match_flag = FALSE; - if (exclude_names != NULL) { - for (j = 0; exclude_names[j] != 0; j++) { - if (strcmp(remove_names[i], exclude_names[j]) == 0) { - match_flag = TRUE; - break; - } - } - } - if (!match_flag) { - if (lstat(remove_names[i], &path_stat) < 0) { - continue; - } - if (S_ISDIR(path_stat.st_mode)) { - if (rmdir(remove_names[i]) != -1) { - remove_flag = TRUE; - } - } else { - if (unlink(remove_names[i]) != -1) { - remove_flag = TRUE; - } - } - } - } - return(remove_flag); -} - -int run_package_script(const char *package_name, const char *script_type) -{ - struct stat path_stat; - char *script_path; - - script_path = xmalloc(strlen(package_name) + strlen(script_type) + 21); - sprintf(script_path, "/var/lib/dpkg/info/%s.%s", package_name, script_type); - - /* If the file doesnt exist is isnt a fatal */ - if (lstat(script_path, &path_stat) < 0) { - free(script_path); - return(EXIT_SUCCESS); - } else { - free(script_path); - return(system(script_path)); - } -} - -void all_control_list(char **remove_files, const char *package_name) -{ - const char *all_extensions[11] = {"preinst", "postinst", "prerm", "postrm", - "list", "md5sums", "shlibs", "conffiles", "config", "templates", NULL }; - int i; - - /* Create a list of all /var/lib/dpkg/info/ files */ - for(i = 0; i < 10; i++) { - remove_files[i] = xmalloc(strlen(package_name) + strlen(all_extensions[i]) + 21); - sprintf(remove_files[i], "/var/lib/dpkg/info/%s.%s", package_name, all_extensions[i]); - } - remove_files[10] = NULL; -} - -void remove_package(const unsigned int package_num) -{ - const char *package_name = name_hashtable[package_hashtable[package_num]->name]; - const unsigned int status_num = search_status_hashtable(package_name); - const int package_name_length = strlen(package_name); - char **remove_files; - char **exclude_files; - char list_name[package_name_length + 25]; - char conffile_name[package_name_length + 30]; - int return_value; - - printf("Removing %s ...\n", package_name); - - /* run prerm script */ - return_value = run_package_script(package_name, "prem"); - if (return_value == -1) { - error_msg_and_die("script failed, prerm failure"); - } - - /* Create a list of files to remove, and a seperate list of those to keep */ - sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name); - remove_files = create_list(list_name); - - sprintf(conffile_name, "/var/lib/dpkg/info/%s.conffiles", package_name); - exclude_files = create_list(conffile_name); - - /* Some directories cant be removed straight away, so do multiple passes */ - while (remove_file_array(remove_files, exclude_files) == TRUE); - - /* Create a list of all /var/lib/dpkg/info/ files */ - remove_files = xmalloc(11); - all_control_list(remove_files, package_name); - - /* Create a list of files in /var/lib/dpkg/info/.* to keep */ - exclude_files = xmalloc(sizeof(char*) * 3); - exclude_files[0] = xstrdup(conffile_name); - exclude_files[1] = xmalloc(package_name_length + 27); - sprintf(exclude_files[1], "/var/lib/dpkg/info/%s.postrm", package_name); - exclude_files[2] = NULL; - - remove_file_array(remove_files, exclude_files); - - /* rename .conffile to .list */ - rename(conffile_name, list_name); - - /* Change package status */ - set_status(status_num, "deinstall", 1); - set_status(status_num, "config-files", 3); -} - -void purge_package(const unsigned int package_num) -{ - const char *package_name = name_hashtable[package_hashtable[package_num]->name]; - const unsigned int status_num = search_status_hashtable(package_name); - char **remove_files; - char **exclude_files; - char list_name[strlen(package_name) + 25]; - - /* run prerm script */ - if (run_package_script(package_name, "prerm") == -1) { - error_msg_and_die("script failed, prerm failure"); - } - - /* Create a list of files to remove */ - sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name); - remove_files = create_list(list_name); - - exclude_files = xmalloc(1); - exclude_files[0] = NULL; - - /* Some directories cant be removed straight away, so do multiple passes */ - while (remove_file_array(remove_files, exclude_files) == TRUE); - - /* Create a list of all /var/lib/dpkg/info/ files */ - remove_files = xmalloc(11); - all_control_list(remove_files, package_name); - remove_file_array(remove_files, exclude_files); - - /* run postrm script */ - if (run_package_script(package_name, "postrm") == -1) { - error_msg_and_die("postrm fialure.. set status to what?"); - } - - /* Change package status */ - set_status(status_num, "purge", 1); - set_status(status_num, "not-installed", 3); -} - -void unpack_package(deb_file_t *deb_file) -{ - const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name]; - const unsigned int status_num = search_status_hashtable(package_name); - const unsigned int status_package_num = status_hashtable[status_num]->status; - - FILE *out_stream; - char *info_prefix; - - /* If existing version, remove it first */ - if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) { - /* Package is already installed, remove old version first */ - printf("Preparing to replace %s %s (using %s) ...\n", package_name, - name_hashtable[package_hashtable[status_package_num]->version], - deb_file->filename); - remove_package(status_package_num); - } else { - printf("Unpacking %s (from %s) ...\n", package_name, deb_file->filename); - } - - /* Extract control.tar.gz to /var/lib/dpkg/info/.filename */ - info_prefix = (char *) xmalloc(sizeof(package_name) + 20 + 4 + 1); - sprintf(info_prefix, "/var/lib/dpkg/info/%s.", package_name); - deb_extract(deb_file->filename, stdout, (extract_quiet | extract_control_tar_gz | extract_all_to_fs), info_prefix, NULL); - - /* Extract data.tar.gz to the root directory */ - deb_extract(deb_file->filename, stdout, (extract_quiet | extract_data_tar_gz | extract_all_to_fs), "/", NULL); - - /* Create the list file */ - strcat(info_prefix, "list"); - out_stream = xfopen(info_prefix, "w"); - deb_extract(deb_file->filename, out_stream, (extract_quiet | extract_data_tar_gz | extract_list), NULL, NULL); - fclose(out_stream); - - /* change status */ - set_status(status_num, "install", 1); - set_status(status_num, "unpacked", 3); - - free(info_prefix); -} - -void configure_package(deb_file_t *deb_file) -{ - const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name]; - const char *package_version = name_hashtable[package_hashtable[deb_file->package]->version]; - const int status_num = search_status_hashtable(package_name); - int return_value; - - printf("Setting up %s (%s)\n", package_name, package_version); - - /* Run the preinst prior to extracting */ - return_value = run_package_script(package_name, "postinst"); - if (return_value == -1) { - /* TODO: handle failure gracefully */ - error_msg_and_die("postrm failure.. set status to what?"); - } - /* Change status to reflect success */ - set_status(status_num, "install", 1); - set_status(status_num, "installed", 3); -} - -extern int dpkg_main(int argc, char **argv) -{ - deb_file_t **deb_file = NULL; - status_node_t *status_node; - char opt = 0; - int package_num; - int dpkg_opt = 0; - int deb_count = 0; - int state_status; - int status_num; - int i; - - while ((opt = getopt(argc, argv, "CF:ilPru")) != -1) { - switch (opt) { - case 'C': // equivalent to --configure in official dpkg - dpkg_opt |= dpkg_opt_configure; - dpkg_opt |= dpkg_opt_package_name; - break; - case 'F': // equivalent to --force in official dpkg - if (strcmp(optarg, "depends") == 0) { - dpkg_opt |= dpkg_opt_force_ignore_depends; - } - case 'i': - dpkg_opt |= dpkg_opt_install; - dpkg_opt |= dpkg_opt_filename; - break; - case 'l': - dpkg_opt |= dpkg_opt_list_installed; - case 'P': - dpkg_opt |= dpkg_opt_purge; - dpkg_opt |= dpkg_opt_package_name; - break; - case 'r': - dpkg_opt |= dpkg_opt_remove; - dpkg_opt |= dpkg_opt_package_name; - break; - case 'u': /* Equivalent to --unpack in official dpkg */ - dpkg_opt |= dpkg_opt_unpack; - dpkg_opt |= dpkg_opt_filename; - break; - default: - show_usage(); - } - } - - if ((argc == optind) || (dpkg_opt == 0)) { - show_usage(); - } - - puts("(Reading database ... xxxxx files and directories installed.)"); - index_status_file("/var/lib/dpkg/status"); - - /* Read arguments and store relevant info in structs */ - deb_file = xmalloc(sizeof(deb_file_t)); - while (optind < argc) { - deb_file[deb_count] = (deb_file_t *) xmalloc(sizeof(deb_file_t)); - if (dpkg_opt & dpkg_opt_filename) { - deb_file[deb_count]->filename = xstrdup(argv[optind]); - deb_file[deb_count]->control_file = deb_extract(argv[optind], stdout, (extract_control_tar_gz | extract_one_to_buffer), NULL, "./control"); - if (deb_file[deb_count]->control_file == NULL) { - error_msg_and_die("Couldnt extract control file"); - } - package_num = fill_package_struct(deb_file[deb_count]->control_file); - - if (package_num == -1) { - error_msg("Invalid control file in %s", argv[optind]); - continue; - } - deb_file[deb_count]->package = (unsigned int) package_num; - /* Add the package to the status hashtable */ - if ((dpkg_opt & dpkg_opt_unpack) || (dpkg_opt & dpkg_opt_install)) { - status_node = (status_node_t *) xmalloc(sizeof(status_node_t)); - status_node->package = deb_file[deb_count]->package; - /* use reinstreq isnt changed to "ok" until the package control info - * is written to the status file*/ - status_node->status = search_name_hashtable("install reinstreq not-installed"); - - status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); - status_hashtable[status_num] = status_node; - } - } - else if (dpkg_opt & dpkg_opt_package_name) { - deb_file[deb_count]->filename = NULL; - deb_file[deb_count]->control_file = NULL; - deb_file[deb_count]->package = search_package_hashtable( - search_name_hashtable(argv[optind]), - search_name_hashtable("ANY"), VER_ANY); - if (package_hashtable[deb_file[deb_count]->package] == NULL) { - error_msg_and_die("Package %s is uninstalled or unknown\n", argv[optind]); - } - state_status = get_status(search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]), 3); - - /* check package status is "installed" */ - if (dpkg_opt & dpkg_opt_remove) { - if ((strcmp(name_hashtable[state_status], "not-installed") == 0) || - (strcmp(name_hashtable[state_status], "config-files") == 0)) { - error_msg_and_die("%s is already removed.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); - } - } - else if (dpkg_opt & dpkg_opt_purge) { - /* if package status is "conf-files" then its ok */ - if (strcmp(name_hashtable[state_status], "not-installed") == 0) { - error_msg_and_die("%s is already purged.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); - } - } - } - deb_count++; - optind++; - } - deb_file[deb_count] = NULL; - - /* Check that the deb file arguments are installable */ - /* TODO: check dependencies before removing */ - if ((dpkg_opt & dpkg_opt_force_ignore_depends) != dpkg_opt_force_ignore_depends) { - if (!check_deps(deb_file, 0, deb_count)) { - error_msg_and_die("Dependency check failed"); - } - } - - for (i = 0; i < deb_count; i++) { - /* Remove or purge packages */ - if (dpkg_opt & dpkg_opt_remove) { - remove_package(deb_file[i]->package); - } - else if (dpkg_opt & dpkg_opt_purge) { - purge_package(deb_file[i]->package); - } - else if (dpkg_opt & dpkg_opt_unpack) { - unpack_package(deb_file[i]); - } - else if (dpkg_opt & dpkg_opt_install) { - unpack_package(deb_file[i]); - configure_package(deb_file[i]); - } - else if (dpkg_opt & dpkg_opt_configure) { - configure_package(deb_file[i]); - } - } - - write_status_file(deb_file); - - for (i = 0; i < deb_count; i++) { - free(deb_file[i]->control_file); - free(deb_file[i]->filename); - free(deb_file[i]); - } - free(deb_file); - - for (i = 0; i < NAME_HASH_PRIME; i++) { - if (name_hashtable[i] != NULL) { - free(name_hashtable[i]); - } - } - - for (i = 0; i < PACKAGE_HASH_PRIME; i++) { - free_package(package_hashtable[i]); - } - - for (i = 0; i < STATUS_HASH_PRIME; i++) { - if (status_hashtable[i] != NULL) { - free(status_hashtable[i]); - } - } - - return(EXIT_FAILURE); -} - diff --git a/busybox/dpkg_deb.c b/busybox/dpkg_deb.c deleted file mode 100644 index a933c6948..000000000 --- a/busybox/dpkg_deb.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include "busybox.h" - -extern int dpkg_deb_main(int argc, char **argv) -{ - char *prefix = NULL; - char *filename = NULL; - char *output_buffer = NULL; - int opt = 0; - int arg_type = 0; - int deb_extract_funct = extract_create_leading_dirs | extract_unconditional; - - const int arg_type_prefix = 1; - const int arg_type_field = 2; - const int arg_type_filename = 4; -// const int arg_type_un_ar_gz = 8; - - while ((opt = getopt(argc, argv, "ceftXxI")) != -1) { - switch (opt) { - case 'c': - deb_extract_funct |= extract_data_tar_gz; - deb_extract_funct |= extract_verbose_list; - break; - case 'e': - arg_type = arg_type_prefix; - deb_extract_funct |= extract_control_tar_gz; - deb_extract_funct |= extract_all_to_fs; - break; - case 'f': - arg_type = arg_type_field; - deb_extract_funct |= extract_control_tar_gz; - deb_extract_funct |= extract_one_to_buffer; - filename = xstrdup("./control"); - break; - case 't': /* --fsys-tarfile, i just made up this short name */ - /* Integrate the functionality needed with some code from ar.c */ - error_msg_and_die("Option disabled"); -// arg_type = arg_type_un_ar_gz; - break; - case 'X': - arg_type = arg_type_prefix; - deb_extract_funct |= extract_data_tar_gz; - deb_extract_funct |= extract_all_to_fs; - deb_extract_funct |= extract_list; - case 'x': - arg_type = arg_type_prefix; - deb_extract_funct |= extract_data_tar_gz; - deb_extract_funct |= extract_all_to_fs; - break; - case 'I': - arg_type = arg_type_filename; - deb_extract_funct |= extract_control_tar_gz; - deb_extract_funct |= extract_one_to_buffer; - break; - default: - show_usage(); - } - } - - if (optind == argc) { - show_usage(); - } - - /* Workout where to extract the files */ - if (arg_type == arg_type_prefix) { - /* argument is a dir name */ - if ((optind + 1) == argc ) { - prefix = xstrdup("./DEBIAN/"); - } else { - prefix = (char *) xmalloc(strlen(argv[optind + 1]) + 2); - strcpy(prefix, argv[optind + 1]); - /* Make sure the directory has a trailing '/' */ - if (last_char_is(prefix, '/') == NULL) { - strcat(prefix, "/"); - } - } - mkdir(prefix, 0777); - } - - if (arg_type == arg_type_filename) { - if ((optind + 1) != argc) { - filename = xstrdup(argv[optind + 1]); - } else { - error_msg_and_die("-I currently requires a filename to be specified"); - } - } - - output_buffer = deb_extract(argv[optind], stdout, deb_extract_funct, prefix, filename); - - if ((arg_type == arg_type_filename) && (output_buffer != NULL)) { - puts(output_buffer); - } - else if (arg_type == arg_type_field) { - char *field = NULL; - char *name; - char *value; - int field_start = 0; - - while (1) { - field_start += read_package_field(&output_buffer[field_start], &name, &value); - if (name == NULL) { - break; - } - if (strcmp(name, argv[optind + 1]) == 0) { - puts(value); - } - free(field); - } - } - - return(EXIT_SUCCESS); -} diff --git a/busybox/du.c b/busybox/du.c deleted file mode 100644 index fb649aee5..000000000 --- a/busybox/du.c +++ /dev/null @@ -1,257 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini du implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by John Beppu - * - * 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 "busybox.h" - - -#ifdef BB_FEATURE_HUMAN_READABLE -static unsigned long disp_hr = KILOBYTE; -#endif - -typedef void (Display) (long, char *); - -static int du_depth = 0; -static int count_hardlinks = 0; - -static Display *print; - -static void print_normal(long size, char *filename) -{ -#ifdef BB_FEATURE_HUMAN_READABLE - printf("%s\t%s\n", make_human_readable_str(size<<10, 1, disp_hr), filename); -#else - printf("%ld\t%s\n", size, filename); -#endif -} - -static void print_summary(long size, char *filename) -{ - if (du_depth == 1) { - print_normal(size, filename); - } -} - -#define HASH_SIZE 311 /* Should be prime */ -#define hash_inode(i) ((i) % HASH_SIZE) - -typedef struct ino_dev_hash_bucket_struct { - struct ino_dev_hash_bucket_struct *next; - ino_t ino; - dev_t dev; - char name[1]; -} ino_dev_hashtable_bucket_t; - -static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE]; - -/* - * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in - * `ino_dev_hashtable', else return 0 - * - * If NAME is a non-NULL pointer to a character pointer, and there is - * a match, then set *NAME to the value of the name slot in that - * bucket. - */ -static int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name) -{ - ino_dev_hashtable_bucket_t *bucket; - - bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)]; - while (bucket != NULL) { - if ((bucket->ino == statbuf->st_ino) && - (bucket->dev == statbuf->st_dev)) - { - if (name) *name = bucket->name; - return 1; - } - bucket = bucket->next; - } - return 0; -} - -/* Add statbuf to statbuf hash table */ -static void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) -{ - int i; - size_t s; - ino_dev_hashtable_bucket_t *bucket; - - i = hash_inode(statbuf->st_ino); - s = name ? strlen(name) : 0; - bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s); - bucket->ino = statbuf->st_ino; - bucket->dev = statbuf->st_dev; - if (name) - strcpy(bucket->name, name); - else - bucket->name[0] = '\0'; - bucket->next = ino_dev_hashtable[i]; - ino_dev_hashtable[i] = bucket; -} - -/* Clear statbuf hash table */ -static void reset_ino_dev_hashtable(void) -{ - int i; - ino_dev_hashtable_bucket_t *bucket; - - for (i = 0; i < HASH_SIZE; i++) { - while (ino_dev_hashtable[i] != NULL) { - bucket = ino_dev_hashtable[i]->next; - free(ino_dev_hashtable[i]); - ino_dev_hashtable[i] = bucket; - } - } -} - -/* tiny recursive du */ -static long du(char *filename) -{ - struct stat statbuf; - long sum; - - if ((lstat(filename, &statbuf)) != 0) { - perror_msg("%s", filename); - return 0; - } - - du_depth++; - sum = (statbuf.st_blocks >> 1); - - /* Don't add in stuff pointed to by symbolic links */ - if (S_ISLNK(statbuf.st_mode)) { - sum = 0L; - if (du_depth == 1) { - } - } - if (S_ISDIR(statbuf.st_mode)) { - DIR *dir; - struct dirent *entry; - char *newfile; - - dir = opendir(filename); - if (!dir) { - du_depth--; - return 0; - } - - newfile = last_char_is(filename, '/'); - if (newfile) - *newfile = '\0'; - - while ((entry = readdir(dir))) { - char *name = entry->d_name; - - if ((strcmp(name, "..") == 0) - || (strcmp(name, ".") == 0)) { - continue; - } - newfile = concat_path_file(filename, name); - sum += du(newfile); - free(newfile); - } - closedir(dir); - print(sum, filename); - } - else if (statbuf.st_nlink > 1 && !count_hardlinks) { - /* Add files with hard links only once */ - if (is_in_ino_dev_hashtable(&statbuf, NULL)) { - sum = 0L; - if (du_depth == 1) - print(sum, filename); - } - else { - add_to_ino_dev_hashtable(&statbuf, NULL); - } - } - du_depth--; - return sum; -} - -int du_main(int argc, char **argv) -{ - int status = EXIT_SUCCESS; - int i; - int c; - - /* default behaviour */ - print = print_normal; - - /* parse argv[] */ - while ((c = getopt(argc, argv, "sl" -#ifdef BB_FEATURE_HUMAN_READABLE -"hm" -#endif -"k")) != EOF) { - switch (c) { - case 's': - print = print_summary; - break; - case 'l': - count_hardlinks = 1; - break; -#ifdef BB_FEATURE_HUMAN_READABLE - case 'h': disp_hr = 0; break; - case 'm': disp_hr = MEGABYTE; break; -#endif - case 'k': break; - default: - show_usage(); - } - } - - /* go through remaining args (if any) */ - if (optind >= argc) { - if (du(".") == 0) - status = EXIT_FAILURE; - } else { - long sum; - - for (i=optind; i < argc; i++) { - sum = du(argv[i]); - if(is_directory(argv[i], FALSE, NULL)==FALSE) { - print_normal(sum, argv[i]); - } - reset_ino_dev_hashtable(); - } - } - - return status; -} - -/* $Id: du.c,v 1.50 2001/06/30 17:54:20 andersen Exp $ */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/dumpkmap.c b/busybox/dumpkmap.c deleted file mode 100644 index 22652a5e2..000000000 --- a/busybox/dumpkmap.c +++ /dev/null @@ -1,95 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini dumpkmap implementation for busybox - * - * Copyright (C) Arne Bernin - * - * 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 "busybox.h" - -/* From */ -struct kbentry { - unsigned char kb_table; - unsigned char kb_index; - unsigned short kb_value; -}; -static const int KDGKBENT = 0x4B46; /* gets one entry in translation table */ - -/* From */ -static const int NR_KEYS = 128; -static const int MAX_NR_KEYMAPS = 256; - -int dumpkmap_main(int argc, char **argv) -{ - struct kbentry ke; - int i, j, fd; - char flags[MAX_NR_KEYMAPS], magic[] = "bkeymap"; - - if (argc>=2 && *argv[1]=='-') { - show_usage(); - } - - fd = open(CURRENT_VC, O_RDWR); - if (fd < 0) { - perror_msg("Error opening " CURRENT_VC); - return EXIT_FAILURE; - } - - write(1, magic, 7); - - for (i=0; i < MAX_NR_KEYMAPS; i++) flags[i]=0; - flags[0]=1; - flags[1]=1; - flags[2]=1; - flags[4]=1; - flags[5]=1; - flags[6]=1; - flags[8]=1; - flags[9]=1; - flags[10]=1; - flags[12]=1; - - /* dump flags */ - for (i=0; i < MAX_NR_KEYMAPS; i++) write(1,&flags[i],1); - - for (i = 0; i < MAX_NR_KEYMAPS; i++) { - if (flags[i] == 1) { - for (j = 0; j < NR_KEYS; j++) { - ke.kb_index = j; - ke.kb_table = i; - if (ioctl(fd, KDGKBENT, &ke) < 0) { - - error_msg("ioctl returned: %s, %s, %s, %xqq", strerror(errno),(char *)&ke.kb_index,(char *)&ke.kb_table,(int)&ke.kb_value); - } - else { - write(1,(void*)&ke.kb_value,2); - } - - } - } - } - close(fd); - return EXIT_SUCCESS; -} diff --git a/busybox/dutmp.c b/busybox/dutmp.c deleted file mode 100644 index df7f64d30..000000000 --- a/busybox/dutmp.c +++ /dev/null @@ -1,64 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * public domain -- Dave 'Kill a Cop' Cinege - * - * dutmp - * Takes utmp formated file on stdin and dumps it's contents - * out in colon delimited fields. Easy to 'cut' for shell based - * versions of 'who', 'last', etc. IP Addr is output in hex, - * little endian on x86. - * - * Modified to support all sorts of libcs by - * Erik Andersen - */ - -#include -#include - -#include -#include -#include -#include -#include "busybox.h" - -extern int dutmp_main(int argc, char **argv) -{ - - int file; - struct utmp ut; - - if (argc<2) { - file = fileno(stdin); - } else if (*argv[1] == '-' ) { - show_usage(); - } else { - file = open(argv[1], O_RDONLY); - if (file < 0) { - perror_msg_and_die(io_error, argv[1]); - } - } - -/* Kludge around the fact that the binary format for utmp has changed. */ -#if __GNU_LIBRARY__ < 5 || defined __UCLIBC__ - /* Linux libc5 */ - while (read(file, (void*)&ut, sizeof(struct utmp))) { - printf("%d|%d|%s|%s|%s|%s|%s|%lx\n", - ut.ut_type, ut.ut_pid, ut.ut_line, - ut.ut_id, ut.ut_user, ut.ut_host, - ctime(&(ut.ut_time)), - (long)ut.ut_addr); - } -#else - /* Glibc, uClibc, etc. */ - while (read(file, (void*)&ut, sizeof(struct utmp))) { - printf("%d|%d|%s|%s|%s|%s|%d|%d|%ld|%ld|%ld|%x\n", - ut.ut_type, ut.ut_pid, ut.ut_line, - ut.ut_id, ut.ut_user, ut.ut_host, - ut.ut_exit.e_termination, ut.ut_exit.e_exit, - ut.ut_session, - ut.ut_tv.tv_sec, ut.ut_tv.tv_usec, - ut.ut_addr); - } -#endif - return EXIT_SUCCESS; -} diff --git a/busybox/echo.c b/busybox/echo.c deleted file mode 100644 index 31c031528..000000000 --- a/busybox/echo.c +++ /dev/null @@ -1,152 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * echo implementation for busybox - * - * 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 - * - * Original copyright notice is retained at the end of this file. - */ - -#include -#include -#include -#include "busybox.h" - -extern int -echo_main(int argc, char** argv) -{ - int nflag = 0; - int eflag = 0; - - /* Skip argv[0]. */ - argc--; - argv++; - - while (argc > 0 && *argv[0] == '-') - { - register char *temp; - register int ix; - - /* - * 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. - */ - temp = argv[0] + 1; - - for (ix = 0; temp[ix]; ix++) - { - if (strrchr("neE", temp[ix]) == 0) - goto just_echo; - } - - if (!*temp) - goto just_echo; - - /* - * All of the options in temp are valid options to echo. - * Handle them. - */ - while (*temp) - { - if (*temp == 'n') - nflag = 1; - else if (*temp == 'e') - eflag = 1; - else if (*temp == 'E') - eflag = 0; - else - goto just_echo; - - temp++; - } - argc--; - argv++; - } - -just_echo: - while (argc > 0) { - const char *arg = argv[0]; - register int c; - - while ((c = *arg++)) { - - /* Check for escape sequence. */ - if (c == '\\' && eflag && *arg) { - if (*arg == 'c') { - /* '\c' means cancel newline. */ - nflag = 1; - arg++; - continue; - } else { - c = process_escape_sequence(&arg); - } - } - - putchar(c); - } - argc--; - argv++; - if (argc > 0) - putchar(' '); - } - if (!nflag) - putchar('\n'); - fflush(stdout); - - return EXIT_SUCCESS; -} - -/*- - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * 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. - * - * California, Berkeley and its contributors. - * 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. - * - * @(#)echo.c 8.1 (Berkeley) 5/31/93 - */ diff --git a/busybox/editors/sed.c b/busybox/editors/sed.c deleted file mode 100644 index 709fb13a8..000000000 --- a/busybox/editors/sed.c +++ /dev/null @@ -1,850 +0,0 @@ -/* - * sed.c - very minimalist version of sed - * - * 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 - * - */ - -/* - Supported features and commands in this version of sed: - - - comments ('#') - - address matching: num|/matchstr/[,num|/matchstr/|$]command - - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags) - - edit commands: (a)ppend, (i)nsert, (c)hange - - file commands: (r)ead - - backreferences in substitution expressions (\1, \2...\9) - - (Note: Specifying an address (range) to match is *optional*; commands - default to the whole pattern space if no specific address match was - requested.) - - Unsupported features: - - - transliteration (y/source-chars/dest-chars/) (use 'tr') - - no pattern space hold space storing / swapping (x, etc.) - - no labels / branching (: label, b, t, and friends) - - and lots, lots more. -*/ - -#include -#include /* for getopt() */ -#include -#include /* for strdup() */ -#include -#include /* for isspace() */ -#include -#include "busybox.h" - -/* externs */ -extern void xregcomp(regex_t *preg, const char *regex, int cflags); -extern int optind; /* in unistd.h */ -extern char *optarg; /* ditto */ - -/* options */ -static int be_quiet = 0; - - -struct sed_cmd { - - - /* GENERAL FIELDS */ - char delimiter; /* The delimiter used to separate regexps */ - - /* address storage */ - int beg_line; /* 'sed 1p' 0 == no begining line, apply commands to all lines */ - int end_line; /* 'sed 1,3p' 0 == no end line, use only beginning. -1 == $ */ - regex_t *beg_match; /* sed -e '/match/cmd' */ - regex_t *end_match; /* sed -e '/match/,/end_match/cmd' */ - - /* the command */ - char cmd; /* p,d,s (add more at your leisure :-) */ - - - /* SUBSTITUTION COMMAND SPECIFIC FIELDS */ - - /* sed -e 's/sub_match/replace/' */ - regex_t *sub_match; - char *replace; - unsigned int num_backrefs:4; /* how many back references (\1..\9) */ - /* Note: GNU/POSIX sed does not save more than nine backrefs, so - * we only use 4 bits to hold the number */ - unsigned int sub_g:1; /* sed -e 's/foo/bar/g' (global) */ - unsigned int sub_p:2; /* sed -e 's/foo/bar/p' (print substitution) */ - - - /* EDIT COMMAND (a,i,c) SPEICIFIC FIELDS */ - - char *editline; - - - /* FILE COMMAND (r) SPEICIFIC FIELDS */ - - char *filename; -}; - -/* globals */ -static struct sed_cmd *sed_cmds = NULL; /* growable arrary holding a sequence of sed cmds */ -static int ncmds = 0; /* number of sed commands */ - -/*static char *cur_file = NULL;*/ /* file currently being processed XXX: do I need this? */ - -#ifdef BB_FEATURE_CLEAN_UP -static void destroy_cmd_strs() -{ - if (sed_cmds == NULL) - return; - - /* destroy all the elements in the array */ - while (--ncmds >= 0) { - - if (sed_cmds[ncmds].beg_match) { - regfree(sed_cmds[ncmds].beg_match); - free(sed_cmds[ncmds].beg_match); - } - if (sed_cmds[ncmds].end_match) { - regfree(sed_cmds[ncmds].end_match); - free(sed_cmds[ncmds].end_match); - } - if (sed_cmds[ncmds].sub_match) { - regfree(sed_cmds[ncmds].sub_match); - free(sed_cmds[ncmds].sub_match); - } - if (sed_cmds[ncmds].replace) - free(sed_cmds[ncmds].replace); - } - - /* destroy the array */ - free(sed_cmds); - sed_cmds = NULL; -} -#endif - - -/* - * index_of_next_unescaped_regexp_delim - walks left to right through a string - * beginning at a specified index and returns the index of the next regular - * expression delimiter (typically a forward * slash ('/')) not preceeded by - * a backslash ('\'). - */ -static int index_of_next_unescaped_regexp_delim(struct sed_cmd *sed_cmd, const char *str, int idx) -{ - int bracket = -1; - int escaped = 0; - - for ( ; str[idx]; idx++) { - if (bracket != -1) { - if (str[idx] == ']' && !(bracket == idx - 1 || - (bracket == idx - 2 && str[idx-1] == '^'))) - bracket = -1; - } else if (escaped) - escaped = 0; - else if (str[idx] == '\\') - escaped = 1; - else if (str[idx] == '[') - bracket = idx; - else if (str[idx] == sed_cmd->delimiter) - return idx; - } - - /* if we make it to here, we've hit the end of the string */ - return -1; -} - -/* - * returns the index in the string just past where the address ends. - */ -static int get_address(struct sed_cmd *sed_cmd, const char *str, int *linenum, regex_t **regex) -{ - char *my_str = strdup(str); - int idx = 0; - char olddelimiter; - olddelimiter = sed_cmd->delimiter; - sed_cmd->delimiter = '/'; - - if (isdigit(my_str[idx])) { - do { - idx++; - } while (isdigit(my_str[idx])); - my_str[idx] = 0; - *linenum = atoi(my_str); - } - else if (my_str[idx] == '$') { - *linenum = -1; - idx++; - } - else if (my_str[idx] == '/') { - idx = index_of_next_unescaped_regexp_delim(sed_cmd, my_str, ++idx); - if (idx == -1) - error_msg_and_die("unterminated match expression"); - my_str[idx] = '\0'; - *regex = (regex_t *)xmalloc(sizeof(regex_t)); - xregcomp(*regex, my_str+1, REG_NEWLINE); - idx++; /* so it points to the next character after the last '/' */ - } - else { - error_msg("get_address: no address found in string\n" - "\t(you probably didn't check the string you passed me)"); - idx = -1; - } - - free(my_str); - sed_cmd->delimiter = olddelimiter; - return idx; -} - -static int parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) -{ - int oldidx, cflags = REG_NEWLINE; - char *match; - int idx = 0; - int j; - - /* - * the string that gets passed to this function should look like this: - * s/match/replace/gIp - * || | ||| - * mandatory optional - * - * (all three of the '/' slashes are mandatory) - */ - - /* verify that the 's' is followed by something. That something - * (typically a 'slash') is now our regexp delimiter... */ - if (!substr[++idx]) - error_msg_and_die("bad format in substitution expression"); - else - sed_cmd->delimiter=substr[idx]; - - /* save the match string */ - oldidx = idx+1; - idx = index_of_next_unescaped_regexp_delim(sed_cmd, substr, ++idx); - if (idx == -1) - error_msg_and_die("bad format in substitution expression"); - match = xstrndup(substr + oldidx, idx - oldidx); - - /* determine the number of back references in the match string */ - /* Note: we compute this here rather than in the do_subst_command() - * function to save processor time, at the expense of a little more memory - * (4 bits) per sed_cmd */ - - /* sed_cmd->num_backrefs = 0; */ /* XXX: not needed? --apparently not */ - for (j = 0; match[j]; j++) { - /* GNU/POSIX sed does not save more than nine backrefs */ - if (match[j] == '\\' && match[j+1] == '(' && sed_cmd->num_backrefs <= 9) - sed_cmd->num_backrefs++; - } - - /* save the replacement string */ - oldidx = idx+1; - idx = index_of_next_unescaped_regexp_delim(sed_cmd, substr, ++idx); - if (idx == -1) - error_msg_and_die("bad format in substitution expression"); - sed_cmd->replace = xstrndup(substr + oldidx, idx - oldidx); - - /* process the flags */ - while (substr[++idx]) { - switch (substr[idx]) { - case 'g': - sed_cmd->sub_g = 1; - break; - case 'I': - cflags |= REG_ICASE; - break; - case 'p': - sed_cmd->sub_p = 1; - break; - default: - /* any whitespace or semicolon trailing after a s/// is ok */ - if (strchr("; \t\v\n\r", substr[idx])) - goto out; - /* else */ - error_msg_and_die("bad option in substitution expression"); - } - } - -out: - /* compile the match string into a regex */ - sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t)); - xregcomp(sed_cmd->sub_match, match, cflags); - free(match); - - return idx; -} - -static int parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr) -{ - int idx = 0; - int slashes_eaten = 0; - char *ptr; /* shorthand */ - - /* - * the string that gets passed to this function should look like this: - * - * need one of these - * | - * | this backslash (immediately following the edit command) is mandatory - * | | - * [aic]\ - * TEXT1\ - * TEXT2\ - * TEXTN - * - * as soon as we hit a TEXT line that has no trailing '\', we're done. - * this means a command like: - * - * i\ - * INSERTME - * - * is a-ok. - * - */ - - if (editstr[1] != '\\' && (editstr[2] != '\n' || editstr[2] != '\r')) - error_msg_and_die("bad format in edit expression"); - - /* store the edit line text */ - /* make editline big enough to accomodate the extra '\n' we will tack on - * to the end */ - sed_cmd->editline = xmalloc(strlen(&editstr[3]) + 2); - strcpy(sed_cmd->editline, &editstr[3]); - ptr = sed_cmd->editline; - - /* now we need to go through * and: s/\\[\r\n]$/\n/g on the edit line */ - while (ptr[idx]) { - while (ptr[idx] != '\\' || (ptr[idx+1] != '\n' && ptr[idx+1] != '\r')) { - idx++; - if (!ptr[idx]) { - goto out; - } - } - /* move the newline over the '\' before it (effectively eats the '\') */ - memmove(&ptr[idx], &ptr[idx+1], strlen(&ptr[idx+1])); - ptr[strlen(ptr)-1] = 0; - slashes_eaten++; - /* substitue \r for \n if needed */ - if (ptr[idx] == '\r') - ptr[idx] = '\n'; - } - -out: - /* this accounts for discrepancies between the modified string and the - * original string passed in to this function */ - idx += slashes_eaten; - - /* figure out if we need to add a newline */ - if (ptr[idx-1] != '\n') { - ptr[idx] = '\n'; - idx++; - } - - /* terminate string */ - ptr[idx]= 0; - /* adjust for opening 2 chars [aic]\ */ - idx += 2; - - return idx; -} - - -static int parse_file_cmd(struct sed_cmd *sed_cmd, const char *filecmdstr) -{ - int idx = 0; - int filenamelen = 0; - - /* - * the string that gets passed to this function should look like this: - * '[ ]filename' - * | | - * | a filename - * | - * optional whitespace - - * re: the file to be read, the GNU manual says the following: "Note that - * if filename cannot be read, it is treated as if it were an empty file, - * without any error indication." Thus, all of the following commands are - * perfectly leagal: - * - * sed -e '1r noexist' - * sed -e '1r ;' - * sed -e '1r' - */ - - /* the file command may be followed by whitespace; move past it. */ - while (isspace(filecmdstr[++idx])) - { ; } - - /* the first non-whitespace we get is a filename. the filename ends when we - * hit a normal sed command terminator or end of string */ - filenamelen = strcspn(&filecmdstr[idx], "; \n\r\t\v\0"); - sed_cmd->filename = xmalloc(filenamelen + 1); - safe_strncpy(sed_cmd->filename, &filecmdstr[idx], filenamelen + 1); - - return idx + filenamelen; -} - - -static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) -{ - int idx = 0; - - /* parse the command - * format is: [addr][,addr]cmd - * |----||-----||-| - * part1 part2 part3 - */ - - /* first part (if present) is an address: either a number or a /regex/ */ - if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/') - idx = get_address(sed_cmd, cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); - - /* second part (if present) will begin with a comma */ - if (cmdstr[idx] == ',') - idx += get_address(sed_cmd, &cmdstr[++idx], &sed_cmd->end_line, &sed_cmd->end_match); - - /* last part (mandatory) will be a command */ - if (cmdstr[idx] == '\0') - error_msg_and_die("missing command"); - sed_cmd->cmd = cmdstr[idx]; - - /* if it was a single-letter command that takes no arguments (such as 'p' - * or 'd') all we need to do is increment the index past that command */ - if (strchr("pd", cmdstr[idx])) { - idx++; - } - /* handle (s)ubstitution command */ - else if (sed_cmd->cmd == 's') { - idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]); - } - /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ - else if (strchr("aic", sed_cmd->cmd)) { - if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c') - error_msg_and_die("only a beginning address can be specified for edit commands"); - idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]); - } - /* handle file cmds: (r)ead */ - else if (sed_cmd->cmd == 'r') { - if (sed_cmd->end_line || sed_cmd->end_match) - error_msg_and_die("Command only uses one address"); - idx += parse_file_cmd(sed_cmd, &cmdstr[idx]); - } - else { - error_msg_and_die("invalid command"); - } - - /* give back whatever's left over */ - return (char *)&cmdstr[idx]; -} - -static void add_cmd_str(const char *cmdstr) -{ - char *mystr = (char *)cmdstr; - - do { - - /* trim leading whitespace and semicolons */ - memmove(mystr, &mystr[strspn(mystr, "; \n\r\t\v")], strlen(mystr)); - /* if we ate the whole thing, that means there was just trailing - * whitespace or a final / no-op semicolon. either way, get out */ - if (strlen(mystr) == 0) - return; - /* if this is a comment, jump past it and keep going */ - if (mystr[0] == '#') { - mystr = strpbrk(mystr, ";\n\r"); - continue; - } - /* grow the array */ - sed_cmds = xrealloc(sed_cmds, sizeof(struct sed_cmd) * (++ncmds)); - /* zero new element */ - memset(&sed_cmds[ncmds-1], 0, sizeof(struct sed_cmd)); - /* load command string into new array element, get remainder */ - mystr = parse_cmd_str(&sed_cmds[ncmds-1], mystr); - - } while (mystr && strlen(mystr)); -} - - -static void load_cmd_file(char *filename) -{ - FILE *cmdfile; - char *line; - char *nextline; - - cmdfile = xfopen(filename, "r"); - - while ((line = get_line_from_file(cmdfile)) != NULL) { - /* if a line ends with '\' it needs the next line appended to it */ - while (line[strlen(line)-2] == '\\' && - (nextline = get_line_from_file(cmdfile)) != NULL) { - line = xrealloc(line, strlen(line) + strlen(nextline) + 1); - strcat(line, nextline); - free(nextline); - } - /* eat trailing newline (if any) --if I don't do this, edit commands - * (aic) will print an extra newline */ - chomp(line); - add_cmd_str(line); - free(line); - } -} - -#define PIPE_MAGIC 0x7f -#define PIPE_GROW 64 -#define pipeputc(c) \ -{ if (pipeline[pipeline_idx] == PIPE_MAGIC) { \ - pipeline = xrealloc(pipeline, pipeline_len+PIPE_GROW); \ - memset(pipeline+pipeline_len, 0, PIPE_GROW); \ - pipeline_len += PIPE_GROW; \ - pipeline[pipeline_len-1] = PIPE_MAGIC; } \ - pipeline[pipeline_idx++] = (c); } - -static void print_subst_w_backrefs(const char *line, const char *replace, - regmatch_t *regmatch, char **pipeline_p, int *pipeline_idx_p, - int *pipeline_len_p, int matches) -{ - char *pipeline = *pipeline_p; - int pipeline_idx = *pipeline_idx_p; - int pipeline_len = *pipeline_len_p; - int i; - - /* go through the replacement string */ - for (i = 0; replace[i]; i++) { - /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */ - if (replace[i] == '\\' && isdigit(replace[i+1])) { - int j; - char tmpstr[2]; - int backref; - ++i; /* i now indexes the backref number, instead of the leading slash */ - tmpstr[0] = replace[i]; - tmpstr[1] = 0; - backref = atoi(tmpstr); - /* print out the text held in regmatch[backref] */ - if (backref <= matches && regmatch[backref].rm_so != -1) - for (j = regmatch[backref].rm_so; j < regmatch[backref].rm_eo; j++) - pipeputc(line[j]); - } - - /* if we find a backslash escaped character, print the character */ - else if (replace[i] == '\\') { - ++i; - pipeputc(replace[i]); - } - - /* if we find an unescaped '&' print out the whole matched text. - * fortunately, regmatch[0] contains the indicies to the whole matched - * expression (kinda seems like it was designed for just such a - * purpose...) */ - else if (replace[i] == '&' && replace[i-1] != '\\') { - int j; - for (j = regmatch[0].rm_so; j < regmatch[0].rm_eo; j++) - pipeputc(line[j]); - } - /* nothing special, just print this char of the replacement string to stdout */ - else - pipeputc(replace[i]); - } - *pipeline_p = pipeline; - *pipeline_idx_p = pipeline_idx; - *pipeline_len_p = pipeline_len; -} - -static int do_subst_command(const struct sed_cmd *sed_cmd, char **line) -{ - char *hackline = *line; - char *pipeline = 0; - int pipeline_idx = 0; - int pipeline_len = 0; - int altered = 0; - regmatch_t *regmatch = NULL; - - /* we only proceed if the substitution 'search' expression matches */ - if (regexec(sed_cmd->sub_match, hackline, 0, NULL, 0) == REG_NOMATCH) - return 0; - - /* whaddaya know, it matched. get the number of back references */ - regmatch = xmalloc(sizeof(regmatch_t) * (sed_cmd->num_backrefs+1)); - - /* allocate more PIPE_GROW bytes - if replaced string is larger than original */ - pipeline_len = strlen(hackline)+PIPE_GROW; - pipeline = xmalloc(pipeline_len); - memset(pipeline, 0, pipeline_len); - /* buffer magic */ - pipeline[pipeline_len-1] = PIPE_MAGIC; - - /* and now, as long as we've got a line to try matching and if we can match - * the search string, we make substitutions */ - while ((*hackline || !altered) && (regexec(sed_cmd->sub_match, hackline, - sed_cmd->num_backrefs+1, regmatch, 0) != REG_NOMATCH) ) { - int i; - - /* print everything before the match */ - for (i = 0; i < regmatch[0].rm_so; i++) - pipeputc(hackline[i]); - - /* then print the substitution string */ - print_subst_w_backrefs(hackline, sed_cmd->replace, regmatch, - &pipeline, &pipeline_idx, &pipeline_len, - sed_cmd->num_backrefs); - - /* advance past the match */ - hackline += regmatch[0].rm_eo; - /* flag that something has changed */ - altered++; - - /* if we're not doing this globally, get out now */ - if (!sed_cmd->sub_g) - break; - } - - for (; *hackline; hackline++) pipeputc(*hackline); - if (pipeline[pipeline_idx] == PIPE_MAGIC) pipeline[pipeline_idx] = 0; - - /* cleanup */ - free(regmatch); - - free(*line); - *line = pipeline; - return altered; -} - - -static void process_file(FILE *file) -{ - char *line = NULL; - static int linenum = 0; /* GNU sed does not restart counting lines at EOF */ - unsigned int still_in_range = 0; - int altered; - int i; - - /* go through every line in the file */ - while ((line = get_line_from_file(file)) != NULL) { - - chomp(line); - linenum++; - altered = 0; - - /* for every line, go through all the commands */ - for (i = 0; i < ncmds; i++) { - - - /* - * entry point into sedding... - */ - if ( - /* no range necessary */ - (sed_cmds[i].beg_line == 0 && sed_cmds[i].end_line == 0 && - sed_cmds[i].beg_match == NULL && - sed_cmds[i].end_match == NULL) || - /* this line number is the first address we're looking for */ - (sed_cmds[i].beg_line && (sed_cmds[i].beg_line == linenum)) || - /* this line matches our first address regex */ - (sed_cmds[i].beg_match && (regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0)) || - /* we are currently within the beginning & ending address range */ - still_in_range - ) { - - /* - * actual sedding - */ - switch (sed_cmds[i].cmd) { - - case 'p': - puts(line); - break; - - case 'd': - altered++; - break; - - case 's': - - /* - * Some special cases for 's' printing to make it compliant with - * GNU sed printing behavior (aka "The -n | s///p Matrix"): - * - * -n ONLY = never print anything regardless of any successful - * substitution - * - * s///p ONLY = always print successful substitutions, even if - * the line is going to be printed anyway (line will be printed - * twice). - * - * -n AND s///p = print ONLY a successful substitution ONE TIME; - * no other lines are printed - this is the reason why the 'p' - * flag exists in the first place. - */ - - /* if the user specified that they didn't want anything printed (i.e., a -n - * flag and no 'p' flag after the s///), then there's really no point doing - * anything here. */ - if (be_quiet && !sed_cmds[i].sub_p) - break; - - /* we print the line once, unless we were told to be quiet */ - if (!be_quiet) - altered |= do_subst_command(&sed_cmds[i], &line); - - /* we also print the line if we were given the 'p' flag - * (this is quite possibly the second printing) */ - if (sed_cmds[i].sub_p) - altered |= do_subst_command(&sed_cmds[i], &line); - if (altered && (i+1 >= ncmds || sed_cmds[i+1].cmd != 's')) - puts(line); - - break; - - case 'a': - puts(line); - fputs(sed_cmds[i].editline, stdout); - altered++; - break; - - case 'i': - fputs(sed_cmds[i].editline, stdout); - break; - - case 'c': - /* single-address case */ - if (sed_cmds[i].end_match == NULL && sed_cmds[i].end_line == 0) { - fputs(sed_cmds[i].editline, stdout); - } - /* multi-address case */ - else { - /* matching text */ - if (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0)) - fputs(sed_cmds[i].editline, stdout); - /* matching line numbers */ - if (sed_cmds[i].end_line > 0 && sed_cmds[i].end_line == linenum) - fputs(sed_cmds[i].editline, stdout); - } - altered++; - - break; - - case 'r': { - FILE *outfile; - puts(line); - outfile = fopen(sed_cmds[i].filename, "r"); - if (outfile) - print_file(outfile); - /* else if we couldn't open the output file, - * no biggie, just don't print anything */ - altered++; - } - break; - } - - /* - * exit point from sedding... - */ - if ( - /* this is a single-address command or... */ - (sed_cmds[i].end_line == 0 && sed_cmds[i].end_match == NULL) || ( - /* we were in the middle of our address range (this - * isn't the first time through) and.. */ - (still_in_range == 1) && ( - /* this line number is the last address we're looking for or... */ - (sed_cmds[i].end_line && (sed_cmds[i].end_line == linenum)) || - /* this line matches our last address regex */ - (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0)) - ) - ) - ) { - /* we're out of our address range */ - still_in_range = 0; - } - - /* didn't hit the exit? then we're still in the middle of an address range */ - else { - still_in_range = 1; - } - } - } - - /* we will print the line unless we were told to be quiet or if the - * line was altered (via a 'd'elete or 's'ubstitution), in which case - * the altered line was already printed */ - if (!be_quiet && !altered) - puts(line); - - free(line); - } -} - -extern int sed_main(int argc, char **argv) -{ - int opt; - -#ifdef BB_FEATURE_CLEAN_UP - /* destroy command strings on exit */ - if (atexit(destroy_cmd_strs) == -1) - perror_msg_and_die("atexit"); -#endif - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "ne:f:")) > 0) { - switch (opt) { - case 'n': - be_quiet++; - break; - case 'e': - add_cmd_str(optarg); - break; - case 'f': - load_cmd_file(optarg); - break; - default: - show_usage(); - } - } - - /* if we didn't get a pattern from a -e and no command file was specified, - * argv[optind] should be the pattern. no pattern, no worky */ - if (ncmds == 0) { - if (argv[optind] == NULL) - show_usage(); - else { - add_cmd_str(argv[optind]); - optind++; - } - } - - - /* 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)) { - process_file(stdin); - } - else { - int i; - FILE *file; - for (i = optind; i < argc; i++) { - file = fopen(argv[i], "r"); - if (file == NULL) { - perror_msg("%s", argv[i]); - } else { - process_file(file); - fclose(file); - } - } - } - - return 0; -} diff --git a/busybox/editors/vi.c b/busybox/editors/vi.c deleted file mode 100644 index 8d7506d0f..000000000 --- a/busybox/editors/vi.c +++ /dev/null @@ -1,3947 +0,0 @@ -/* vi: set sw=8 ts=8: */ -/* - * tiny vi.c: A small 'vi' clone - * Copyright (C) 2000, 2001 Sterling Huxley - * - * 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. - */ - -static const char vi_Version[] = - "$Id: vi.c,v 1.15 2001/08/02 05:26:41 andersen Exp $"; - -/* - * To compile for standalone use: - * gcc -Wall -Os -s -DSTANDALONE -o vi vi.c - * or - * gcc -Wall -Os -s -DSTANDALONE -DBB_FEATURE_VI_CRASHME -o vi vi.c # include testing features - * strip vi - */ - -/* - * Things To Do: - * EXINIT - * $HOME/.exrc and ./.exrc - * add magic to search /foo.*bar - * add :help command - * :map macros - * how about mode lines: vi: set sw=8 ts=8: - * if mark[] values were line numbers rather than pointers - * it would be easier to change the mark when add/delete lines - * More intelligence in refresh() - * ":r !cmd" and "!cmd" to filter text through an external command - * A true "undo" facility - * An "ex" line oriented mode- maybe using "cmdedit" - */ - -//---- Feature -------------- Bytes to immplement -#ifdef STANDALONE -#define vi_main main -#define BB_FEATURE_VI_COLON // 4288 -#define BB_FEATURE_VI_YANKMARK // 1408 -#define BB_FEATURE_VI_SEARCH // 1088 -#define BB_FEATURE_VI_USE_SIGNALS // 1056 -#define BB_FEATURE_VI_DOT_CMD // 576 -#define BB_FEATURE_VI_READONLY // 128 -#define BB_FEATURE_VI_SETOPTS // 576 -#define BB_FEATURE_VI_SET // 224 -#define BB_FEATURE_VI_WIN_RESIZE // 256 WIN_RESIZE -// To test editor using CRASHME: -// vi -C filename -// To stop testing, wait until all to text[] is deleted, or -// Ctrl-Z and kill -9 %1 -// while in the editor Ctrl-T will toggle the crashme function on and off. -//#define BB_FEATURE_VI_CRASHME // randomly pick commands to execute -#endif /* STANDALONE */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef STANDALONE -#include "busybox.h" -#endif /* STANDALONE */ - -#ifndef TRUE -#define TRUE ((int)1) -#define FALSE ((int)0) -#endif /* TRUE */ -#define MAX_SCR_COLS BUFSIZ - -// Misc. non-Ascii keys that report an escape sequence -#define VI_K_UP 128 // cursor key Up -#define VI_K_DOWN 129 // cursor key Down -#define VI_K_RIGHT 130 // Cursor Key Right -#define VI_K_LEFT 131 // cursor key Left -#define VI_K_HOME 132 // Cursor Key Home -#define VI_K_END 133 // Cursor Key End -#define VI_K_INSERT 134 // Cursor Key Insert -#define VI_K_PAGEUP 135 // Cursor Key Page Up -#define VI_K_PAGEDOWN 136 // Cursor Key Page Down -#define VI_K_FUN1 137 // Function Key F1 -#define VI_K_FUN2 138 // Function Key F2 -#define VI_K_FUN3 139 // Function Key F3 -#define VI_K_FUN4 140 // Function Key F4 -#define VI_K_FUN5 141 // Function Key F5 -#define VI_K_FUN6 142 // Function Key F6 -#define VI_K_FUN7 143 // Function Key F7 -#define VI_K_FUN8 144 // Function Key F8 -#define VI_K_FUN9 145 // Function Key F9 -#define VI_K_FUN10 146 // Function Key F10 -#define VI_K_FUN11 147 // Function Key F11 -#define VI_K_FUN12 148 // Function Key F12 - -static const int YANKONLY = FALSE; -static const int YANKDEL = TRUE; -static const int FORWARD = 1; // code depends on "1" for array index -static const int BACK = -1; // code depends on "-1" for array index -static const int LIMITED = 0; // how much of text[] in char_search -static const int FULL = 1; // how much of text[] in char_search - -static const int S_BEFORE_WS = 1; // used in skip_thing() for moving "dot" -static const int S_TO_WS = 2; // used in skip_thing() for moving "dot" -static const int S_OVER_WS = 3; // used in skip_thing() for moving "dot" -static const int S_END_PUNCT = 4; // used in skip_thing() for moving "dot" -static const int S_END_ALNUM = 5; // used in skip_thing() for moving "dot" - -typedef unsigned char Byte; - - -static int editing; // >0 while we are editing a file -static int cmd_mode; // 0=command 1=insert -static int file_modified; // buffer contents changed -static int err_method; // indicate error with beep or flash -static int fn_start; // index of first cmd line file name -static int save_argc; // how many file names on cmd line -static int cmdcnt; // repetition count -static fd_set rfds; // use select() for small sleeps -static struct timeval tv; // use select() for small sleeps -static char erase_char; // the users erase character -static int rows, columns; // the terminal screen is this size -static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset -static char *SOs, *SOn; // terminal standout start/normal ESC sequence -static char *bell; // terminal bell sequence -static char *Ceol, *Ceos; // Clear-end-of-line and Clear-end-of-screen ESC sequence -static char *CMrc; // Cursor motion arbitrary destination ESC sequence -static char *CMup, *CMdown; // Cursor motion up and down ESC sequence -static Byte *status_buffer; // mesages to the user -static Byte last_input_char; // last char read from user -static Byte last_forward_char; // last char searched for with 'f' -static Byte *cfn; // previous, current, and next file name -static Byte *text, *end, *textend; // pointers to the user data in memory -static Byte *screen; // pointer to the virtual screen buffer -static int screensize; // and its size -static Byte *screenbegin; // index into text[], of top line on the screen -static Byte *dot; // where all the action takes place -static int tabstop; -static struct termios term_orig, term_vi; // remember what the cooked mode was - -#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR -static int last_row; // where the cursor was last moved to -#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ -#ifdef BB_FEATURE_VI_USE_SIGNALS -static jmp_buf restart; // catch_sig() -#endif /* BB_FEATURE_VI_USE_SIGNALS */ -#ifdef BB_FEATURE_VI_WIN_RESIZE -static struct winsize winsize; // remember the window size -#endif /* BB_FEATURE_VI_WIN_RESIZE */ -#ifdef BB_FEATURE_VI_DOT_CMD -static int adding2q; // are we currently adding user input to q -static Byte *last_modifying_cmd; // last modifying cmd for "." -static Byte *ioq, *ioq_start; // pointer to string for get_one_char to "read" -#endif /* BB_FEATURE_VI_DOT_CMD */ -#if defined(BB_FEATURE_VI_DOT_CMD) || defined(BB_FEATURE_VI_YANKMARK) -static Byte *modifying_cmds; // cmds that modify text[] -#endif /* BB_FEATURE_VI_DOT_CMD || BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_READONLY -static int vi_readonly, readonly; -#endif /* BB_FEATURE_VI_READONLY */ -#ifdef BB_FEATURE_VI_SETOPTS -static int autoindent; -static int showmatch; -static int ignorecase; -#endif /* BB_FEATURE_VI_SETOPTS */ -#ifdef BB_FEATURE_VI_YANKMARK -static Byte *reg[28]; // named register a-z, "D", and "U" 0-25,26,27 -static int YDreg, Ureg; // default delete register and orig line for "U" -static Byte *mark[28]; // user marks points somewhere in text[]- a-z and previous context '' -static Byte *context_start, *context_end; -#endif /* BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_SEARCH -static Byte *last_search_pattern; // last pattern from a '/' or '?' search -#endif /* BB_FEATURE_VI_SEARCH */ - - -static void edit_file(Byte *); // edit one file -static void do_cmd(Byte); // execute a command -static void sync_cursor(Byte *, int *, int *); // synchronize the screen cursor to dot -static Byte *begin_line(Byte *); // return pointer to cur line B-o-l -static Byte *end_line(Byte *); // return pointer to cur line E-o-l -static Byte *dollar_line(Byte *); // return pointer to just before NL -static Byte *prev_line(Byte *); // return pointer to prev line B-o-l -static Byte *next_line(Byte *); // return pointer to next line B-o-l -static Byte *end_screen(void); // get pointer to last char on screen -static int count_lines(Byte *, Byte *); // count line from start to stop -static Byte *find_line(int); // find begining of line #li -static Byte *move_to_col(Byte *, int); // move "p" to column l -static int isblnk(Byte); // is the char a blank or tab -static void dot_left(void); // move dot left- dont leave line -static void dot_right(void); // move dot right- dont leave line -static void dot_begin(void); // move dot to B-o-l -static void dot_end(void); // move dot to E-o-l -static void dot_next(void); // move dot to next line B-o-l -static void dot_prev(void); // move dot to prev line B-o-l -static void dot_scroll(int, int); // move the screen up or down -static void dot_skip_over_ws(void); // move dot pat WS -static void dot_delete(void); // delete the char at 'dot' -static Byte *bound_dot(Byte *); // make sure text[0] <= P < "end" -static Byte *new_screen(int, int); // malloc virtual screen memory -static Byte *new_text(int); // malloc memory for text[] buffer -static Byte *char_insert(Byte *, Byte); // insert the char c at 'p' -static Byte *stupid_insert(Byte *, Byte); // stupidly insert the char c at 'p' -static Byte find_range(Byte **, Byte **, Byte); // return pointers for an object -static int st_test(Byte *, int, int, Byte *); // helper for skip_thing() -static Byte *skip_thing(Byte *, int, int, int); // skip some object -static Byte *find_pair(Byte *, Byte); // find matching pair () [] {} -static Byte *text_hole_delete(Byte *, Byte *); // at "p", delete a 'size' byte hole -static Byte *text_hole_make(Byte *, int); // at "p", make a 'size' byte hole -static Byte *yank_delete(Byte *, Byte *, int, int); // yank text[] into register then delete -static void show_help(void); // display some help info -static void print_literal(Byte *, Byte *); // copy s to buf, convert unprintable -static void rawmode(void); // set "raw" mode on tty -static void cookmode(void); // return to "cooked" mode on tty -static int mysleep(int); // sleep for 'h' 1/100 seconds -static Byte readit(void); // read (maybe cursor) key from stdin -static Byte get_one_char(void); // read 1 char from stdin -static int file_size(Byte *); // what is the byte size of "fn" -static int file_insert(Byte *, Byte *, int); -static int file_write(Byte *, Byte *, Byte *); -static void place_cursor(int, int, int); -static void screen_erase(); -static void clear_to_eol(void); -static void clear_to_eos(void); -static void standout_start(void); // send "start reverse video" sequence -static void standout_end(void); // send "end reverse video" sequence -static void flash(int); // flash the terminal screen -static void beep(void); // beep the terminal -static void indicate_error(char); // use flash or beep to indicate error -static void show_status_line(void); // put a message on the bottom line -static void psb(char *, ...); // Print Status Buf -static void psbs(char *, ...); // Print Status Buf in standout mode -static void ni(Byte *); // display messages -static void edit_status(void); // show file status on status line -static void redraw(int); // force a full screen refresh -static void format_line(Byte*, Byte*, int); -static void refresh(int); // update the terminal from screen[] - -#ifdef BB_FEATURE_VI_SEARCH -static Byte *char_search(Byte *, Byte *, int, int); // search for pattern starting at p -static int mycmp(Byte *, Byte *, int); // string cmp based in "ignorecase" -#endif /* BB_FEATURE_VI_SEARCH */ -#ifdef BB_FEATURE_VI_COLON -static void Hit_Return(void); -static Byte *get_one_address(Byte *, int *); // get colon addr, if present -static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present -static void colon(Byte *); // execute the "colon" mode cmds -#endif /* BB_FEATURE_VI_COLON */ -static Byte *get_input_line(Byte *); // get input line- use "status line" -#ifdef BB_FEATURE_VI_USE_SIGNALS -static void winch_sig(int); // catch window size changes -static void suspend_sig(int); // catch ctrl-Z -static void alarm_sig(int); // catch alarm time-outs -static void catch_sig(int); // catch ctrl-C -static void core_sig(int); // catch a core dump signal -#endif /* BB_FEATURE_VI_USE_SIGNALS */ -#ifdef BB_FEATURE_VI_DOT_CMD -static void start_new_cmd_q(Byte); // new queue for command -static void end_cmd_q(); // stop saving input chars -#else /* BB_FEATURE_VI_DOT_CMD */ -#define end_cmd_q() -#endif /* BB_FEATURE_VI_DOT_CMD */ -#ifdef BB_FEATURE_VI_WIN_RESIZE -static void window_size_get(int); // find out what size the window is -#endif /* BB_FEATURE_VI_WIN_RESIZE */ -#ifdef BB_FEATURE_VI_SETOPTS -static void showmatching(Byte *); // show the matching pair () [] {} -#endif /* BB_FEATURE_VI_SETOPTS */ -#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME) -static Byte *string_insert(Byte *, Byte *); // insert the string at 'p' -#endif /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */ -#ifdef BB_FEATURE_VI_YANKMARK -static Byte *text_yank(Byte *, Byte *, int); // save copy of "p" into a register -static Byte what_reg(void); // what is letter of current YDreg -static void check_context(Byte); // remember context for '' command -static Byte *swap_context(Byte *); // goto new context for '' command -#endif /* BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_CRASHME -static void crash_dummy(); -static void crash_test(); -static int crashme = 0; -#endif /* BB_FEATURE_VI_CRASHME */ - - -extern int vi_main(int argc, char **argv) -{ - int c; - -#ifdef BB_FEATURE_VI_YANKMARK - int i; -#endif /* BB_FEATURE_VI_YANKMARK */ - - CMrc= "\033[%d;%dH"; // Terminal Crusor motion ESC sequence - CMup= "\033[A"; // move cursor up one line, same col - CMdown="\n"; // move cursor down one line, same col - Ceol= "\033[0K"; // Clear from cursor to end of line - Ceos= "\033[0J"; // Clear from cursor to end of screen - SOs = "\033[7m"; // Terminal standout mode on - SOn = "\033[0m"; // Terminal standout mode off - bell= "\007"; // Terminal bell sequence -#ifdef BB_FEATURE_VI_CRASHME - (void) srand((long) getpid()); -#endif /* BB_FEATURE_VI_CRASHME */ - status_buffer = (Byte *) malloc(200); // hold messages to user -#ifdef BB_FEATURE_VI_READONLY - vi_readonly = readonly = FALSE; - if (strncmp(argv[0], "view", 4) == 0) { - readonly = TRUE; - vi_readonly = TRUE; - } -#endif /* BB_FEATURE_VI_READONLY */ -#ifdef BB_FEATURE_VI_SETOPTS - autoindent = 1; - ignorecase = 1; - showmatch = 1; -#endif /* BB_FEATURE_VI_SETOPTS */ -#ifdef BB_FEATURE_VI_YANKMARK - for (i = 0; i < 28; i++) { - reg[i] = 0; - } // init the yank regs -#endif /* BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_DOT_CMD - modifying_cmds = (Byte *) "aAcCdDiIJoOpPrRsxX<>~"; // cmds modifying text[] -#endif /* BB_FEATURE_VI_DOT_CMD */ - - // 1- process $HOME/.exrc file - // 2- process EXINIT variable from environment - // 3- process command line args - while ((c = getopt(argc, argv, "hCR")) != -1) { - switch (c) { -#ifdef BB_FEATURE_VI_CRASHME - case 'C': - crashme = 1; - break; -#endif /* BB_FEATURE_VI_CRASHME */ -#ifdef BB_FEATURE_VI_READONLY - case 'R': // Read-only flag - readonly = TRUE; - break; -#endif /* BB_FEATURE_VI_READONLY */ - //case 'r': // recover flag- ignore- we don't use tmp file - //case 'x': // encryption flag- ignore - //case 'c': // execute command first - //case 'h': // help -- just use default - default: - show_help(); - return 1; - } - } - - // The argv array can be used by the ":next" and ":rewind" commands - // save optind. - fn_start = optind; // remember first file name for :next and :rew - save_argc = argc; - - //----- This is the main file handling loop -------------- - if (optind >= argc) { - editing = 1; // 0= exit, 1= one file, 2= multiple files - edit_file(0); - } else { - for (; optind < argc; optind++) { - editing = 1; // 0=exit, 1=one file, 2+ =many files - if (cfn != 0) - free(cfn); - cfn = (Byte *) strdup(argv[optind]); - edit_file(cfn); - } - } - //----------------------------------------------------------- - - return (0); -} - -static void edit_file(Byte * fn) -{ - char c; - int cnt, size, ch; - -#ifdef BB_FEATURE_VI_USE_SIGNALS - char *msg; - int sig; -#endif /* BB_FEATURE_VI_USE_SIGNALS */ -#ifdef BB_FEATURE_VI_YANKMARK - static Byte *cur_line; -#endif /* BB_FEATURE_VI_YANKMARK */ - - rawmode(); - rows = 24; - columns = 80; - ch= -1; -#ifdef BB_FEATURE_VI_WIN_RESIZE - window_size_get(0); -#endif /* BB_FEATURE_VI_WIN_RESIZE */ - new_screen(rows, columns); // get memory for virtual screen - - cnt = file_size(fn); // file size - size = 2 * cnt; // 200% of file size - new_text(size); // get a text[] buffer - screenbegin = dot = end = text; - if (fn != 0) { - ch= file_insert(fn, text, cnt); - } - if (ch < 1) { - (void) char_insert(text, '\n'); // start empty buf with dummy line - } - file_modified = FALSE; -#ifdef BB_FEATURE_VI_YANKMARK - YDreg = 26; // default Yank/Delete reg - Ureg = 27; // hold orig line for "U" cmd - for (cnt = 0; cnt < 28; cnt++) { - mark[cnt] = 0; - } // init the marks - mark[26] = mark[27] = text; // init "previous context" -#endif /* BB_FEATURE_VI_YANKMARK */ - - err_method = 1; // flash - last_forward_char = last_input_char = '\0'; - crow = 0; - ccol = 0; - edit_status(); - -#ifdef BB_FEATURE_VI_USE_SIGNALS - signal(SIGHUP, catch_sig); - signal(SIGINT, catch_sig); - signal(SIGALRM, alarm_sig); - signal(SIGTERM, catch_sig); - signal(SIGQUIT, core_sig); - signal(SIGILL, core_sig); - signal(SIGTRAP, core_sig); - signal(SIGIOT, core_sig); - signal(SIGABRT, core_sig); - signal(SIGFPE, core_sig); - signal(SIGBUS, core_sig); - signal(SIGSEGV, core_sig); -#ifdef SIGSYS - signal(SIGSYS, core_sig); -#endif - signal(SIGWINCH, winch_sig); - signal(SIGTSTP, suspend_sig); - sig = setjmp(restart); - if (sig != 0) { - msg = ""; - if (sig == SIGWINCH) - msg = "(window resize)"; - if (sig == SIGHUP) - msg = "(hangup)"; - if (sig == SIGINT) - msg = "(interrupt)"; - if (sig == SIGTERM) - msg = "(terminate)"; - if (sig == SIGBUS) - msg = "(bus error)"; - if (sig == SIGSEGV) - msg = "(I tried to touch invalid memory)"; - if (sig == SIGALRM) - msg = "(alarm)"; - - psbs("-- caught signal %d %s--", sig, msg); - screenbegin = dot = text; - } -#endif /* BB_FEATURE_VI_USE_SIGNALS */ - - editing = 1; - cmd_mode = 0; // 0=command 1=insert 2='R'eplace - cmdcnt = 0; - tabstop = 8; - offset = 0; // no horizontal offset - c = '\0'; -#ifdef BB_FEATURE_VI_DOT_CMD - if (last_modifying_cmd != 0) - free(last_modifying_cmd); - if (ioq_start != NULL) - free(ioq_start); - ioq = ioq_start = last_modifying_cmd = 0; - adding2q = 0; -#endif /* BB_FEATURE_VI_DOT_CMD */ - redraw(FALSE); // dont force every col re-draw - show_status_line(); - - //------This is the main Vi cmd handling loop ----------------------- - while (editing > 0) { -#ifdef BB_FEATURE_VI_CRASHME - if (crashme > 0) { - if ((end - text) > 1) { - crash_dummy(); // generate a random command - } else { - crashme = 0; - dot = - string_insert(text, (Byte *) "\n\n##### Ran out of text to work on. #####\n\n"); // insert the string - refresh(FALSE); - } - } -#endif /* BB_FEATURE_VI_CRASHME */ - last_input_char = c = get_one_char(); // get a cmd from user -#ifdef BB_FEATURE_VI_YANKMARK - // save a copy of the current line- for the 'U" command - if (begin_line(dot) != cur_line) { - cur_line = begin_line(dot); - text_yank(begin_line(dot), end_line(dot), Ureg); - } -#endif /* BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_DOT_CMD - // These are commands that change text[]. - // Remember the input for the "." command - if (!adding2q && ioq_start == 0 - && strchr((char *) modifying_cmds, c) != NULL) { - start_new_cmd_q(c); - } -#endif /* BB_FEATURE_VI_DOT_CMD */ - do_cmd(c); // execute the user command - // - // poll to see if there is input already waiting. if we are - // not able to display output fast enough to keep up, skip - // the display update until we catch up with input. - if (mysleep(0) == 0) { - // no input pending- so update output - refresh(FALSE); - show_status_line(); - } -#ifdef BB_FEATURE_VI_CRASHME - if (crashme > 0) - crash_test(); // test editor variables -#endif /* BB_FEATURE_VI_CRASHME */ - } - //------------------------------------------------------------------- - - place_cursor(rows, 0, FALSE); // go to bottom of screen - clear_to_eol(); // Erase to end of line - cookmode(); -} - -static Byte readbuffer[BUFSIZ]; - -#ifdef BB_FEATURE_VI_CRASHME -static int totalcmds = 0; -static int Mp = 85; // Movement command Probability -static int Np = 90; // Non-movement command Probability -static int Dp = 96; // Delete command Probability -static int Ip = 97; // Insert command Probability -static int Yp = 98; // Yank command Probability -static int Pp = 99; // Put command Probability -static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0; -char chars[20] = "\t012345 abcdABCD-=.$"; -char *words[20] = { "this", "is", "a", "test", - "broadcast", "the", "emergency", "of", - "system", "quick", "brown", "fox", - "jumped", "over", "lazy", "dogs", - "back", "January", "Febuary", "March" -}; -char *lines[20] = { - "You should have received a copy of the GNU General Public License\n", - "char c, cm, *cmd, *cmd1;\n", - "generate a command by percentages\n", - "Numbers may be typed as a prefix to some commands.\n", - "Quit, discarding changes!\n", - "Forced write, if permission originally not valid.\n", - "In general, any ex or ed command (such as substitute or delete).\n", - "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n", - "Please get w/ me and I will go over it with you.\n", - "The following is a list of scheduled, committed changes.\n", - "1. Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n", - "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n", - "Any question about transactions please contact Sterling Huxley.\n", - "I will try to get back to you by Friday, December 31.\n", - "This Change will be implemented on Friday.\n", - "Let me know if you have problems accessing this;\n", - "Sterling Huxley recently added you to the access list.\n", - "Would you like to go to lunch?\n", - "The last command will be automatically run.\n", - "This is too much english for a computer geek.\n", -}; -char *multilines[20] = { - "You should have received a copy of the GNU General Public License\n", - "char c, cm, *cmd, *cmd1;\n", - "generate a command by percentages\n", - "Numbers may be typed as a prefix to some commands.\n", - "Quit, discarding changes!\n", - "Forced write, if permission originally not valid.\n", - "In general, any ex or ed command (such as substitute or delete).\n", - "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n", - "Please get w/ me and I will go over it with you.\n", - "The following is a list of scheduled, committed changes.\n", - "1. Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n", - "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n", - "Any question about transactions please contact Sterling Huxley.\n", - "I will try to get back to you by Friday, December 31.\n", - "This Change will be implemented on Friday.\n", - "Let me know if you have problems accessing this;\n", - "Sterling Huxley recently added you to the access list.\n", - "Would you like to go to lunch?\n", - "The last command will be automatically run.\n", - "This is too much english for a computer geek.\n", -}; - -// create a random command to execute -static void crash_dummy() -{ - static int sleeptime; // how long to pause between commands - char c, cm, *cmd, *cmd1; - int i, cnt, thing, rbi, startrbi, percent; - - // "dot" movement commands - cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL"; - - // is there already a command running? - if (strlen((char *) readbuffer) > 0) - goto cd1; - cd0: - startrbi = rbi = 0; - sleeptime = 0; // how long to pause between commands - memset(readbuffer, '\0', BUFSIZ - 1); // clear the read buffer - // generate a command by percentages - percent = (int) lrand48() % 100; // get a number from 0-99 - if (percent < Mp) { // Movement commands - // available commands - cmd = cmd1; - M++; - } else if (percent < Np) { // non-movement commands - cmd = "mz<>\'\""; // available commands - N++; - } else if (percent < Dp) { // Delete commands - cmd = "dx"; // available commands - D++; - } else if (percent < Ip) { // Inset commands - cmd = "iIaAsrJ"; // available commands - I++; - } else if (percent < Yp) { // Yank commands - cmd = "yY"; // available commands - Y++; - } else if (percent < Pp) { // Put commands - cmd = "pP"; // available commands - P++; - } else { - // We do not know how to handle this command, try again - U++; - goto cd0; - } - // randomly pick one of the available cmds from "cmd[]" - i = (int) lrand48() % strlen(cmd); - cm = cmd[i]; - if (strchr(":\024", cm)) - goto cd0; // dont allow colon or ctrl-T commands - readbuffer[rbi++] = cm; // put cmd into input buffer - - // now we have the command- - // there are 1, 2, and multi char commands - // find out which and generate the rest of command as necessary - if (strchr("dmryz<>\'\"", cm)) { // 2-char commands - cmd1 = " \n\r0$^-+wWeEbBhjklHL"; - if (cm == 'm' || cm == '\'' || cm == '\"') { // pick a reg[] - cmd1 = "abcdefghijklmnopqrstuvwxyz"; - } - thing = (int) lrand48() % strlen(cmd1); // pick a movement command - c = cmd1[thing]; - readbuffer[rbi++] = c; // add movement to input buffer - } - if (strchr("iIaAsc", cm)) { // multi-char commands - if (cm == 'c') { - // change some thing - thing = (int) lrand48() % strlen(cmd1); // pick a movement command - c = cmd1[thing]; - readbuffer[rbi++] = c; // add movement to input buffer - } - thing = (int) lrand48() % 4; // what thing to insert - cnt = (int) lrand48() % 10; // how many to insert - for (i = 0; i < cnt; i++) { - if (thing == 0) { // insert chars - readbuffer[rbi++] = chars[((int) lrand48() % strlen(chars))]; - } else if (thing == 1) { // insert words - strcat((char *) readbuffer, words[(int) lrand48() % 20]); - strcat((char *) readbuffer, " "); - sleeptime = 0; // how fast to type - } else if (thing == 2) { // insert lines - strcat((char *) readbuffer, lines[(int) lrand48() % 20]); - sleeptime = 0; // how fast to type - } else { // insert multi-lines - strcat((char *) readbuffer, multilines[(int) lrand48() % 20]); - sleeptime = 0; // how fast to type - } - } - strcat((char *) readbuffer, "\033"); - } - cd1: - totalcmds++; - if (sleeptime > 0) - (void) mysleep(sleeptime); // sleep 1/100 sec -} - -// test to see if there are any errors -static void crash_test() -{ - static time_t oldtim; - time_t tim; - char d[2], buf[BUFSIZ], msg[BUFSIZ]; - - msg[0] = '\0'; - if (end < text) { - strcat((char *) msg, "end textend) { - strcat((char *) msg, "end>textend "); - } - if (dot < text) { - strcat((char *) msg, "dot end) { - strcat((char *) msg, "dot>end "); - } - if (screenbegin < text) { - strcat((char *) msg, "screenbegin end - 1) { - strcat((char *) msg, "screenbegin>end-1 "); - } - - if (strlen(msg) > 0) { - alarm(0); - sprintf(buf, "\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s", - totalcmds, last_input_char, msg, SOs, SOn); - write(1, buf, strlen(buf)); - while (read(0, d, 1) > 0) { - if (d[0] == '\n' || d[0] == '\r') - break; - } - alarm(3); - } - tim = (time_t) time((time_t *) 0); - if (tim >= (oldtim + 3)) { - sprintf((char *) status_buffer, - "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d", - totalcmds, M, N, I, D, Y, P, U, end - text + 1); - oldtim = tim; - } - return; -} -#endif /* BB_FEATURE_VI_CRASHME */ - -//--------------------------------------------------------------------- -//----- the Ascii Chart ----------------------------------------------- -// -// 00 nul 01 soh 02 stx 03 etx 04 eot 05 enq 06 ack 07 bel -// 08 bs 09 ht 0a nl 0b vt 0c np 0d cr 0e so 0f si -// 10 dle 11 dc1 12 dc2 13 dc3 14 dc4 15 nak 16 syn 17 etb -// 18 can 19 em 1a sub 1b esc 1c fs 1d gs 1e rs 1f us -// 20 sp 21 ! 22 " 23 # 24 $ 25 % 26 & 27 ' -// 28 ( 29 ) 2a * 2b + 2c , 2d - 2e . 2f / -// 30 0 31 1 32 2 33 3 34 4 35 5 36 6 37 7 -// 38 8 39 9 3a : 3b ; 3c < 3d = 3e > 3f ? -// 40 @ 41 A 42 B 43 C 44 D 45 E 46 F 47 G -// 48 H 49 I 4a J 4b K 4c L 4d M 4e N 4f O -// 50 P 51 Q 52 R 53 S 54 T 55 U 56 V 57 W -// 58 X 59 Y 5a Z 5b [ 5c \ 5d ] 5e ^ 5f _ -// 60 ` 61 a 62 b 63 c 64 d 65 e 66 f 67 g -// 68 h 69 i 6a j 6b k 6c l 6d m 6e n 6f o -// 70 p 71 q 72 r 73 s 74 t 75 u 76 v 77 w -// 78 x 79 y 7a z 7b { 7c | 7d } 7e ~ 7f del -//--------------------------------------------------------------------- - -//----- Execute a Vi Command ----------------------------------- -static void do_cmd(Byte c) -{ - Byte c1, *p, *q, *msg, buf[9], *save_dot; - int cnt, i, j, dir, yf; - - c1 = c; // quiet the compiler - cnt = yf = dir = 0; // quiet the compiler - p = q = save_dot = msg = buf; // quiet the compiler - memset(buf, '\0', 9); // clear buf - if (cmd_mode == 2) { - // we are 'R'eplacing the current *dot with new char - if (*dot == '\n') { - // don't Replace past E-o-l - cmd_mode = 1; // convert to insert - } else { - if (1 <= c && c <= 127) { // only ASCII chars - if (c != 27) - dot = yank_delete(dot, dot, 0, YANKDEL); // delete char - dot = char_insert(dot, c); // insert new char - } - goto dc1; - } - } - if (cmd_mode == 1) { - // hitting "Insert" twice means "R" replace mode - if (c == VI_K_INSERT) goto dc5; - // insert the char c at "dot" - if (1 <= c && c <= 127) { - dot = char_insert(dot, c); // only ASCII chars - } - goto dc1; - } - - switch (c) { - //case 0x01: // soh - //case 0x09: // ht - //case 0x0b: // vt - //case 0x0e: // so - //case 0x0f: // si - //case 0x10: // dle - //case 0x11: // dc1 - //case 0x13: // dc3 -#ifdef BB_FEATURE_VI_CRASHME - case 0x14: // dc4 ctrl-T - crashme = (crashme == 0) ? 1 : 0; - break; -#endif /* BB_FEATURE_VI_CRASHME */ - //case 0x16: // syn - //case 0x17: // etb - //case 0x18: // can - //case 0x1c: // fs - //case 0x1d: // gs - //case 0x1e: // rs - //case 0x1f: // us - //case '!': // !- - //case '#': // #- - //case '&': // &- - //case '(': // (- - //case ')': // )- - //case '*': // *- - //case ',': // ,- - //case '=': // =- - //case '@': // @- - //case 'F': // F- - //case 'K': // K- - //case 'Q': // Q- - //case 'S': // S- - //case 'T': // T- - //case 'V': // V- - //case '[': // [- - //case '\\': // \- - //case ']': // ]- - //case '_': // _- - //case '`': // `- - //case 'g': // g- - //case 'u': // u- FIXME- there is no undo - //case 'v': // v- - default: // unrecognised command - buf[0] = c; - buf[1] = '\0'; - if (c <= ' ') { - buf[0] = '^'; - buf[1] = c + '@'; - buf[2] = '\0'; - } - ni((Byte *) buf); - end_cmd_q(); // stop adding to q - case 0x00: // nul- ignore - break; - case 2: // ctrl-B scroll up full screen - case VI_K_PAGEUP: // Cursor Key Page Up - dot_scroll(rows - 2, -1); - break; -#ifdef BB_FEATURE_VI_USE_SIGNALS - case 0x03: // ctrl-C interrupt - longjmp(restart, 1); - break; - case 26: // ctrl-Z suspend - suspend_sig(SIGTSTP); - break; -#endif /* BB_FEATURE_VI_USE_SIGNALS */ - case 4: // ctrl-D scroll down half screen - dot_scroll((rows - 2) / 2, 1); - break; - case 5: // ctrl-E scroll down one line - dot_scroll(1, 1); - break; - case 6: // ctrl-F scroll down full screen - case VI_K_PAGEDOWN: // Cursor Key Page Down - dot_scroll(rows - 2, 1); - break; - case 7: // ctrl-G show current status - edit_status(); - break; - case 'h': // h- move left - case VI_K_LEFT: // cursor key Left - case 8: // ctrl-H- move left (This may be ERASE char) - case 127: // DEL- move left (This may be ERASE char) - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dot_left(); - break; - case 10: // Newline ^J - case 'j': // j- goto next line, same col - case VI_K_DOWN: // cursor key Down - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dot_next(); // go to next B-o-l - dot = move_to_col(dot, ccol + offset); // try stay in same col - break; - case 12: // ctrl-L force redraw whole screen - case 18: // ctrl-R force redraw - place_cursor(0, 0, FALSE); // put cursor in correct place - clear_to_eos(); // tel terminal to erase display - (void) mysleep(10); - screen_erase(); // erase the internal screen buffer - refresh(TRUE); // this will redraw the entire display - break; - case 13: // Carriage Return ^M - case '+': // +- goto next line - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dot_next(); - dot_skip_over_ws(); - break; - case 21: // ctrl-U scroll up half screen - dot_scroll((rows - 2) / 2, -1); - break; - case 25: // ctrl-Y scroll up one line - dot_scroll(1, -1); - break; - case 27: // esc - if (cmd_mode == 0) - indicate_error(c); - cmd_mode = 0; // stop insrting - end_cmd_q(); - *status_buffer = '\0'; // clear status buffer - break; - case ' ': // move right - case 'l': // move right - case VI_K_RIGHT: // Cursor Key Right - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dot_right(); - break; -#ifdef BB_FEATURE_VI_YANKMARK - case '"': // "- name a register to use for Delete/Yank - c1 = get_one_char(); - c1 = tolower(c1); - if (islower(c1)) { - YDreg = c1 - 'a'; - } else { - indicate_error(c); - } - break; - case '\'': // '- goto a specific mark - c1 = get_one_char(); - c1 = tolower(c1); - if (islower(c1)) { - c1 = c1 - 'a'; - // get the b-o-l - q = mark[(int) c1]; - if (text <= q && q < end) { - dot = q; - dot_begin(); // go to B-o-l - dot_skip_over_ws(); - } - } else if (c1 == '\'') { // goto previous context - dot = swap_context(dot); // swap current and previous context - dot_begin(); // go to B-o-l - dot_skip_over_ws(); - } else { - indicate_error(c); - } - break; - case 'm': // m- Mark a line - // this is really stupid. If there are any inserts or deletes - // between text[0] and dot then this mark will not point to the - // correct location! It could be off by many lines! - // Well..., at least its quick and dirty. - c1 = get_one_char(); - c1 = tolower(c1); - if (islower(c1)) { - c1 = c1 - 'a'; - // remember the line - mark[(int) c1] = dot; - } else { - indicate_error(c); - } - break; - case 'P': // P- Put register before - case 'p': // p- put register after - p = reg[YDreg]; - if (p == 0) { - psbs("Nothing in register %c", what_reg()); - break; - } - // are we putting whole lines or strings - if (strchr((char *) p, '\n') != NULL) { - if (c == 'P') { - dot_begin(); // putting lines- Put above - } - if (c == 'p') { - // are we putting after very last line? - if (end_line(dot) == (end - 1)) { - dot = end; // force dot to end of text[] - } else { - dot_next(); // next line, then put before - } - } - } else { - if (c == 'p') - dot_right(); // move to right, can move to NL - } - dot = string_insert(dot, p); // insert the string - end_cmd_q(); // stop adding to q - break; - case 'U': // U- Undo; replace current line with original version - if (reg[Ureg] != 0) { - p = begin_line(dot); - q = end_line(dot); - p = text_hole_delete(p, q); // delete cur line - p = string_insert(p, reg[Ureg]); // insert orig line - dot = p; - dot_skip_over_ws(); - } - break; -#endif /* BB_FEATURE_VI_YANKMARK */ - case '$': // $- goto end of line - case VI_K_END: // Cursor Key End - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dot = end_line(dot + 1); - break; - case '%': // %- find matching char of pair () [] {} - for (q = dot; q < end && *q != '\n'; q++) { - if (strchr("()[]{}", *q) != NULL) { - // we found half of a pair - p = find_pair(q, *q); - if (p == NULL) { - indicate_error(c); - } else { - dot = p; - } - break; - } - } - if (*q == '\n') - indicate_error(c); - break; - case 'f': // f- forward to a user specified char - last_forward_char = get_one_char(); // get the search char - // - // dont seperate these two commands. 'f' depends on ';' - // - //**** fall thru to ... 'i' - case ';': // ;- look at rest of line for last forward char - if (cmdcnt-- > 1) { - do_cmd(';'); - } // repeat cnt - if (last_forward_char == 0) break; - q = dot + 1; - while (q < end - 1 && *q != '\n' && *q != last_forward_char) { - q++; - } - if (*q == last_forward_char) - dot = q; - break; - case '-': // -- goto prev line - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dot_prev(); - dot_skip_over_ws(); - break; -#ifdef BB_FEATURE_VI_DOT_CMD - case '.': // .- repeat the last modifying command - // Stuff the last_modifying_cmd back into stdin - // and let it be re-executed. - if (last_modifying_cmd != 0) { - ioq = ioq_start = (Byte *) strdup((char *) last_modifying_cmd); - } - break; -#endif /* BB_FEATURE_VI_DOT_CMD */ -#ifdef BB_FEATURE_VI_SEARCH - case '?': // /- search for a pattern - case '/': // /- search for a pattern - buf[0] = c; - buf[1] = '\0'; - q = get_input_line(buf); // get input line- use "status line" - if (strlen((char *) q) == 1) - goto dc3; // if no pat re-use old pat - if (strlen((char *) q) > 1) { // new pat- save it and find - // there is a new pat - if (last_search_pattern != 0) { - free(last_search_pattern); - } - last_search_pattern = (Byte *) strdup((char *) q); - goto dc3; // now find the pattern - } - // user changed mind and erased the "/"- do nothing - break; - case 'N': // N- backward search for last pattern - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dir = BACK; // assume BACKWARD search - p = dot - 1; - if (last_search_pattern[0] == '?') { - dir = FORWARD; - p = dot + 1; - } - goto dc4; // now search for pattern - break; - case 'n': // n- repeat search for last pattern - // search rest of text[] starting at next char - // if search fails return orignal "p" not the "p+1" address - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dc3: - if (last_search_pattern == 0) { - msg = (Byte *) "No previous regular expression"; - goto dc2; - } - if (last_search_pattern[0] == '/') { - dir = FORWARD; // assume FORWARD search - p = dot + 1; - } - if (last_search_pattern[0] == '?') { - dir = BACK; - p = dot - 1; - } - dc4: - q = char_search(p, last_search_pattern + 1, dir, FULL); - if (q != NULL) { - dot = q; // good search, update "dot" - msg = (Byte *) ""; - goto dc2; - } - // no pattern found between "dot" and "end"- continue at top - p = text; - if (dir == BACK) { - p = end - 1; - } - q = char_search(p, last_search_pattern + 1, dir, FULL); - if (q != NULL) { // found something - dot = q; // found new pattern- goto it - msg = (Byte *) "search hit BOTTOM, continuing at TOP"; - if (dir == BACK) { - msg = (Byte *) "search hit TOP, continuing at BOTTOM"; - } - } else { - msg = (Byte *) "Pattern not found"; - } - dc2: - psbs("%s", msg); - break; - case '{': // {- move backward paragraph - q = char_search(dot, (Byte *) "\n\n", BACK, FULL); - if (q != NULL) { // found blank line - dot = next_line(q); // move to next blank line - } - break; - case '}': // }- move forward paragraph - q = char_search(dot, (Byte *) "\n\n", FORWARD, FULL); - if (q != NULL) { // found blank line - dot = next_line(q); // move to next blank line - } - break; -#endif /* BB_FEATURE_VI_SEARCH */ - case '0': // 0- goto begining of line - case '1': // 1- - case '2': // 2- - case '3': // 3- - case '4': // 4- - case '5': // 5- - case '6': // 6- - case '7': // 7- - case '8': // 8- - case '9': // 9- - if (c == '0' && cmdcnt < 1) { - dot_begin(); // this was a standalone zero - } else { - cmdcnt = cmdcnt * 10 + (c - '0'); // this 0 is part of a number - } - break; - case ':': // :- the colon mode commands - p = get_input_line((Byte *) ":"); // get input line- use "status line" -#ifdef BB_FEATURE_VI_COLON - colon(p); // execute the command -#else /* BB_FEATURE_VI_COLON */ - if (*p == ':') - p++; // move past the ':' - cnt = strlen((char *) p); - if (cnt <= 0) - break; - if (strncasecmp((char *) p, "quit", cnt) == 0 || - strncasecmp((char *) p, "q!", cnt) == 0) { // delete lines - if (file_modified == TRUE && p[1] != '!') { - psbs("No write since last change (:quit! overrides)"); - } else { - editing = 0; - } - } else if (strncasecmp((char *) p, "write", cnt) == 0 || - strncasecmp((char *) p, "wq", cnt) == 0) { - cnt = file_write(cfn, text, end - 1); - file_modified = FALSE; - psb("\"%s\" %dL, %dC", cfn, count_lines(text, end - 1), cnt); - if (p[1] == 'q') { - editing = 0; - } - } else if (strncasecmp((char *) p, "file", cnt) == 0 ) { - edit_status(); // show current file status - } else if (sscanf((char *) p, "%d", &j) > 0) { - dot = find_line(j); // go to line # j - dot_skip_over_ws(); - } else { // unrecognised cmd - ni((Byte *) p); - } -#endif /* BB_FEATURE_VI_COLON */ - break; - case '<': // <- Left shift something - case '>': // >- Right shift something - cnt = count_lines(text, dot); // remember what line we are on - c1 = get_one_char(); // get the type of thing to delete - find_range(&p, &q, c1); - (void) yank_delete(p, q, 1, YANKONLY); // save copy before change - p = begin_line(p); - q = end_line(q); - i = count_lines(p, q); // # of lines we are shifting - for ( ; i > 0; i--, p = next_line(p)) { - if (c == '<') { - // shift left- remove tab or 8 spaces - if (*p == '\t') { - // shrink buffer 1 char - (void) text_hole_delete(p, p); - } else if (*p == ' ') { - // we should be calculating columns, not just SPACE - for (j = 0; *p == ' ' && j < tabstop; j++) { - (void) text_hole_delete(p, p); - } - } - } else if (c == '>') { - // shift right -- add tab or 8 spaces - (void) char_insert(p, '\t'); - } - } - dot = find_line(cnt); // what line were we on - dot_skip_over_ws(); - end_cmd_q(); // stop adding to q - break; - case 'A': // A- append at e-o-l - dot_end(); // go to e-o-l - //**** fall thru to ... 'a' - case 'a': // a- append after current char - if (*dot != '\n') - dot++; - goto dc_i; - break; - case 'B': // B- back a blank-delimited Word - case 'E': // E- end of a blank-delimited word - case 'W': // W- forward a blank-delimited word - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dir = FORWARD; - if (c == 'B') - dir = BACK; - if (c == 'W' || isspace(dot[dir])) { - dot = skip_thing(dot, 1, dir, S_TO_WS); - dot = skip_thing(dot, 2, dir, S_OVER_WS); - } - if (c != 'W') - dot = skip_thing(dot, 1, dir, S_BEFORE_WS); - break; - case 'C': // C- Change to e-o-l - case 'D': // D- delete to e-o-l - save_dot = dot; - dot = dollar_line(dot); // move to before NL - // copy text into a register and delete - dot = yank_delete(save_dot, dot, 0, YANKDEL); // delete to e-o-l - if (c == 'C') - goto dc_i; // start inserting -#ifdef BB_FEATURE_VI_DOT_CMD - if (c == 'D') - end_cmd_q(); // stop adding to q -#endif /* BB_FEATURE_VI_DOT_CMD */ - break; - case 'G': // G- goto to a line number (default= E-O-F) - dot = end - 1; // assume E-O-F - if (cmdcnt > 0) { - dot = find_line(cmdcnt); // what line is #cmdcnt - } - dot_skip_over_ws(); - break; - case 'H': // H- goto top line on screen - dot = screenbegin; - if (cmdcnt > (rows - 1)) { - cmdcnt = (rows - 1); - } - if (cmdcnt-- > 1) { - do_cmd('+'); - } // repeat cnt - dot_skip_over_ws(); - break; - case 'I': // I- insert before first non-blank - dot_begin(); // 0 - dot_skip_over_ws(); - //**** fall thru to ... 'i' - case 'i': // i- insert before current char - case VI_K_INSERT: // Cursor Key Insert - dc_i: - cmd_mode = 1; // start insrting - psb("-- Insert --"); - break; - case 'J': // J- join current and next lines together - if (cmdcnt-- > 2) { - do_cmd(c); - } // repeat cnt - dot_end(); // move to NL - if (dot < end - 1) { // make sure not last char in text[] - *dot++ = ' '; // replace NL with space - while (isblnk(*dot)) { // delete leading WS - dot_delete(); - } - } - end_cmd_q(); // stop adding to q - break; - case 'L': // L- goto bottom line on screen - dot = end_screen(); - if (cmdcnt > (rows - 1)) { - cmdcnt = (rows - 1); - } - if (cmdcnt-- > 1) { - do_cmd('-'); - } // repeat cnt - dot_begin(); - dot_skip_over_ws(); - break; - case 'M': // M- goto middle line on screen - dot = screenbegin; - for (cnt = 0; cnt < (rows-1) / 2; cnt++) - dot = next_line(dot); - break; - case 'O': // O- open a empty line above - // 0i\n ESC -i - p = begin_line(dot); - if (p[-1] == '\n') { - dot_prev(); - case 'o': // o- open a empty line below; Yes, I know it is in the middle of the "if (..." - dot_end(); - dot = char_insert(dot, '\n'); - } else { - dot_begin(); // 0 - dot = char_insert(dot, '\n'); // i\n ESC - dot_prev(); // - - } - goto dc_i; - break; - case 'R': // R- continuous Replace char - dc5: - cmd_mode = 2; - psb("-- Replace --"); - break; - case 'X': // X- delete char before dot - case 'x': // x- delete the current char - case 's': // s- substitute the current char - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dir = 0; - if (c == 'X') - dir = -1; - if (dot[dir] != '\n') { - if (c == 'X') - dot--; // delete prev char - dot = yank_delete(dot, dot, 0, YANKDEL); // delete char - } - if (c == 's') - goto dc_i; // start insrting - end_cmd_q(); // stop adding to q - break; - case 'Z': // Z- if modified, {write}; exit - // ZZ means to save file (if necessary), then exit - c1 = get_one_char(); - if (c1 != 'Z') { - indicate_error(c); - break; - } - if (file_modified == TRUE -#ifdef BB_FEATURE_VI_READONLY - && vi_readonly == FALSE - && readonly == FALSE -#endif /* BB_FEATURE_VI_READONLY */ - ) { - cnt = file_write(cfn, text, end - 1); - if (cnt == (end - 1 - text + 1)) { - editing = 0; - } - } else { - editing = 0; - } - break; - case '^': // ^- move to first non-blank on line - dot_begin(); - dot_skip_over_ws(); - break; - case 'b': // b- back a word - case 'e': // e- end of word - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dir = FORWARD; - if (c == 'b') - dir = BACK; - if ((dot + dir) < text || (dot + dir) > end - 1) - break; - dot += dir; - if (isspace(*dot)) { - dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS); - } - if (isalnum(*dot) || *dot == '_') { - dot = skip_thing(dot, 1, dir, S_END_ALNUM); - } else if (ispunct(*dot)) { - dot = skip_thing(dot, 1, dir, S_END_PUNCT); - } - break; - case 'c': // c- change something - case 'd': // d- delete something -#ifdef BB_FEATURE_VI_YANKMARK - case 'y': // y- yank something - case 'Y': // Y- Yank a line -#endif /* BB_FEATURE_VI_YANKMARK */ - yf = YANKDEL; // assume either "c" or "d" -#ifdef BB_FEATURE_VI_YANKMARK - if (c == 'y' || c == 'Y') - yf = YANKONLY; -#endif /* BB_FEATURE_VI_YANKMARK */ - c1 = 'y'; - if (c != 'Y') - c1 = get_one_char(); // get the type of thing to delete - find_range(&p, &q, c1); - if (c1 == 27) { // ESC- user changed mind and wants out - c = c1 = 27; // Escape- do nothing - } else if (strchr("wW", c1)) { - if (c == 'c') { - // don't include trailing WS as part of word - while (isblnk(*q)) { - if (q <= text || q[-1] == '\n') - break; - q--; - } - } - dot = yank_delete(p, q, 0, yf); // delete word - } else if (strchr("^0bBeEft$", c1)) { - // single line copy text into a register and delete - dot = yank_delete(p, q, 0, yf); // delete word - } else if (strchr("cdykjHL%+-{}\r\n", c1)) { - // multiple line copy text into a register and delete - dot = yank_delete(p, q, 1, yf); // delete lines - if (c == 'c') { - dot = char_insert(dot, '\n'); - // on the last line of file don't move to prev line - if (dot != (end-1)) { - dot_prev(); - } - } else if (c == 'd') { - dot_begin(); - dot_skip_over_ws(); - } - } else { - // could not recognize object - c = c1 = 27; // error- - indicate_error(c); - } - if (c1 != 27) { - // if CHANGING, not deleting, start inserting after the delete - if (c == 'c') { - strcpy((char *) buf, "Change"); - goto dc_i; // start inserting - } - if (c == 'd') { - strcpy((char *) buf, "Delete"); - } -#ifdef BB_FEATURE_VI_YANKMARK - if (c == 'y' || c == 'Y') { - strcpy((char *) buf, "Yank"); - } - p = reg[YDreg]; - q = p + strlen((char *) p); - for (cnt = 0; p <= q; p++) { - if (*p == '\n') - cnt++; - } - psb("%s %d lines (%d chars) using [%c]", - buf, cnt, strlen((char *) reg[YDreg]), what_reg()); -#endif /* BB_FEATURE_VI_YANKMARK */ - end_cmd_q(); // stop adding to q - } - break; - case 'k': // k- goto prev line, same col - case VI_K_UP: // cursor key Up - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dot_prev(); - dot = move_to_col(dot, ccol + offset); // try stay in same col - break; - case 'r': // r- replace the current char with user input - c1 = get_one_char(); // get the replacement char - if (*dot != '\n') { - *dot = c1; - file_modified = TRUE; // has the file been modified - } - end_cmd_q(); // stop adding to q - break; - case 't': // t- move to char prior to next x - last_forward_char = get_one_char(); - do_cmd(';'); - if (*dot == last_forward_char) - dot_left(); - last_forward_char= 0; - break; - case 'w': // w- forward a word - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - if (isalnum(*dot) || *dot == '_') { // we are on ALNUM - dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); - } else if (ispunct(*dot)) { // we are on PUNCT - dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT); - } - if (dot < end - 1) - dot++; // move over word - if (isspace(*dot)) { - dot = skip_thing(dot, 2, FORWARD, S_OVER_WS); - } - break; - case 'z': // z- - c1 = get_one_char(); // get the replacement char - cnt = 0; - if (c1 == '.') - cnt = (rows - 2) / 2; // put dot at center - if (c1 == '-') - cnt = rows - 2; // put dot at bottom - screenbegin = begin_line(dot); // start dot at top - dot_scroll(cnt, -1); - break; - case '|': // |- move to column "cmdcnt" - dot = move_to_col(dot, cmdcnt - 1); // try to move to column - break; - case '~': // ~- flip the case of letters a-z -> A-Z - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - if (islower(*dot)) { - *dot = toupper(*dot); - file_modified = TRUE; // has the file been modified - } else if (isupper(*dot)) { - *dot = tolower(*dot); - file_modified = TRUE; // has the file been modified - } - dot_right(); - end_cmd_q(); // stop adding to q - break; - //----- The Cursor and Function Keys ----------------------------- - case VI_K_HOME: // Cursor Key Home - dot_begin(); - break; - // The Fn keys could point to do_macro which could translate them - case VI_K_FUN1: // Function Key F1 - case VI_K_FUN2: // Function Key F2 - case VI_K_FUN3: // Function Key F3 - case VI_K_FUN4: // Function Key F4 - case VI_K_FUN5: // Function Key F5 - case VI_K_FUN6: // Function Key F6 - case VI_K_FUN7: // Function Key F7 - case VI_K_FUN8: // Function Key F8 - case VI_K_FUN9: // Function Key F9 - case VI_K_FUN10: // Function Key F10 - case VI_K_FUN11: // Function Key F11 - case VI_K_FUN12: // Function Key F12 - break; - } - - dc1: - // if text[] just became empty, add back an empty line - if (end == text) { - (void) char_insert(text, '\n'); // start empty buf with dummy line - dot = text; - } - // it is OK for dot to exactly equal to end, otherwise check dot validity - if (dot != end) { - dot = bound_dot(dot); // make sure "dot" is valid - } -#ifdef BB_FEATURE_VI_YANKMARK - check_context(c); // update the current context -#endif /* BB_FEATURE_VI_YANKMARK */ - - if (!isdigit(c)) - cmdcnt = 0; // cmd was not a number, reset cmdcnt - cnt = dot - begin_line(dot); - // Try to stay off of the Newline - if (*dot == '\n' && cnt > 0 && cmd_mode == 0) - dot--; -} - -//----- The Colon commands ------------------------------------- -#ifdef BB_FEATURE_VI_COLON -static Byte *get_one_address(Byte * p, int *addr) // get colon addr, if present -{ - int st; - Byte *q; - -#ifdef BB_FEATURE_VI_YANKMARK - Byte c; -#endif /* BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_SEARCH - Byte *pat, buf[BUFSIZ]; -#endif /* BB_FEATURE_VI_SEARCH */ - - *addr = -1; // assume no addr - if (*p == '.') { // the current line - p++; - q = begin_line(dot); - *addr = count_lines(text, q); -#ifdef BB_FEATURE_VI_YANKMARK - } else if (*p == '\'') { // is this a mark addr - p++; - c = tolower(*p); - p++; - if (c >= 'a' && c <= 'z') { - // we have a mark - c = c - 'a'; - q = mark[(int) c]; - if (q != NULL) { // is mark valid - *addr = count_lines(text, q); // count lines - } - } -#endif /* BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_SEARCH - } else if (*p == '/') { // a search pattern - q = buf; - for (p++; *p; p++) { - if (*p == '/') - break; - *q++ = *p; - *q = '\0'; - } - pat = (Byte *) strdup((char *) buf); // save copy of pattern - if (*p == '/') - p++; - q = char_search(dot, pat, FORWARD, FULL); - if (q != NULL) { - *addr = count_lines(text, q); - } - free(pat); -#endif /* BB_FEATURE_VI_SEARCH */ - } else if (*p == '$') { // the last line in file - p++; - q = begin_line(end - 1); - *addr = count_lines(text, q); - } else if (isdigit(*p)) { // specific line number - sscanf((char *) p, "%d%n", addr, &st); - p += st; - } else { // I don't reconise this - // unrecognised address- assume -1 - *addr = -1; - } - return (p); -} - -static Byte *get_address(Byte *p, int *b, int *e) // get two colon addrs, if present -{ - //----- get the address' i.e., 1,3 'a,'b ----- - // get FIRST addr, if present - while (isblnk(*p)) - p++; // skip over leading spaces - if (*p == '%') { // alias for 1,$ - p++; - *b = 1; - *e = count_lines(text, end-1); - goto ga0; - } - p = get_one_address(p, b); - while (isblnk(*p)) - p++; - if (*p == ',') { // is there a address seperator - p++; - while (isblnk(*p)) - p++; - // get SECOND addr, if present - p = get_one_address(p, e); - } -ga0: - while (isblnk(*p)) - p++; // skip over trailing spaces - return (p); -} - -static void colon(Byte * buf) -{ - Byte c, *orig_buf, *buf1, *q, *r; - Byte *fn, cmd[BUFSIZ], args[BUFSIZ]; - int i, l, li, ch, st, b, e; - int useforce, forced; - struct stat st_buf; - - // :3154 // if (-e line 3154) goto it else stay put - // :4,33w! foo // write a portion of buffer to file "foo" - // :w // write all of buffer to current file - // :q // quit - // :q! // quit- dont care about modified file - // :'a,'z!sort -u // filter block through sort - // :'f // goto mark "f" - // :'fl // list literal the mark "f" line - // :.r bar // read file "bar" into buffer before dot - // :/123/,/abc/d // delete lines from "123" line to "abc" line - // :/xyz/ // goto the "xyz" line - // :s/find/replace/ // substitute pattern "find" with "replace" - // :! // run then return - // - if (strlen((char *) buf) <= 0) - goto vc1; - if (*buf == ':') - buf++; // move past the ':' - - forced = useforce = FALSE; - li = st = ch = i = 0; - b = e = -1; - q = text; // assume 1,$ for the range - r = end - 1; - li = count_lines(text, end - 1); - fn = cfn; // default to current file - memset(cmd, '\0', BUFSIZ); // clear cmd[] - memset(args, '\0', BUFSIZ); // clear args[] - - // look for optional address(es) :. :1 :1,9 :'q,'a :% - buf = get_address(buf, &b, &e); - - // remember orig command line - orig_buf = buf; - - // get the COMMAND into cmd[] - buf1 = cmd; - while (*buf != '\0') { - if (isspace(*buf)) - break; - *buf1++ = *buf++; - } - // get any ARGuments - while (isblnk(*buf)) - buf++; - strcpy((char *) args, (char *) buf); - buf1 = last_char_is((char *)cmd, '!'); - if (buf1) { - useforce = TRUE; - *buf1 = '\0'; // get rid of ! - } - if (b >= 0) { - // if there is only one addr, then the addr - // is the line number of the single line the - // user wants. So, reset the end - // pointer to point at end of the "b" line - q = find_line(b); // what line is #b - r = end_line(q); - li = 1; - } - if (e >= 0) { - // we were given two addrs. change the - // end pointer to the addr given by user. - r = find_line(e); // what line is #e - r = end_line(r); - li = e - b + 1; - } - // ------------ now look for the command ------------ - i = strlen((char *) cmd); - if (i == 0) { // :123CR goto line #123 - if (b >= 0) { - dot = find_line(b); // what line is #b - dot_skip_over_ws(); - } - } else if (strncmp((char *) cmd, "!", 1) == 0) { // run a cmd - // :!ls run the - (void) alarm(0); // wait for input- no alarms - place_cursor(rows - 1, 0, FALSE); // go to Status line - clear_to_eol(); // clear the line - cookmode(); - system(orig_buf+1); // run the cmd - rawmode(); - Hit_Return(); // let user see results - (void) alarm(3); // done waiting for input - } else if (strncmp((char *) cmd, "=", i) == 0) { // where is the address - if (b < 0) { // no addr given- use defaults - b = e = count_lines(text, dot); - } - psb("%d", b); - } else if (strncasecmp((char *) cmd, "delete", i) == 0) { // delete lines - if (b < 0) { // no addr given- use defaults - q = begin_line(dot); // assume .,. for the range - r = end_line(dot); - } - dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines - dot_skip_over_ws(); - } else if (strncasecmp((char *) cmd, "edit", i) == 0) { // Edit a file - int sr; - sr= 0; - // don't edit, if the current file has been modified - if (file_modified == TRUE && useforce != TRUE) { - psbs("No write since last change (:edit! overrides)"); - goto vc1; - } - if (strlen(args) > 0) { - // the user supplied a file name - fn= args; - } else if (cfn != 0 && strlen(cfn) > 0) { - // no user supplied name- use the current filename - fn= cfn; - goto vc5; - } else { - // no user file name, no current name- punt - psbs("No current filename"); - goto vc1; - } - - // see if file exists- if not, its just a new file request - if ((sr=stat((char*)fn, &st_buf)) < 0) { - // This is just a request for a new file creation. - // The file_insert below will fail but we get - // an empty buffer with a file name. Then the "write" - // command can do the create. - } else { - if ((st_buf.st_mode & (S_IFREG)) == 0) { - // This is not a regular file - psbs("\"%s\" is not a regular file", fn); - goto vc1; - } - if ((st_buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) { - // dont have any read permissions - psbs("\"%s\" is not readable", fn); - goto vc1; - } - } - - // There is a read-able regular file - // make this the current file - q = (Byte *) strdup((char *) fn); // save the cfn - if (cfn != 0) - free(cfn); // free the old name - cfn = q; // remember new cfn - - vc5: - // delete all the contents of text[] - new_text(2 * file_size(fn)); - screenbegin = dot = end = text; - - // insert new file - ch = file_insert(fn, text, file_size(fn)); - - if (ch < 1) { - // start empty buf with dummy line - (void) char_insert(text, '\n'); - ch= 1; - } - file_modified = FALSE; -#ifdef BB_FEATURE_VI_YANKMARK - if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { - free(reg[Ureg]); // free orig line reg- for 'U' - reg[Ureg]= 0; - } - if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) { - free(reg[YDreg]); // free default yank/delete register - reg[YDreg]= 0; - } - for (li = 0; li < 28; li++) { - mark[li] = 0; - } // init the marks -#endif /* BB_FEATURE_VI_YANKMARK */ - // how many lines in text[]? - li = count_lines(text, end - 1); - psb("\"%s\"%s" -#ifdef BB_FEATURE_VI_READONLY - "%s" -#endif /* BB_FEATURE_VI_READONLY */ - " %dL, %dC", cfn, - (sr < 0 ? " [New file]" : ""), -#ifdef BB_FEATURE_VI_READONLY - ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""), -#endif /* BB_FEATURE_VI_READONLY */ - li, ch); - } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this - if (b != -1 || e != -1) { - ni((Byte *) "No address allowed on this command"); - goto vc1; - } - if (strlen((char *) args) > 0) { - // user wants a new filename - if (cfn != NULL) - free(cfn); - cfn = (Byte *) strdup((char *) args); - } else { - // user wants file status info - edit_status(); - } - } else if (strncasecmp((char *) cmd, "features", i) == 0) { // what features are available - // print out values of all features - place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen - clear_to_eol(); // clear the line - cookmode(); - show_help(); - rawmode(); - Hit_Return(); - } else if (strncasecmp((char *) cmd, "list", i) == 0) { // literal print line - if (b < 0) { // no addr given- use defaults - q = begin_line(dot); // assume .,. for the range - r = end_line(dot); - } - place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen - clear_to_eol(); // clear the line - write(1, "\r\n", 2); - for (; q <= r; q++) { - c = *q; - if (c > '~') - standout_start(); - if (c == '\n') { - write(1, "$\r", 2); - } else if (*q < ' ') { - write(1, "^", 1); - c += '@'; - } - write(1, &c, 1); - if (c > '~') - standout_end(); - } -#ifdef BB_FEATURE_VI_SET - vc2: -#endif /* BB_FEATURE_VI_SET */ - Hit_Return(); - } else if ((strncasecmp((char *) cmd, "quit", i) == 0) || // Quit - (strncasecmp((char *) cmd, "next", i) == 0)) { // edit next file - if (useforce == TRUE) { - // force end of argv list - if (*cmd == 'q') { - optind = save_argc; - } - editing = 0; - goto vc1; - } - // don't exit if the file been modified - if (file_modified == TRUE) { - psbs("No write since last change (:%s! overrides)", - (*cmd == 'q' ? "quit" : "next")); - goto vc1; - } - // are there other file to edit - if (*cmd == 'q' && optind < save_argc - 1) { - psbs("%d more file to edit", (save_argc - optind - 1)); - goto vc1; - } - if (*cmd == 'n' && optind >= save_argc - 1) { - psbs("No more files to edit"); - goto vc1; - } - editing = 0; - } else if (strncasecmp((char *) cmd, "read", i) == 0) { // read file into text[] - fn = args; - if (strlen((char *) fn) <= 0) { - psbs("No filename given"); - goto vc1; - } - if (b < 0) { // no addr given- use defaults - q = begin_line(dot); // assume "dot" - } - // read after current line- unless user said ":0r foo" - if (b != 0) - q = next_line(q); -#ifdef BB_FEATURE_VI_READONLY - l= readonly; // remember current files' status -#endif - ch = file_insert(fn, q, file_size(fn)); -#ifdef BB_FEATURE_VI_READONLY - readonly= l; -#endif - if (ch < 0) - goto vc1; // nothing was inserted - // how many lines in text[]? - li = count_lines(q, q + ch - 1); - psb("\"%s\"" -#ifdef BB_FEATURE_VI_READONLY - "%s" -#endif /* BB_FEATURE_VI_READONLY */ - " %dL, %dC", fn, -#ifdef BB_FEATURE_VI_READONLY - ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""), -#endif /* BB_FEATURE_VI_READONLY */ - li, ch); - if (ch > 0) { - // if the insert is before "dot" then we need to update - if (q <= dot) - dot += ch; - file_modified = TRUE; - } - } else if (strncasecmp((char *) cmd, "rewind", i) == 0) { // rewind cmd line args - if (file_modified == TRUE && useforce != TRUE) { - psbs("No write since last change (:rewind! overrides)"); - } else { - // reset the filenames to edit - optind = fn_start - 1; - editing = 0; - } -#ifdef BB_FEATURE_VI_SET - } else if (strncasecmp((char *) cmd, "set", i) == 0) { // set or clear features - i = 0; // offset into args - if (strlen((char *) args) == 0) { - // print out values of all options - place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen - clear_to_eol(); // clear the line - printf("----------------------------------------\r\n"); -#ifdef BB_FEATURE_VI_SETOPTS - if (!autoindent) - printf("no"); - printf("autoindent "); - if (!err_method) - printf("no"); - printf("flash "); - if (!ignorecase) - printf("no"); - printf("ignorecase "); - if (!showmatch) - printf("no"); - printf("showmatch "); - printf("tabstop=%d ", tabstop); -#endif /* BB_FEATURE_VI_SETOPTS */ - printf("\r\n"); - goto vc2; - } - if (strncasecmp((char *) args, "no", 2) == 0) - i = 2; // ":set noautoindent" -#ifdef BB_FEATURE_VI_SETOPTS - if (strncasecmp((char *) args + i, "autoindent", 10) == 0 || - strncasecmp((char *) args + i, "ai", 2) == 0) { - autoindent = (i == 2) ? 0 : 1; - } - if (strncasecmp((char *) args + i, "flash", 5) == 0 || - strncasecmp((char *) args + i, "fl", 2) == 0) { - err_method = (i == 2) ? 0 : 1; - } - if (strncasecmp((char *) args + i, "ignorecase", 10) == 0 || - strncasecmp((char *) args + i, "ic", 2) == 0) { - ignorecase = (i == 2) ? 0 : 1; - } - if (strncasecmp((char *) args + i, "showmatch", 9) == 0 || - strncasecmp((char *) args + i, "sm", 2) == 0) { - showmatch = (i == 2) ? 0 : 1; - } - if (strncasecmp((char *) args + i, "tabstop", 7) == 0) { - sscanf(strchr((char *) args + i, '='), "=%d", &ch); - if (ch > 0 && ch < columns - 1) - tabstop = ch; - } -#endif /* BB_FEATURE_VI_SETOPTS */ -#endif /* BB_FEATURE_VI_SET */ -#ifdef BB_FEATURE_VI_SEARCH - } else if (strncasecmp((char *) cmd, "s", 1) == 0) { // substitute a pattern with a replacement pattern - Byte *ls, *F, *R; - int gflag; - - // F points to the "find" pattern - // R points to the "replace" pattern - // replace the cmd line delimiters "/" with NULLs - gflag = 0; // global replace flag - c = orig_buf[1]; // what is the delimiter - F = orig_buf + 2; // start of "find" - R = (Byte *) strchr((char *) F, c); // middle delimiter - if (!R) goto colon_s_fail; - *R++ = '\0'; // terminate "find" - buf1 = (Byte *) strchr((char *) R, c); - if (!buf1) goto colon_s_fail; - *buf1++ = '\0'; // terminate "replace" - if (*buf1 == 'g') { // :s/foo/bar/g - buf1++; - gflag++; // turn on gflag - } - q = begin_line(q); - if (b < 0) { // maybe :s/foo/bar/ - q = begin_line(dot); // start with cur line - b = count_lines(text, q); // cur line number - } - if (e < 0) - e = b; // maybe :.s/foo/bar/ - for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 - ls = q; // orig line start - vc4: - buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" - if (buf1 != NULL) { - // we found the "find" pattern- delete it - (void) text_hole_delete(buf1, buf1 + strlen((char *) F) - 1); - // inset the "replace" patern - (void) string_insert(buf1, R); // insert the string - // check for "global" :s/foo/bar/g - if (gflag == 1) { - if ((buf1 + strlen((char *) R)) < end_line(ls)) { - q = buf1 + strlen((char *) R); - goto vc4; // don't let q move past cur line - } - } - } - q = next_line(ls); - } -#endif /* BB_FEATURE_VI_SEARCH */ - } else if (strncasecmp((char *) cmd, "version", i) == 0) { // show software version - psb("%s", vi_Version); - } else if ((strncasecmp((char *) cmd, "write", i) == 0) || // write text to file - (strncasecmp((char *) cmd, "wq", i) == 0)) { // write text to file - // is there a file name to write to? - if (strlen((char *) args) > 0) { - fn = args; - } -#ifdef BB_FEATURE_VI_READONLY - if ((vi_readonly == TRUE || readonly == TRUE) && useforce == FALSE) { - psbs("\"%s\" File is read only", fn); - goto vc3; - } -#endif /* BB_FEATURE_VI_READONLY */ - // how many lines in text[]? - li = count_lines(q, r); - ch = r - q + 1; - // see if file exists- if not, its just a new file request - if (useforce == TRUE) { - // if "fn" is not write-able, chmod u+w - // sprintf(syscmd, "chmod u+w %s", fn); - // system(syscmd); - forced = TRUE; - } - l = file_write(fn, q, r); - if (useforce == TRUE && forced == TRUE) { - // chmod u-w - // sprintf(syscmd, "chmod u-w %s", fn); - // system(syscmd); - forced = FALSE; - } - psb("\"%s\" %dL, %dC", fn, li, l); - if (q == text && r == end - 1 && l == ch) - file_modified = FALSE; - if (cmd[1] == 'q' && l == ch) { - editing = 0; - } -#ifdef BB_FEATURE_VI_READONLY - vc3:; -#endif /* BB_FEATURE_VI_READONLY */ -#ifdef BB_FEATURE_VI_YANKMARK - } else if (strncasecmp((char *) cmd, "yank", i) == 0) { // yank lines - if (b < 0) { // no addr given- use defaults - q = begin_line(dot); // assume .,. for the range - r = end_line(dot); - } - text_yank(q, r, YDreg); - li = count_lines(q, r); - psb("Yank %d lines (%d chars) into [%c]", - li, strlen((char *) reg[YDreg]), what_reg()); -#endif /* BB_FEATURE_VI_YANKMARK */ - } else { - // cmd unknown - ni((Byte *) cmd); - } - vc1: - dot = bound_dot(dot); // make sure "dot" is valid - return; -#ifdef BB_FEATURE_VI_SEARCH -colon_s_fail: - psb(":s expression missing delimiters"); - return; -#endif - -} - -static void Hit_Return(void) -{ - char c; - - standout_start(); // start reverse video - write(1, "[Hit return to continue]", 24); - standout_end(); // end reverse video - while ((c = get_one_char()) != '\n' && c != '\r') /*do nothing */ - ; - redraw(TRUE); // force redraw all -} -#endif /* BB_FEATURE_VI_COLON */ - -//----- Synchronize the cursor to Dot -------------------------- -static void sync_cursor(Byte * d, int *row, int *col) -{ - Byte *beg_cur, *end_cur; // begin and end of "d" line - Byte *beg_scr, *end_scr; // begin and end of screen - Byte *tp; - int cnt, ro, co; - - beg_cur = begin_line(d); // first char of cur line - end_cur = end_line(d); // last char of cur line - - beg_scr = end_scr = screenbegin; // first char of screen - end_scr = end_screen(); // last char of screen - - if (beg_cur < screenbegin) { - // "d" is before top line on screen - // how many lines do we have to move - cnt = count_lines(beg_cur, screenbegin); - sc1: - screenbegin = beg_cur; - if (cnt > (rows - 1) / 2) { - // we moved too many lines. put "dot" in middle of screen - for (cnt = 0; cnt < (rows - 1) / 2; cnt++) { - screenbegin = prev_line(screenbegin); - } - } - } else if (beg_cur > end_scr) { - // "d" is after bottom line on screen - // how many lines do we have to move - cnt = count_lines(end_scr, beg_cur); - if (cnt > (rows - 1) / 2) - goto sc1; // too many lines - for (ro = 0; ro < cnt - 1; ro++) { - // move screen begin the same amount - screenbegin = next_line(screenbegin); - // now, move the end of screen - end_scr = next_line(end_scr); - end_scr = end_line(end_scr); - } - } - // "d" is on screen- find out which row - tp = screenbegin; - for (ro = 0; ro < rows - 1; ro++) { // drive "ro" to correct row - if (tp == beg_cur) - break; - tp = next_line(tp); - } - - // find out what col "d" is on - co = 0; - do { // drive "co" to correct column - if (*tp == '\n' || *tp == '\0') - break; - if (*tp == '\t') { - // 7 - (co % 8 ) - co += ((tabstop - 1) - (co % tabstop)); - } else if (*tp < ' ') { - co++; // display as ^X, use 2 columns - } - } while (tp++ < d && ++co); - - // "co" is the column where "dot" is. - // The screen has "columns" columns. - // The currently displayed columns are 0+offset -- columns+ofset - // |-------------------------------------------------------------| - // ^ ^ ^ - // offset | |------- columns ----------------| - // - // If "co" is already in this range then we do not have to adjust offset - // but, we do have to subtract the "offset" bias from "co". - // If "co" is outside this range then we have to change "offset". - // If the first char of a line is a tab the cursor will try to stay - // in column 7, but we have to set offset to 0. - - if (co < 0 + offset) { - offset = co; - } - if (co >= columns + offset) { - offset = co - columns + 1; - } - // if the first char of the line is a tab, and "dot" is sitting on it - // force offset to 0. - if (d == beg_cur && *d == '\t') { - offset = 0; - } - co -= offset; - - *row = ro; - *col = co; -} - -//----- Text Movement Routines --------------------------------- -static Byte *begin_line(Byte * p) // return pointer to first char cur line -{ - while (p > text && p[-1] != '\n') - p--; // go to cur line B-o-l - return (p); -} - -static Byte *end_line(Byte * p) // return pointer to NL of cur line line -{ - while (p < end - 1 && *p != '\n') - p++; // go to cur line E-o-l - return (p); -} - -static Byte *dollar_line(Byte * p) // return pointer to just before NL line -{ - while (p < end - 1 && *p != '\n') - p++; // go to cur line E-o-l - // Try to stay off of the Newline - if (*p == '\n' && (p - begin_line(p)) > 0) - p--; - return (p); -} - -static Byte *prev_line(Byte * p) // return pointer first char prev line -{ - p = begin_line(p); // goto begining of cur line - if (p[-1] == '\n' && p > text) - p--; // step to prev line - p = begin_line(p); // goto begining of prev line - return (p); -} - -static Byte *next_line(Byte * p) // return pointer first char next line -{ - p = end_line(p); - if (*p == '\n' && p < end - 1) - p++; // step to next line - return (p); -} - -//----- Text Information Routines ------------------------------ -static Byte *end_screen(void) -{ - Byte *q; - int cnt; - - // find new bottom line - q = screenbegin; - for (cnt = 0; cnt < rows - 2; cnt++) - q = next_line(q); - q = end_line(q); - return (q); -} - -static int count_lines(Byte * start, Byte * stop) // count line from start to stop -{ - Byte *q; - int cnt; - - if (stop < start) { // start and stop are backwards- reverse them - q = start; - start = stop; - stop = q; - } - cnt = 0; - stop = end_line(stop); // get to end of this line - for (q = start; q <= stop && q <= end - 1; q++) { - if (*q == '\n') - cnt++; - } - return (cnt); -} - -static Byte *find_line(int li) // find begining of line #li -{ - Byte *q; - - for (q = text; li > 1; li--) { - q = next_line(q); - } - return (q); -} - -//----- Dot Movement Routines ---------------------------------- -static void dot_left(void) -{ - if (dot > text && dot[-1] != '\n') - dot--; -} - -static void dot_right(void) -{ - if (dot < end - 1 && *dot != '\n') - dot++; -} - -static void dot_begin(void) -{ - dot = begin_line(dot); // return pointer to first char cur line -} - -static void dot_end(void) -{ - dot = end_line(dot); // return pointer to last char cur line -} - -static Byte *move_to_col(Byte * p, int l) -{ - int co; - - p = begin_line(p); - co = 0; - do { - if (*p == '\n' || *p == '\0') - break; - if (*p == '\t') { - // 7 - (co % 8 ) - co += ((tabstop - 1) - (co % tabstop)); - } else if (*p < ' ') { - co++; // display as ^X, use 2 columns - } - } while (++co <= l && p++ < end); - return (p); -} - -static void dot_next(void) -{ - dot = next_line(dot); -} - -static void dot_prev(void) -{ - dot = prev_line(dot); -} - -static void dot_scroll(int cnt, int dir) -{ - Byte *q; - - for (; cnt > 0; cnt--) { - if (dir < 0) { - // scroll Backwards - // ctrl-Y scroll up one line - screenbegin = prev_line(screenbegin); - } else { - // scroll Forwards - // ctrl-E scroll down one line - screenbegin = next_line(screenbegin); - } - } - // make sure "dot" stays on the screen so we dont scroll off - if (dot < screenbegin) - dot = screenbegin; - q = end_screen(); // find new bottom line - if (dot > q) - dot = begin_line(q); // is dot is below bottom line? - dot_skip_over_ws(); -} - -static void dot_skip_over_ws(void) -{ - // skip WS - while (isspace(*dot) && *dot != '\n' && dot < end - 1) - dot++; -} - -static void dot_delete(void) // delete the char at 'dot' -{ - (void) text_hole_delete(dot, dot); -} - -static Byte *bound_dot(Byte * p) // make sure text[0] <= P < "end" -{ - if (p >= end && end > text) { - p = end - 1; - indicate_error('1'); - } - if (p < text) { - p = text; - indicate_error('2'); - } - return (p); -} - -//----- Helper Utility Routines -------------------------------- - -//---------------------------------------------------------------- -//----- Char Routines -------------------------------------------- -/* Chars that are part of a word- - * 0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz - * Chars that are Not part of a word (stoppers) - * !"#$%&'()*+,-./:;<=>?@[\]^`{|}~ - * Chars that are WhiteSpace - * TAB NEWLINE VT FF RETURN SPACE - * DO NOT COUNT NEWLINE AS WHITESPACE - */ - -static Byte *new_screen(int ro, int co) -{ - int li; - - if (screen != 0) - free(screen); - screensize = ro * co + 8; - screen = (Byte *) malloc(screensize); - // initialize the new screen. assume this will be a empty file. - screen_erase(); - // non-existant text[] lines start with a tilde (~). - for (li = 1; li < ro - 1; li++) { - screen[(li * co) + 0] = '~'; - } - return (screen); -} - -static Byte *new_text(int size) -{ - if (size < 10240) - size = 10240; // have a minimum size for new files - if (text != 0) { - //text -= 4; - free(text); - } - text = (Byte *) malloc(size + 8); - memset(text, '\0', size); // clear new text[] - //text += 4; // leave some room for "oops" - textend = text + size - 1; - //textend -= 4; // leave some root for "oops" - return (text); -} - -#ifdef BB_FEATURE_VI_SEARCH -static int mycmp(Byte * s1, Byte * s2, int len) -{ - int i; - - i = strncmp((char *) s1, (char *) s2, len); -#ifdef BB_FEATURE_VI_SETOPTS - if (ignorecase) { - i = strncasecmp((char *) s1, (char *) s2, len); - } -#endif /* BB_FEATURE_VI_SETOPTS */ - return (i); -} - -static Byte *char_search(Byte * p, Byte * pat, int dir, int range) // search for pattern starting at p -{ -#ifndef REGEX_SEARCH - Byte *start, *stop; - int len; - - len = strlen((char *) pat); - if (dir == FORWARD) { - stop = end - 1; // assume range is p - end-1 - if (range == LIMITED) - stop = next_line(p); // range is to next line - for (start = p; start < stop; start++) { - if (mycmp(start, pat, len) == 0) { - return (start); - } - } - } else if (dir == BACK) { - stop = text; // assume range is text - p - if (range == LIMITED) - stop = prev_line(p); // range is to prev line - for (start = p - len; start >= stop; start--) { - if (mycmp(start, pat, len) == 0) { - return (start); - } - } - } - // pattern not found - return (NULL); -#else /*REGEX_SEARCH */ - char *q; - struct re_pattern_buffer preg; - int i; - int size, range; - - re_syntax_options = RE_SYNTAX_POSIX_EXTENDED; - preg.translate = 0; - preg.fastmap = 0; - preg.buffer = 0; - preg.allocated = 0; - - // assume a LIMITED forward search - q = next_line(p); - q = end_line(q); - q = end - 1; - if (dir == BACK) { - q = prev_line(p); - q = text; - } - // count the number of chars to search over, forward or backward - size = q - p; - if (size < 0) - size = p - q; - // RANGE could be negative if we are searching backwards - range = q - p; - - q = (char *) re_compile_pattern(pat, strlen((char *) pat), &preg); - if (q != 0) { - // The pattern was not compiled - psbs("bad search pattern: \"%s\": %s", pat, q); - i = 0; // return p if pattern not compiled - goto cs1; - } - - q = p; - if (range < 0) { - q = p - size; - if (q < text) - q = text; - } - // search for the compiled pattern, preg, in p[] - // range < 0- search backward - // range > 0- search forward - // 0 < start < size - // re_search() < 0 not found or error - // re_search() > 0 index of found pattern - // struct pattern char int int int struct reg - // re_search (*pattern_buffer, *string, size, start, range, *regs) - i = re_search(&preg, q, size, 0, range, 0); - if (i == -1) { - p = 0; - i = 0; // return NULL if pattern not found - } - cs1: - if (dir == FORWARD) { - p = p + i; - } else { - p = p - i; - } - return (p); -#endif /*REGEX_SEARCH */ -} -#endif /* BB_FEATURE_VI_SEARCH */ - -static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p' -{ - if (c == 22) { // Is this an ctrl-V? - p = stupid_insert(p, '^'); // use ^ to indicate literal next - p--; // backup onto ^ - refresh(FALSE); // show the ^ - c = get_one_char(); - *p = c; - p++; - file_modified = TRUE; // has the file been modified - } else if (c == 27) { // Is this an ESC? - cmd_mode = 0; - cmdcnt = 0; - end_cmd_q(); // stop adding to q - strcpy((char *) status_buffer, " "); // clear the status buffer - if ((p[-1] != '\n') && (dot>text)) { - p--; - } - } else if (c == erase_char) { // Is this a BS - // 123456789 - if ((p[-1] != '\n') && (dot>text)) { - p--; - p = text_hole_delete(p, p); // shrink buffer 1 char -#ifdef BB_FEATURE_VI_DOT_CMD - // also rmove char from last_modifying_cmd - if (strlen((char *) last_modifying_cmd) > 0) { - Byte *q; - - q = last_modifying_cmd; - q[strlen((char *) q) - 1] = '\0'; // erase BS - q[strlen((char *) q) - 1] = '\0'; // erase prev char - } -#endif /* BB_FEATURE_VI_DOT_CMD */ - } - } else { - // insert a char into text[] - Byte *sp; // "save p" - - if (c == 13) - c = '\n'; // translate \r to \n - sp = p; // remember addr of insert - p = stupid_insert(p, c); // insert the char -#ifdef BB_FEATURE_VI_SETOPTS - if (showmatch && strchr(")]}", *sp) != NULL) { - showmatching(sp); - } - if (autoindent && c == '\n') { // auto indent the new line - Byte *q; - - q = prev_line(p); // use prev line as templet - for (; isblnk(*q); q++) { - p = stupid_insert(p, *q); // insert the char - } - } -#endif /* BB_FEATURE_VI_SETOPTS */ - } - return (p); -} - -static Byte *stupid_insert(Byte * p, Byte c) // stupidly insert the char c at 'p' -{ - p = text_hole_make(p, 1); - if (p != 0) { - *p = c; - file_modified = TRUE; // has the file been modified - p++; - } - return (p); -} - -static Byte find_range(Byte ** start, Byte ** stop, Byte c) -{ - Byte *save_dot, *p, *q; - int cnt; - - save_dot = dot; - p = q = dot; - - if (strchr("cdy><", c)) { - // these cmds operate on whole lines - p = q = begin_line(p); - for (cnt = 1; cnt < cmdcnt; cnt++) { - q = next_line(q); - } - q = end_line(q); - } else if (strchr("^%$0bBeEft", c)) { - // These cmds operate on char positions - do_cmd(c); // execute movement cmd - q = dot; - } else if (strchr("wW", c)) { - do_cmd(c); // execute movement cmd - if (dot > text) - dot--; // move back off of next word - if (dot > text && *dot == '\n') - dot--; // stay off NL - q = dot; - } else if (strchr("H-k{", c)) { - // these operate on multi-lines backwards - q = end_line(dot); // find NL - do_cmd(c); // execute movement cmd - dot_begin(); - p = dot; - } else if (strchr("L+j}\r\n", c)) { - // these operate on multi-lines forwards - p = begin_line(dot); - do_cmd(c); // execute movement cmd - dot_end(); // find NL - q = dot; - } else { - c = 27; // error- return an ESC char - //break; - } - *start = p; - *stop = q; - if (q < p) { - *start = q; - *stop = p; - } - dot = save_dot; - return (c); -} - -static int st_test(Byte * p, int type, int dir, Byte * tested) -{ - Byte c, c0, ci; - int test, inc; - - inc = dir; - c = c0 = p[0]; - ci = p[inc]; - test = 0; - - if (type == S_BEFORE_WS) { - c = ci; - test = ((!isspace(c)) || c == '\n'); - } - if (type == S_TO_WS) { - c = c0; - test = ((!isspace(c)) || c == '\n'); - } - if (type == S_OVER_WS) { - c = c0; - test = ((isspace(c))); - } - if (type == S_END_PUNCT) { - c = ci; - test = ((ispunct(c))); - } - if (type == S_END_ALNUM) { - c = ci; - test = ((isalnum(c)) || c == '_'); - } - *tested = c; - return (test); -} - -static Byte *skip_thing(Byte * p, int linecnt, int dir, int type) -{ - Byte c; - - while (st_test(p, type, dir, &c)) { - // make sure we limit search to correct number of lines - if (c == '\n' && --linecnt < 1) - break; - if (dir >= 0 && p >= end - 1) - break; - if (dir < 0 && p <= text) - break; - p += dir; // move to next char - } - return (p); -} - -// find matching char of pair () [] {} -static Byte *find_pair(Byte * p, Byte c) -{ - Byte match, *q; - int dir, level; - - match = ')'; - level = 1; - dir = 1; // assume forward - switch (c) { - case '(': - match = ')'; - break; - case '[': - match = ']'; - break; - case '{': - match = '}'; - break; - case ')': - match = '('; - dir = -1; - break; - case ']': - match = '['; - dir = -1; - break; - case '}': - match = '{'; - dir = -1; - break; - } - for (q = p + dir; text <= q && q < end; q += dir) { - // look for match, count levels of pairs (( )) - if (*q == c) - level++; // increase pair levels - if (*q == match) - level--; // reduce pair level - if (level == 0) - break; // found matching pair - } - if (level != 0) - q = NULL; // indicate no match - return (q); -} - -#ifdef BB_FEATURE_VI_SETOPTS -// show the matching char of a pair, () [] {} -static void showmatching(Byte * p) -{ - Byte *q, *save_dot; - - // we found half of a pair - q = find_pair(p, *p); // get loc of matching char - if (q == NULL) { - indicate_error('3'); // no matching char - } else { - // "q" now points to matching pair - save_dot = dot; // remember where we are - dot = q; // go to new loc - refresh(FALSE); // let the user see it - (void) mysleep(40); // give user some time - dot = save_dot; // go back to old loc - refresh(FALSE); - } -} -#endif /* BB_FEATURE_VI_SETOPTS */ - -// open a hole in text[] -static Byte *text_hole_make(Byte * p, int size) // at "p", make a 'size' byte hole -{ - Byte *src, *dest; - int cnt; - - if (size <= 0) - goto thm0; - src = p; - dest = p + size; - cnt = end - src; // the rest of buffer - if (memmove(dest, src, cnt) != dest) { - psbs("can't create room for new characters"); - } - memset(p, ' ', size); // clear new hole - end = end + size; // adjust the new END - file_modified = TRUE; // has the file been modified - thm0: - return (p); -} - -// close a hole in text[] -static Byte *text_hole_delete(Byte * p, Byte * q) // delete "p" thru "q", inclusive -{ - Byte *src, *dest; - int cnt, hole_size; - - // move forwards, from beginning - // assume p <= q - src = q + 1; - dest = p; - if (q < p) { // they are backward- swap them - src = p + 1; - dest = q; - } - hole_size = q - p + 1; - cnt = end - src; - if (src < text || src > end) - goto thd0; - if (dest < text || dest >= end) - goto thd0; - if (src >= end) - goto thd_atend; // just delete the end of the buffer - if (memmove(dest, src, cnt) != dest) { - psbs("can't delete the character"); - } - thd_atend: - end = end - hole_size; // adjust the new END - if (dest >= end) - dest = end - 1; // make sure dest in below end-1 - if (end <= text) - dest = end = text; // keep pointers valid - file_modified = TRUE; // has the file been modified - thd0: - return (dest); -} - -// copy text into register, then delete text. -// if dist <= 0, do not include, or go past, a NewLine -// -static Byte *yank_delete(Byte * start, Byte * stop, int dist, int yf) -{ - Byte *p; - - // make sure start <= stop - if (start > stop) { - // they are backwards, reverse them - p = start; - start = stop; - stop = p; - } - if (dist <= 0) { - // we can not cross NL boundaries - p = start; - if (*p == '\n') - return (p); - // dont go past a NewLine - for (; p + 1 <= stop; p++) { - if (p[1] == '\n') { - stop = p; // "stop" just before NewLine - break; - } - } - } - p = start; -#ifdef BB_FEATURE_VI_YANKMARK - text_yank(start, stop, YDreg); -#endif /* BB_FEATURE_VI_YANKMARK */ - if (yf == YANKDEL) { - p = text_hole_delete(start, stop); - } // delete lines - return (p); -} - -static void show_help(void) -{ - puts("These features are available:" -#ifdef BB_FEATURE_VI_SEARCH - "\n\tPattern searches with / and ?" -#endif /* BB_FEATURE_VI_SEARCH */ -#ifdef BB_FEATURE_VI_DOT_CMD - "\n\tLast command repeat with \'.\'" -#endif /* BB_FEATURE_VI_DOT_CMD */ -#ifdef BB_FEATURE_VI_YANKMARK - "\n\tLine marking with 'x" - "\n\tNamed buffers with \"x" -#endif /* BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_READONLY - "\n\tReadonly if vi is called as \"view\"" - "\n\tReadonly with -R command line arg" -#endif /* BB_FEATURE_VI_READONLY */ -#ifdef BB_FEATURE_VI_SET - "\n\tSome colon mode commands with \':\'" -#endif /* BB_FEATURE_VI_SET */ -#ifdef BB_FEATURE_VI_SETOPTS - "\n\tSettable options with \":set\"" -#endif /* BB_FEATURE_VI_SETOPTS */ -#ifdef BB_FEATURE_VI_USE_SIGNALS - "\n\tSignal catching- ^C" - "\n\tJob suspend and resume with ^Z" -#endif /* BB_FEATURE_VI_USE_SIGNALS */ -#ifdef BB_FEATURE_VI_WIN_RESIZE - "\n\tAdapt to window re-sizes" -#endif /* BB_FEATURE_VI_WIN_RESIZE */ - ); -} - -static void print_literal(Byte * buf, Byte * s) // copy s to buf, convert unprintable -{ - Byte c, b[2]; - - b[1] = '\0'; - strcpy((char *) buf, ""); // init buf - if (strlen((char *) s) <= 0) - s = (Byte *) "(NULL)"; - for (; *s > '\0'; s++) { - c = *s; - if (*s > '~') { - strcat((char *) buf, SOs); - c = *s - 128; - } - if (*s < ' ') { - strcat((char *) buf, "^"); - c += '@'; - } - b[0] = c; - strcat((char *) buf, (char *) b); - if (*s > '~') - strcat((char *) buf, SOn); - if (*s == '\n') { - strcat((char *) buf, "$"); - } - } -} - -#ifdef BB_FEATURE_VI_DOT_CMD -static void start_new_cmd_q(Byte c) -{ - // release old cmd - if (last_modifying_cmd != 0) - free(last_modifying_cmd); - // get buffer for new cmd - last_modifying_cmd = (Byte *) malloc(BUFSIZ); - memset(last_modifying_cmd, '\0', BUFSIZ); // clear new cmd queue - // if there is a current cmd count put it in the buffer first - if (cmdcnt > 0) - sprintf((char *) last_modifying_cmd, "%d", cmdcnt); - // save char c onto queue - last_modifying_cmd[strlen((char *) last_modifying_cmd)] = c; - adding2q = 1; - return; -} - -static void end_cmd_q() -{ -#ifdef BB_FEATURE_VI_YANKMARK - YDreg = 26; // go back to default Yank/Delete reg -#endif /* BB_FEATURE_VI_YANKMARK */ - adding2q = 0; - return; -} -#endif /* BB_FEATURE_VI_DOT_CMD */ - -#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME) -static Byte *string_insert(Byte * p, Byte * s) // insert the string at 'p' -{ - int cnt, i; - - i = strlen((char *) s); - p = text_hole_make(p, i); - strncpy((char *) p, (char *) s, i); - for (cnt = 0; *s != '\0'; s++) { - if (*s == '\n') - cnt++; - } -#ifdef BB_FEATURE_VI_YANKMARK - psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); -#endif /* BB_FEATURE_VI_YANKMARK */ - return (p); -} -#endif /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */ - -#ifdef BB_FEATURE_VI_YANKMARK -static Byte *text_yank(Byte * p, Byte * q, int dest) // copy text into a register -{ - Byte *t; - int cnt; - - if (q < p) { // they are backwards- reverse them - t = q; - q = p; - p = t; - } - cnt = q - p + 1; - t = reg[dest]; - if (t != 0) { // if already a yank register - free(t); // free it - } - t = (Byte *) malloc(cnt + 1); // get a new register - memset(t, '\0', cnt + 1); // clear new text[] - strncpy((char *) t, (char *) p, cnt); // copy text[] into bufer - reg[dest] = t; - return (p); -} - -static Byte what_reg(void) -{ - Byte c; - int i; - - i = 0; - c = 'D'; // default to D-reg - if (0 <= YDreg && YDreg <= 25) - c = 'a' + (Byte) YDreg; - if (YDreg == 26) - c = 'D'; - if (YDreg == 27) - c = 'U'; - return (c); -} - -static void check_context(Byte cmd) -{ - // A context is defined to be "modifying text" - // Any modifying command establishes a new context. - - if (dot < context_start || dot > context_end) { - if (strchr((char *) modifying_cmds, cmd) != NULL) { - // we are trying to modify text[]- make this the current context - mark[27] = mark[26]; // move cur to prev - mark[26] = dot; // move local to cur - context_start = prev_line(prev_line(dot)); - context_end = next_line(next_line(dot)); - //loiter= start_loiter= now; - } - } - return; -} - -static Byte *swap_context(Byte * p) // goto new context for '' command make this the current context -{ - Byte *tmp; - - // the current context is in mark[26] - // the previous context is in mark[27] - // only swap context if other context is valid - if (text <= mark[27] && mark[27] <= end - 1) { - tmp = mark[27]; - mark[27] = mark[26]; - mark[26] = tmp; - p = mark[26]; // where we are going- previous context - context_start = prev_line(prev_line(prev_line(p))); - context_end = next_line(next_line(next_line(p))); - } - return (p); -} -#endif /* BB_FEATURE_VI_YANKMARK */ - -static int isblnk(Byte c) // is the char a blank or tab -{ - return (c == ' ' || c == '\t'); -} - -//----- Set terminal attributes -------------------------------- -static void rawmode(void) -{ - tcgetattr(0, &term_orig); - term_vi = term_orig; - term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's - term_vi.c_iflag &= (~IXON & ~ICRNL); - term_vi.c_oflag &= (~ONLCR); -#ifndef linux - term_vi.c_cc[VMIN] = 1; - term_vi.c_cc[VTIME] = 0; -#endif - erase_char = term_vi.c_cc[VERASE]; - tcsetattr(0, TCSANOW, &term_vi); -} - -static void cookmode(void) -{ - tcsetattr(0, TCSANOW, &term_orig); -} - -#ifdef BB_FEATURE_VI_WIN_RESIZE -//----- See what the window size currently is -------------------- -static void window_size_get(int sig) -{ - int i; - - i = ioctl(0, TIOCGWINSZ, &winsize); - if (i != 0) { - // force 24x80 - winsize.ws_row = 24; - winsize.ws_col = 80; - } - if (winsize.ws_row <= 1) { - winsize.ws_row = 24; - } - if (winsize.ws_col <= 1) { - winsize.ws_col = 80; - } - rows = (int) winsize.ws_row; - columns = (int) winsize.ws_col; -} -#endif /* BB_FEATURE_VI_WIN_RESIZE */ - -//----- Come here when we get a window resize signal --------- -#ifdef BB_FEATURE_VI_USE_SIGNALS -static void winch_sig(int sig) -{ - signal(SIGWINCH, winch_sig); -#ifdef BB_FEATURE_VI_WIN_RESIZE - window_size_get(0); -#endif /* BB_FEATURE_VI_WIN_RESIZE */ - new_screen(rows, columns); // get memory for virtual screen - redraw(TRUE); // re-draw the screen -} - -//----- Come here when we get a continue signal ------------------- -static void cont_sig(int sig) -{ - rawmode(); // terminal to "raw" - *status_buffer = '\0'; // clear the status buffer - redraw(TRUE); // re-draw the screen - - signal(SIGTSTP, suspend_sig); - signal(SIGCONT, SIG_DFL); - kill(getpid(), SIGCONT); -} - -//----- Come here when we get a Suspend signal ------------------- -static void suspend_sig(int sig) -{ - place_cursor(rows - 1, 0, FALSE); // go to bottom of screen - clear_to_eol(); // Erase to end of line - cookmode(); // terminal to "cooked" - - signal(SIGCONT, cont_sig); - signal(SIGTSTP, SIG_DFL); - kill(getpid(), SIGTSTP); -} - -//----- Come here when we get a signal --------------------------- -static void catch_sig(int sig) -{ - signal(SIGHUP, catch_sig); - signal(SIGINT, catch_sig); - signal(SIGTERM, catch_sig); - longjmp(restart, sig); -} - -static void alarm_sig(int sig) -{ - signal(SIGALRM, catch_sig); - longjmp(restart, sig); -} - -//----- Come here when we get a core dump signal ----------------- -static void core_sig(int sig) -{ - signal(SIGQUIT, core_sig); - signal(SIGILL, core_sig); - signal(SIGTRAP, core_sig); - signal(SIGIOT, core_sig); - signal(SIGABRT, core_sig); - signal(SIGFPE, core_sig); - signal(SIGBUS, core_sig); - signal(SIGSEGV, core_sig); -#ifdef SIGSYS - signal(SIGSYS, core_sig); -#endif - - dot = bound_dot(dot); // make sure "dot" is valid - - longjmp(restart, sig); -} -#endif /* BB_FEATURE_VI_USE_SIGNALS */ - -static int mysleep(int hund) // sleep for 'h' 1/100 seconds -{ - // Don't hang- Wait 5/100 seconds- 1 Sec= 1000000 - FD_ZERO(&rfds); - FD_SET(0, &rfds); - tv.tv_sec = 0; - tv.tv_usec = hund * 10000; - select(1, &rfds, NULL, NULL, &tv); - return (FD_ISSET(0, &rfds)); -} - -//----- IO Routines -------------------------------------------- -static Byte readit(void) // read (maybe cursor) key from stdin -{ - Byte c; - int i, bufsiz, cnt, cmdindex; - struct esc_cmds { - Byte *seq; - Byte val; - }; - - static struct esc_cmds esccmds[] = { - {(Byte *) "OA", (Byte) VI_K_UP}, // cursor key Up - {(Byte *) "OB", (Byte) VI_K_DOWN}, // cursor key Down - {(Byte *) "OC", (Byte) VI_K_RIGHT}, // Cursor Key Right - {(Byte *) "OD", (Byte) VI_K_LEFT}, // cursor key Left - {(Byte *) "OH", (Byte) VI_K_HOME}, // Cursor Key Home - {(Byte *) "OF", (Byte) VI_K_END}, // Cursor Key End - {(Byte *) "", (Byte) VI_K_UP}, // cursor key Up - {(Byte *) "", (Byte) VI_K_DOWN}, // cursor key Down - {(Byte *) "", (Byte) VI_K_RIGHT}, // Cursor Key Right - {(Byte *) "", (Byte) VI_K_LEFT}, // cursor key Left - {(Byte *) "", (Byte) VI_K_HOME}, // Cursor Key Home - {(Byte *) "", (Byte) VI_K_END}, // Cursor Key End - {(Byte *) "[2~", (Byte) VI_K_INSERT}, // Cursor Key Insert - {(Byte *) "[5~", (Byte) VI_K_PAGEUP}, // Cursor Key Page Up - {(Byte *) "[6~", (Byte) VI_K_PAGEDOWN}, // Cursor Key Page Down - {(Byte *) "OP", (Byte) VI_K_FUN1}, // Function Key F1 - {(Byte *) "OQ", (Byte) VI_K_FUN2}, // Function Key F2 - {(Byte *) "OR", (Byte) VI_K_FUN3}, // Function Key F3 - {(Byte *) "OS", (Byte) VI_K_FUN4}, // Function Key F4 - {(Byte *) "[15~", (Byte) VI_K_FUN5}, // Function Key F5 - {(Byte *) "[17~", (Byte) VI_K_FUN6}, // Function Key F6 - {(Byte *) "[18~", (Byte) VI_K_FUN7}, // Function Key F7 - {(Byte *) "[19~", (Byte) VI_K_FUN8}, // Function Key F8 - {(Byte *) "[20~", (Byte) VI_K_FUN9}, // Function Key F9 - {(Byte *) "[21~", (Byte) VI_K_FUN10}, // Function Key F10 - {(Byte *) "[23~", (Byte) VI_K_FUN11}, // Function Key F11 - {(Byte *) "[24~", (Byte) VI_K_FUN12}, // Function Key F12 - {(Byte *) "[11~", (Byte) VI_K_FUN1}, // Function Key F1 - {(Byte *) "[12~", (Byte) VI_K_FUN2}, // Function Key F2 - {(Byte *) "[13~", (Byte) VI_K_FUN3}, // Function Key F3 - {(Byte *) "[14~", (Byte) VI_K_FUN4}, // Function Key F4 - }; - -#define ESCCMDS_COUNT (sizeof(esccmds)/sizeof(struct esc_cmds)) - - (void) alarm(0); // turn alarm OFF while we wait for input - // get input from User- are there already input chars in Q? - bufsiz = strlen((char *) readbuffer); - if (bufsiz <= 0) { - ri0: - // the Q is empty, wait for a typed char - bufsiz = read(0, readbuffer, BUFSIZ - 1); - if (bufsiz < 0) { - if (errno == EINTR) - goto ri0; // interrupted sys call - if (errno == EBADF) - editing = 0; - if (errno == EFAULT) - editing = 0; - if (errno == EINVAL) - editing = 0; - if (errno == EIO) - editing = 0; - errno = 0; - bufsiz = 0; - } - readbuffer[bufsiz] = '\0'; - } - // return char if it is not part of ESC sequence - if (readbuffer[0] != 27) - goto ri1; - - // This is an ESC char. Is this Esc sequence? - // Could be bare Esc key. See if there are any - // more chars to read after the ESC. This would - // be a Function or Cursor Key sequence. - FD_ZERO(&rfds); - FD_SET(0, &rfds); - tv.tv_sec = 0; - tv.tv_usec = 50000; // Wait 5/100 seconds- 1 Sec=1000000 - - // keep reading while there are input chars and room in buffer - while (select(1, &rfds, NULL, NULL, &tv) > 0 && bufsiz <= (BUFSIZ - 5)) { - // read the rest of the ESC string - i = read(0, (void *) (readbuffer + bufsiz), BUFSIZ - bufsiz); - if (i > 0) { - bufsiz += i; - readbuffer[bufsiz] = '\0'; // Terminate the string - } - } - // Maybe cursor or function key? - for (cmdindex = 0; cmdindex < ESCCMDS_COUNT; cmdindex++) { - cnt = strlen((char *) esccmds[cmdindex].seq); - i = strncmp((char *) esccmds[cmdindex].seq, (char *) readbuffer, cnt); - if (i == 0) { - // is a Cursor key- put derived value back into Q - readbuffer[0] = esccmds[cmdindex].val; - // squeeze out the ESC sequence - for (i = 1; i < cnt; i++) { - memmove(readbuffer + 1, readbuffer + 2, BUFSIZ - 2); - readbuffer[BUFSIZ - 1] = '\0'; - } - break; - } - } - ri1: - c = readbuffer[0]; - // remove one char from Q - memmove(readbuffer, readbuffer + 1, BUFSIZ - 1); - readbuffer[BUFSIZ - 1] = '\0'; - (void) alarm(3); // we are done waiting for input, turn alarm ON - return (c); -} - -//----- IO Routines -------------------------------------------- -static Byte get_one_char() -{ - static Byte c; - -#ifdef BB_FEATURE_VI_DOT_CMD - // ! adding2q && ioq == 0 read() - // ! adding2q && ioq != 0 *ioq - // adding2q *last_modifying_cmd= read() - if (!adding2q) { - // we are not adding to the q. - // but, we may be reading from a q - if (ioq == 0) { - // there is no current q, read from STDIN - c = readit(); // get the users input - } else { - // there is a queue to get chars from first - c = *ioq++; - if (c == '\0') { - // the end of the q, read from STDIN - free(ioq_start); - ioq_start = ioq = 0; - c = readit(); // get the users input - } - } - } else { - // adding STDIN chars to q - c = readit(); // get the users input - if (last_modifying_cmd != 0) { - // add new char to q - last_modifying_cmd[strlen((char *) last_modifying_cmd)] = c; - } - } -#else /* BB_FEATURE_VI_DOT_CMD */ - c = readit(); // get the users input -#endif /* BB_FEATURE_VI_DOT_CMD */ - return (c); // return the char, where ever it came from -} - -static Byte *get_input_line(Byte * prompt) // get input line- use "status line" -{ - Byte buf[BUFSIZ]; - Byte c; - int i; - static Byte *obufp = NULL; - - strcpy((char *) buf, (char *) prompt); - *status_buffer = '\0'; // clear the status buffer - place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen - clear_to_eol(); // clear the line - write(1, prompt, strlen((char *) prompt)); // write out the :, /, or ? prompt - - for (i = strlen((char *) buf); i < BUFSIZ;) { - c = get_one_char(); // read user input - if (c == '\n' || c == '\r' || c == 27) - break; // is this end of input - if (c == erase_char) { // user wants to erase prev char - i--; // backup to prev char - buf[i] = '\0'; // erase the char - buf[i + 1] = '\0'; // null terminate buffer - write(1, " ", 3); // erase char on screen - if (i <= 0) { // user backs up before b-o-l, exit - break; - } - } else { - buf[i] = c; // save char in buffer - buf[i + 1] = '\0'; // make sure buffer is null terminated - write(1, buf + i, 1); // echo the char back to user - i++; - } - } - refresh(FALSE); - if (obufp != NULL) - free(obufp); - obufp = (Byte *) strdup((char *) buf); - return (obufp); -} - -static int file_size(Byte * fn) // what is the byte size of "fn" -{ - struct stat st_buf; - int cnt, sr; - - if (fn == 0 || strlen(fn) <= 0) - return (-1); - cnt = -1; - sr = stat((char *) fn, &st_buf); // see if file exists - if (sr >= 0) { - cnt = (int) st_buf.st_size; - } - return (cnt); -} - -static int file_insert(Byte * fn, Byte * p, int size) -{ - int fd, cnt; - - cnt = -1; -#ifdef BB_FEATURE_VI_READONLY - readonly = FALSE; -#endif /* BB_FEATURE_VI_READONLY */ - if (fn == 0 || strlen((char*) fn) <= 0) { - psbs("No filename given"); - goto fi0; - } - if (size == 0) { - // OK- this is just a no-op - cnt = 0; - goto fi0; - } - if (size < 0) { - psbs("Trying to insert a negative number (%d) of characters", size); - goto fi0; - } - if (p < text || p > end) { - psbs("Trying to insert file outside of memory"); - goto fi0; - } - - // see if we can open the file -#ifdef BB_FEATURE_VI_READONLY - if (vi_readonly == TRUE) goto fi1; // do not try write-mode -#endif - fd = open((char *) fn, O_RDWR); // assume read & write - if (fd < 0) { - // could not open for writing- maybe file is read only -#ifdef BB_FEATURE_VI_READONLY - fi1: -#endif - fd = open((char *) fn, O_RDONLY); // try read-only - if (fd < 0) { - psbs("\"%s\" %s", fn, "could not open file"); - goto fi0; - } -#ifdef BB_FEATURE_VI_READONLY - // got the file- read-only - readonly = TRUE; -#endif /* BB_FEATURE_VI_READONLY */ - } - p = text_hole_make(p, size); - cnt = read(fd, p, size); - close(fd); - if (cnt < 0) { - cnt = -1; - p = text_hole_delete(p, p + size - 1); // un-do buffer insert - psbs("could not read file \"%s\"", fn); - } else if (cnt < size) { - // There was a partial read, shrink unused space text[] - p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert - psbs("could not read all of file \"%s\"", fn); - } - if (cnt >= size) - file_modified = TRUE; - fi0: - return (cnt); -} - -static int file_write(Byte * fn, Byte * first, Byte * last) -{ - int fd, cnt, charcnt; - - if (fn == 0) { - psbs("No current filename"); - return (-1); - } - charcnt = 0; - // FIXIT- use the correct umask() - fd = open((char *) fn, (O_WRONLY | O_CREAT | O_TRUNC), 0664); - if (fd < 0) - return (-1); - cnt = last - first + 1; - charcnt = write(fd, first, cnt); - if (charcnt == cnt) { - // good write - //file_modified= FALSE; // the file has not been modified - } else { - charcnt = 0; - } - close(fd); - return (charcnt); -} - -//----- Terminal Drawing --------------------------------------- -// The terminal is made up of 'rows' line of 'columns' columns. -// classicly this would be 24 x 80. -// screen coordinates -// 0,0 ... 0,79 -// 1,0 ... 1,79 -// . ... . -// . ... . -// 22,0 ... 22,79 -// 23,0 ... 23,79 status line -// - -//----- Move the cursor to row x col (count from 0, not 1) ------- -static void place_cursor(int row, int col, int opti) -{ - char cm1[BUFSIZ]; - char *cm; - int l; -#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR - char cm2[BUFSIZ]; - Byte *screenp; - // char cm3[BUFSIZ]; - int Rrow= last_row; -#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ - - memset(cm1, '\0', BUFSIZ - 1); // clear the buffer - - if (row < 0) row = 0; - if (row >= rows) row = rows - 1; - if (col < 0) col = 0; - if (col >= columns) col = columns - 1; - - //----- 1. Try the standard terminal ESC sequence - sprintf((char *) cm1, CMrc, row + 1, col + 1); - cm= cm1; - if (opti == FALSE) goto pc0; - -#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR - //----- find the minimum # of chars to move cursor ------------- - //----- 2. Try moving with discreet chars (Newline, [back]space, ...) - memset(cm2, '\0', BUFSIZ - 1); // clear the buffer - - // move to the correct row - while (row < Rrow) { - // the cursor has to move up - strcat(cm2, CMup); - Rrow--; - } - while (row > Rrow) { - // the cursor has to move down - strcat(cm2, CMdown); - Rrow++; - } - - // now move to the correct column - strcat(cm2, "\r"); // start at col 0 - // just send out orignal source char to get to correct place - screenp = &screen[row * columns]; // start of screen line - strncat(cm2, screenp, col); - - //----- 3. Try some other way of moving cursor - //--------------------------------------------- - - // pick the shortest cursor motion to send out - cm= cm1; - if (strlen(cm2) < strlen(cm)) { - cm= cm2; - } /* else if (strlen(cm3) < strlen(cm)) { - cm= cm3; - } */ -#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ - pc0: - l= strlen(cm); - if (l) write(1, cm, l); // move the cursor -} - -//----- Erase from cursor to end of line ----------------------- -static void clear_to_eol() -{ - write(1, Ceol, strlen(Ceol)); // Erase from cursor to end of line -} - -//----- Erase from cursor to end of screen ----------------------- -static void clear_to_eos() -{ - write(1, Ceos, strlen(Ceos)); // Erase from cursor to end of screen -} - -//----- Start standout mode ------------------------------------ -static void standout_start() // send "start reverse video" sequence -{ - write(1, SOs, strlen(SOs)); // Start reverse video mode -} - -//----- End standout mode -------------------------------------- -static void standout_end() // send "end reverse video" sequence -{ - write(1, SOn, strlen(SOn)); // End reverse video mode -} - -//----- Flash the screen -------------------------------------- -static void flash(int h) -{ - standout_start(); // send "start reverse video" sequence - redraw(TRUE); - (void) mysleep(h); - standout_end(); // send "end reverse video" sequence - redraw(TRUE); -} - -static void beep() -{ - write(1, bell, strlen(bell)); // send out a bell character -} - -static void indicate_error(char c) -{ -#ifdef BB_FEATURE_VI_CRASHME - if (crashme > 0) - return; // generate a random command -#endif /* BB_FEATURE_VI_CRASHME */ - if (err_method == 0) { - beep(); - } else { - flash(10); - } -} - -//----- Screen[] Routines -------------------------------------- -//----- Erase the Screen[] memory ------------------------------ -static void screen_erase() -{ - memset(screen, ' ', screensize); // clear new screen -} - -//----- Draw the status line at bottom of the screen ------------- -static void show_status_line(void) -{ - static int last_cksum; - int l, cnt, cksum; - - cnt = strlen((char *) status_buffer); - for (cksum= l= 0; l < cnt; l++) { cksum += (int)(status_buffer[l]); } - // don't write the status line unless it changes - if (cnt > 0 && last_cksum != cksum) { - last_cksum= cksum; // remember if we have seen this line - place_cursor(rows - 1, 0, FALSE); // put cursor on status line - write(1, status_buffer, cnt); - clear_to_eol(); - place_cursor(crow, ccol, FALSE); // put cursor back in correct place - } -} - -//----- format the status buffer, the bottom line of screen ------ -// print status buffer, with STANDOUT mode -static void psbs(char *format, ...) -{ - va_list args; - - va_start(args, format); - strcpy((char *) status_buffer, SOs); // Terminal standout mode on - vsprintf((char *) status_buffer + strlen((char *) status_buffer), format, - args); - strcat((char *) status_buffer, SOn); // Terminal standout mode off - va_end(args); - - return; -} - -// print status buffer -static void psb(char *format, ...) -{ - va_list args; - - va_start(args, format); - vsprintf((char *) status_buffer, format, args); - va_end(args); - return; -} - -static void ni(Byte * s) // display messages -{ - Byte buf[BUFSIZ]; - - print_literal(buf, s); - psbs("\'%s\' is not implemented", buf); -} - -static void edit_status(void) // show file status on status line -{ - int cur, tot, percent; - - cur = count_lines(text, dot); - tot = count_lines(text, end - 1); - // current line percent - // ------------- ~~ ---------- - // total lines 100 - if (tot > 0) { - percent = (100 * cur) / tot; - } else { - cur = tot = 0; - percent = 100; - } - psb("\"%s\"" -#ifdef BB_FEATURE_VI_READONLY - "%s" -#endif /* BB_FEATURE_VI_READONLY */ - "%s line %d of %d --%d%%--", - (cfn != 0 ? (char *) cfn : "No file"), -#ifdef BB_FEATURE_VI_READONLY - ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""), -#endif /* BB_FEATURE_VI_READONLY */ - (file_modified == TRUE ? " [modified]" : ""), - cur, tot, percent); -} - -//----- Force refresh of all Lines ----------------------------- -static void redraw(int full_screen) -{ - place_cursor(0, 0, FALSE); // put cursor in correct place - clear_to_eos(); // tel terminal to erase display - screen_erase(); // erase the internal screen buffer - refresh(full_screen); // this will redraw the entire display -} - -//----- Format a text[] line into a buffer --------------------- -static void format_line(Byte *dest, Byte *src, int li) -{ - int co; - Byte c; - - for (co= 0; co < MAX_SCR_COLS; co++) { - c= ' '; // assume blank - if (li > 0 && co == 0) { - c = '~'; // not first line, assume Tilde - } - // are there chars in text[] and have we gone past the end - if (text < end && src < end) { - c = *src++; - } - if (c == '\n') - break; - if (c < ' ' || c > '~') { - if (c == '\t') { - c = ' '; - // co % 8 != 7 - for (; (co % tabstop) != (tabstop - 1); co++) { - dest[co] = c; - } - } else { - dest[co++] = '^'; - c |= '@'; // make it visible - c &= 0x7f; // get rid of hi bit - } - } - // the co++ is done here so that the column will - // not be overwritten when we blank-out the rest of line - dest[co] = c; - if (src >= end) - break; - } -} - -//----- Refresh the changed screen lines ----------------------- -// Copy the source line from text[] into the buffer and note -// if the current screenline is different from the new buffer. -// If they differ then that line needs redrawing on the terminal. -// -static void refresh(int full_screen) -{ - static int old_offset; - int li, changed; - Byte buf[MAX_SCR_COLS]; - Byte *tp, *sp; // pointer into text[] and screen[] -#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR - int last_li= -2; // last line that changed- for optimizing cursor movement -#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ - -#ifdef BB_FEATURE_VI_WIN_RESIZE - window_size_get(0); -#endif /* BB_FEATURE_VI_WIN_RESIZE */ - sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot") - tp = screenbegin; // index into text[] of top line - - // compare text[] to screen[] and mark screen[] lines that need updating - for (li = 0; li < rows - 1; li++) { - int cs, ce; // column start & end - memset(buf, ' ', MAX_SCR_COLS); // blank-out the buffer - buf[MAX_SCR_COLS-1] = 0; // NULL terminate the buffer - // format current text line into buf - format_line(buf, tp, li); - - // skip to the end of the current text[] line - while (tp < end && *tp++ != '\n') /*no-op*/ ; - - // see if there are any changes between vitual screen and buf - changed = FALSE; // assume no change - cs= 0; - ce= columns-1; - sp = &screen[li * columns]; // start of screen line - if (full_screen == TRUE) { - // force re-draw of every single column from 0 - columns-1 - goto re0; - } - // compare newly formatted buffer with virtual screen - // look forward for first difference between buf and screen - for ( ; cs <= ce; cs++) { - if (buf[cs + offset] != sp[cs]) { - changed = TRUE; // mark for redraw - break; - } - } - - // look backward for last difference between buf and screen - for ( ; ce >= cs; ce--) { - if (buf[ce + offset] != sp[ce]) { - changed = TRUE; // mark for redraw - break; - } - } - // now, cs is index of first diff, and ce is index of last diff - - // if horz offset has changed, force a redraw - if (offset != old_offset) { - re0: - changed = TRUE; - } - - // make a sanity check of columns indexes - if (cs < 0) cs= 0; - if (ce > columns-1) ce= columns-1; - if (cs > ce) { cs= 0; ce= columns-1; } - // is there a change between vitual screen and buf - if (changed == TRUE) { - // copy changed part of buffer to virtual screen - memmove(sp+cs, buf+(cs+offset), ce-cs+1); - - // move cursor to column of first change - if (offset != old_offset) { - // opti_cur_move is still too stupid - // to handle offsets correctly - place_cursor(li, cs, FALSE); - } else { -#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR - // if this just the next line - // try to optimize cursor movement - // otherwise, use standard ESC sequence - place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE); - last_li= li; -#else /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ - place_cursor(li, cs, FALSE); // use standard ESC sequence -#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ - } - - // write line out to terminal - write(1, sp+cs, ce-cs+1); -#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR - last_row = li; -#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ - } - } - -#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR - place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE); - last_row = crow; -#else - place_cursor(crow, ccol, FALSE); -#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ - - if (offset != old_offset) - old_offset = offset; -} diff --git a/busybox/env.c b/busybox/env.c deleted file mode 100644 index 8bb690b72..000000000 --- a/busybox/env.c +++ /dev/null @@ -1,106 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * env implementation for busybox - * - * 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 - * - * Original copyright notice is retained at the end of this file. - * - * Modified for BusyBox by Erik Andersen , - */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -extern int env_main(int argc, char** argv) -{ - char **ep, *p; - char *cleanenv[1]; - int ignore_environment = 0; - int ch; - - while ((ch = getopt(argc, argv, "+iu:")) != -1) { - switch(ch) { - case 'i': - ignore_environment = 1; - break; - case 'u': - unsetenv(optarg); - break; - default: - show_usage(); - } - } - if (optind != argc && !strcmp(argv[optind], "-")) { - ignore_environment = 1; - argv++; - } - if (ignore_environment) { - environ = cleanenv; - cleanenv[0] = NULL; - } - for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv) - if (putenv(*argv) < 0) - perror_msg_and_die("%s", *argv); - if (*argv) { - execvp(*argv, argv); - perror_msg_and_die("%s", *argv); - } - for (ep = environ; *ep; ep++) - puts(*ep); - return 0; -} - -/* - * Copyright (c) 1988, 1993, 1994 - * The 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. - */ - - diff --git a/busybox/examples/bootfloppy/bootfloppy.txt b/busybox/examples/bootfloppy/bootfloppy.txt deleted file mode 100644 index 575c93fcc..000000000 --- a/busybox/examples/bootfloppy/bootfloppy.txt +++ /dev/null @@ -1,185 +0,0 @@ -Building a Busybox Boot Floppy -============================== - -This document describes how to buid a boot floppy using the following -components: - - - Linux Kernel (http://www.kernel.org) - - uClibc: C library (http://cvs.uclinux.org/uClibc.html) - - Busybox: Unix utilities (http://busybox.lineo.com) - - Syslinux: bootloader (http://syslinux.zytor.com) - -It is based heavily on a paper presented by Erik Andersen at the 2001 Embedded -Systems Conference. - - - -Building The Software Components --------------------------------- - -Detailed instructions on how to build Busybox, uClibc, or a working Linux -kernel are beyond the scope of this document. The following guidelines will -help though: - - - Stock Busybox from CVS or a tarball will work with no modifications to - any files. Just extract and go. - - Ditto uClibc. - - Your Linux kernel must include support for initrd or else the floppy - won't be able to mount it's root file system. - -If you require further information on building Busybox uClibc or Linux, please -refer to the web pages and documentation for those individual programs. - - - -Making a Root File System -------------------------- - -The following steps will create a root file system. - - - Create an empty file that you can format as a filesystem: - - dd if=/dev/zero of=rootfs bs=1k count=4000 - - - Set up the rootfs file we just created to be used as a loop device (may not - be necessary) - - losetup /dev/loop0 rootfs - - - Format the rootfs file with a filesystem: - - mkfs.ext2 -F -i 2000 rootfs - - - Mount the file on a mountpoint so we can place files in it: - - mkdir loop - mount -o loop rootfs loop/ - - (you will probably need to be root to do this) - - - Copy on the C library, the dynamic linking library, and other necessary - libraries. For this example, we copy the following files from the uClibc - tree: - - mkdir loop/lib - (chdir to uClibc directory) - cp -a libc.so* uClibc*.so \ - ld.so-1/d-link/ld-linux-uclibc.so* \ - ld.so-1/libdl/libdl.so* \ - crypt/libcrypt.so* \ - (path to)loop/lib - - - Install the Busybox binary and accompanying symlinks: - - (chdir to busybox directory) - make PREFIX=(path to)loop/ install - - - Make device files in /dev: - - This can be done by running the 'mkdevs.sh' script. If you want the gory - details, you can read the script. - - - Make necessary files in /etc: - - For this, just cp -a the etc/ directory onto rootfs. Again, if you want - all the details, you can just look at the files in the dir. - - - Run ldconfig so busybox and other binaries can have access to the libraries - that they need: - - (path to)uClibc/ld.so-1/util/ldconfig -r loop/ - - - Unmount the rootfs from the mountpoint: - - umount loop - - - Compress it: - - gzip -9 rootfs - - -Making a SYSLINUX boot floppy ------------------------------ - -The following steps will create the boot floppy. - -Note: You will need to have the mtools package installed beforehand. - - - Insert a floppy in the drive and format it with an MSDOS filesystem: - - mformat a: - - (if the system doesn't know what device 'a:' is, look at /etc/mtools.conf) - - - Run syslinux on the floppy: - - syslinux -s /dev/fd0 - - (the -s stands for "safe, slow, and stupid" and should work better with - buggy BIOSes; it can be omitted) - - - Put on a syslinux.cfg file: - - mcopy syslinux.cfg a: - - (more on syslinux.cfg below) - - - Copy the root file system you made onto the MSDOS formatted floppy - - mcopy rootfs.gz a: - - - Build a linux kernel and copy it onto the disk with the filename 'linux' - - mcopy bzImage a:linux - - -Sample syslinux.cfg -~~~~~~~~~~~~~~~~~~~ - -The following simple syslinux.cfg file should work. You can tweak it if you -like. - -----begin-syslinux.cfg--------------- -DEFAULT linux -APPEND initrd=rootfs.gz root=/dev/ram0 -TIMEOUT 10 -PROMPT 1 -----end-syslinux.cfg--------------- - -Some changes you could make to syslinux.cfg: - - - This value is the number seconds it will wait before booting. You can set - the timeout to 0 (or omit) to boot instantly, or you can set it as high as - 10 to wait awhile. - - - PROMPT can be set to 0 to disable the 'boot:' prompt. - - - you can add this line to display the contents of a file as a welcome - message: - - DISPLAY display.txt - - - -Additional Resources --------------------- - -Other useful information on making a Linux bootfloppy is available at the -following URLs: - -http://www.linuxdoc.org/HOWTO/Bootdisk-HOWTO/index.html -http://www.linux-embedded.com/howto/Embedded-Linux-Howto.html -http://linux-embedded.org/howto/LFS-HOWTO.html -http://linux-embedded.org/pmhowto.html -http://recycle.lbl.gov/~ldoolitt/embedded/ (Larry Doolittle's stuff) - - - -Possible TODOs --------------- - -The following features that we might want to add later: - - - support for additional filesystems besides ext2, i.e. minix - - different libc, static vs dynamic loading - - maybe using an alternate bootloader diff --git a/busybox/examples/bootfloppy/display.txt b/busybox/examples/bootfloppy/display.txt deleted file mode 100644 index 399d326d9..000000000 --- a/busybox/examples/bootfloppy/display.txt +++ /dev/null @@ -1,4 +0,0 @@ - -This boot floppy is made with Busybox, uClibc, and the Linux kernel. -Hit RETURN to boot or enter boot parameters at the prompt below. - diff --git a/busybox/examples/bootfloppy/etc/fstab b/busybox/examples/bootfloppy/etc/fstab deleted file mode 100644 index ef14ca2cc..000000000 --- a/busybox/examples/bootfloppy/etc/fstab +++ /dev/null @@ -1,2 +0,0 @@ -proc /proc proc defaults 0 0 - diff --git a/busybox/examples/bootfloppy/etc/init.d/rcS b/busybox/examples/bootfloppy/etc/init.d/rcS deleted file mode 100755 index 4f29b923f..000000000 --- a/busybox/examples/bootfloppy/etc/init.d/rcS +++ /dev/null @@ -1,3 +0,0 @@ -#! /bin/sh - -/bin/mount -a diff --git a/busybox/examples/bootfloppy/etc/inittab b/busybox/examples/bootfloppy/etc/inittab deleted file mode 100644 index eb3e979ce..000000000 --- a/busybox/examples/bootfloppy/etc/inittab +++ /dev/null @@ -1,5 +0,0 @@ -::sysinit:/etc/init.d/rcS -::respawn:-/bin/sh -tty2::askfirst:-/bin/sh -::ctrlaltdel:/bin/umount -a -r - diff --git a/busybox/examples/bootfloppy/etc/profile b/busybox/examples/bootfloppy/etc/profile deleted file mode 100644 index e9b11e90a..000000000 --- a/busybox/examples/bootfloppy/etc/profile +++ /dev/null @@ -1,8 +0,0 @@ -# /etc/profile: system-wide .profile file for the Bourne shells - -echo -echo -n "Processing /etc/profile... " -# no-op -echo "Done" -echo - diff --git a/busybox/examples/bootfloppy/mkdevs.sh b/busybox/examples/bootfloppy/mkdevs.sh deleted file mode 100755 index 03a1a8550..000000000 --- a/busybox/examples/bootfloppy/mkdevs.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/sh -# -# makedev.sh - creates device files for a busybox boot floppy image - - -# we do our work in the dev/ directory -if [ -z "$1" ]; then - echo "usage: `basename $0` path/to/dev/dir" - exit 1 -fi - -cd $1 - - -# miscellaneous one-of-a-kind stuff -mknod console c 5 1 -mknod full c 1 7 -mknod kmem c 1 2 -mknod mem c 1 1 -mknod null c 1 3 -mknod port c 1 4 -mknod random c 1 8 -mknod urandom c 1 9 -mknod zero c 1 5 -ln -s /proc/kcore core - -# IDE HD devs -# note: not going to bother creating all concievable partitions; you can do -# that yourself as you need 'em. -mknod hda b 3 0 -mknod hdb b 3 64 -mknod hdc b 22 0 -mknod hdd b 22 64 - -# loop devs -for i in `seq 0 7`; do - mknod loop$i b 7 $i -done - -# ram devs -for i in `seq 0 9`; do - mknod ram$i b 1 $i -done -ln -s ram1 ram - -# ttys -mknod tty c 5 0 -for i in `seq 0 9`; do - mknod tty$i c 4 $i -done - -# virtual console screen devs -for i in `seq 0 9`; do - mknod vcs$i b 7 $i -done -ln -s vcs0 vcs - -# virtual console screen w/ attributes devs -for i in `seq 0 9`; do - mknod vcsa$i b 7 $i -done -ln -s vcsa0 vcsa diff --git a/busybox/examples/bootfloppy/mkrootfs.sh b/busybox/examples/bootfloppy/mkrootfs.sh deleted file mode 100755 index b59b57af0..000000000 --- a/busybox/examples/bootfloppy/mkrootfs.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/bash -# -# mkrootfs.sh - creates a root file system -# - -# TODO: need to add checks here to verify that busybox, uClibc and bzImage -# exist - - -# command-line settable variables -BUSYBOX_DIR=.. -UCLIBC_DIR=../../uClibc -TARGET_DIR=./loop -FSSIZE=4000 -CLEANUP=1 -MKFS='mkfs.ext2 -F' - -# don't-touch variables -BASE_DIR=`pwd` - - -while getopts 'b:u:s:t:Cm' opt -do - case $opt in - b) BUSYBOX_DIR=$OPTARG ;; - u) UCLIBC_DIR=$OPTARG ;; - t) TARGET_DIR=$OPTARG ;; - s) FSSIZE=$OPTARG ;; - C) CLEANUP=0 ;; - m) MKFS='mkfs.minix' ;; - *) - echo "usage: `basename $0` [-bu]" - echo " -b DIR path to busybox direcory (default ..)" - echo " -u DIR path to uClibc direcory (default ../../uClibc)" - echo " -t DIR path to target direcory (default ./loop)" - echo " -s SIZE size of root filesystem in Kbytes (default 4000)" - echo " -C don't perform cleanup (umount target dir, gzip rootfs, etc.)" - echo " (this allows you to 'chroot loop/ /bin/sh' to test it)" - echo " -m use minix filesystem (default is ext2)" - exit 1 - ;; - esac -done - - - - -# clean up from any previous work -mount | grep -q loop -[ $? -eq 0 ] && umount $TARGET_DIR -[ -d $TARGET_DIR ] && rm -rf $TARGET_DIR/ -[ -f rootfs ] && rm -f rootfs -[ -f rootfs.gz ] && rm -f rootfs.gz - - -# prepare root file system and mount as loopback -dd if=/dev/zero of=rootfs bs=1k count=$FSSIZE -$MKFS -i 2000 rootfs -mkdir $TARGET_DIR -mount -o loop,exec rootfs $TARGET_DIR # must be root - - -# install uClibc -mkdir -p $TARGET_DIR/lib -cd $UCLIBC_DIR -make INSTALL_DIR= -cp -a libc.so* $BASE_DIR/$TARGET_DIR/lib -cp -a uClibc*.so $BASE_DIR/$TARGET_DIR/lib -cp -a ld.so-1/d-link/ld-linux-uclibc.so* $BASE_DIR/$TARGET_DIR/lib -cp -a ld.so-1/libdl/libdl.so* $BASE_DIR/$TARGET_DIR/lib -cp -a crypt/libcrypt.so* $BASE_DIR/$TARGET_DIR/lib -cd $BASE_DIR - - -# install busybox and components -cd $BUSYBOX_DIR -make distclean -make CC=$BASE_DIR/$UCLIBC_DIR/extra/gcc-uClibc/i386-uclibc-gcc -make PREFIX=$BASE_DIR/$TARGET_DIR install -cd $BASE_DIR - - -# make files in /dev -mkdir $TARGET_DIR/dev -./mkdevs.sh $TARGET_DIR/dev - - -# make files in /etc -cp -a etc $TARGET_DIR -ln -s /proc/mounts $TARGET_DIR/etc/mtab - - -# other miscellaneous setup -mkdir $TARGET_DIR/initrd -mkdir $TARGET_DIR/proc -$UCLIBC_DIR/ld.so-1/util/ldconfig -r $TARGET_DIR - - -# Done. Maybe do cleanup. -if [ $CLEANUP -eq 1 ] -then - umount $TARGET_DIR - rmdir $TARGET_DIR - gzip -9 rootfs -fi - diff --git a/busybox/examples/bootfloppy/mksyslinux.sh b/busybox/examples/bootfloppy/mksyslinux.sh deleted file mode 100755 index e25417353..000000000 --- a/busybox/examples/bootfloppy/mksyslinux.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/bash -# -# Formats a floppy to use Syslinux - -dummy="" - - -# need to have mtools installed -if [ -z `which mformat` -o -z `which mcopy` ]; then - echo "You must have the mtools package installed to run this script" - exit 1 -fi - - -# need an arg for the location of the kernel -if [ -z "$1" ]; then - echo "usage: `basename $0` path/to/linux/kernel" - exit 1 -fi - - -# need to have a root file system built -if [ ! -f rootfs.gz ]; then - echo "You need to have a rootfs built first." - echo "Hit RETURN to make one now or Control-C to quit." - read dummy - ./mkrootfs.sh -fi - - -# prepare the floppy -echo "Please insert a blank floppy in the drive and press RETURN to format" -echo "(WARNING: All data will be erased! Hit Control-C to abort)" -read dummy - -echo "Formatting the floppy..." -mformat a: -echo "Making it bootable with Syslinux..." -syslinux -s /dev/fd0 -echo "Copying Syslinux configuration files..." -mcopy syslinux.cfg display.txt a: -echo "Copying root filesystem file..." -mcopy rootfs.gz a: -# XXX: maybe check for "no space on device" errors here -echo "Copying linux kernel..." -mcopy $1 a:linux -# XXX: maybe check for "no space on device" errors here too -echo "Finished: boot floppy created" diff --git a/busybox/examples/bootfloppy/quickstart.txt b/busybox/examples/bootfloppy/quickstart.txt deleted file mode 100644 index 0d8090824..000000000 --- a/busybox/examples/bootfloppy/quickstart.txt +++ /dev/null @@ -1,15 +0,0 @@ -Quickstart on making the Busybox boot-floppy: - - 1) Download Busybox and uClibc from CVS or tarballs. Make sure they share a - common parent directory. (i.e. busybox/ and uclibc/ are both right off of - /tmp, or wherever.) - - 2) Build a Linux kernel. Make sure you include support for initrd. - - 3) Put a floppy in the drive. Make sure it is a floppy you don't care about - because the contents will be overwritten. - - 4) As root, type ./mksyslinux.sh path/to/linux/kernel from this directory. - Wait patiently while the magic happens. - - 5) Boot up on the floppy. diff --git a/busybox/examples/bootfloppy/syslinux.cfg b/busybox/examples/bootfloppy/syslinux.cfg deleted file mode 100644 index 8d407cad4..000000000 --- a/busybox/examples/bootfloppy/syslinux.cfg +++ /dev/null @@ -1,7 +0,0 @@ -display display.txt -default linux -timeout 10 -prompt 1 -label linux - kernel linux - append initrd=rootfs.gz root=/dev/ram0 diff --git a/busybox/examples/busybox.spec b/busybox/examples/busybox.spec deleted file mode 100644 index 5cf13ca37..000000000 --- a/busybox/examples/busybox.spec +++ /dev/null @@ -1,44 +0,0 @@ -%define name busybox -%define epoch 0 -%define version 0.60.2.pre -%define release %(date -I | sed -e 's/-/_/g') -%define serial 1 - -Name: %{name} -#Epoch: %{epoch} -Version: %{version} -Release: %{release} -Serial: %{serial} -Copyright: GPL -Group: System/Utilities -Summary: BusyBox is a tiny suite of Unix utilities in a multi-call binary. -URL: http://busybox.lineo.com/ -Source: ftp://oss.lineo.com/busybox/%{name}-%{version}.tar.gz -Buildroot: /var/tmp/%{name}-%{version} -Packager : Erik Andersen - -%Description -BusyBox combines tiny versions of many common UNIX utilities into a single -small executable. It provides minimalist replacements for most of the utilities -you usually find in fileutils, shellutils, findutils, textutils, grep, gzip, -tar, etc. BusyBox provides a fairly complete POSIX environment for any small -or emdedded system. The utilities in BusyBox generally have fewer options then -their full featured GNU cousins; however, the options that are provided behave -very much like their GNU counterparts. - -%Prep -%setup -q -n %{name}-%{version} - -%Build -make - -%Install -rm -rf $RPM_BUILD_ROOT -make PREFIX=$RPM_BUILD_ROOT install - -%Clean -rm -rf $RPM_BUILD_ROOT - -%Files -%defattr(-,root,root) -/ diff --git a/busybox/examples/depmod.pl b/busybox/examples/depmod.pl deleted file mode 100755 index e65f07b68..000000000 --- a/busybox/examples/depmod.pl +++ /dev/null @@ -1,227 +0,0 @@ -#!/usr/bin/perl -w -# vi: set ts=4: -# Copyright (c) 2001 David Schleef -# Copyright (c) 2001 Erik Andersen -# Copyright (c) 2001 Stuart Hughes -# This program is free software; you can redistribute it and/or modify it -# under the same terms as Perl itself. - -# TODO -- use strict mode... -#use strict; - -use Getopt::Long; -use File::Find; - - -# Set up some default values - -my $basedir=""; -my $kernel; -my $kernelsyms; -my $stdout=1; -my $verbose=0; - - -# get command-line options - -my %opt; - -GetOptions( - \%opt, - "help|h", - "basedir|b=s" => \$basedir, - "kernel|k=s" => \$kernel, - "kernelsyms|F=s" => \$kernelsyms, - "stdout|n" => \$stdout, - "verbose|v" => \$verbose, -); - -if (defined $opt{help}) { - print - "$0 [OPTION]... [basedir]\n", - "\t-h --help\t\tShow this help screen\n", - "\t-b --basedir\t\tModules base directory (defaults to /lib/modules)\n", - "\t-k --kernel\t\tKernel binary for the target\n", - "\t-F --kernelsyms\t\tKernel symbol file\n", - "\t-n --stdout\t\tWrite to stdout instead of modules.dep\n", - "\t-v --verbose\t\tPrint out lots of debugging stuff\n", - ; - exit 1; -} - -if($basedir !~ m-/lib/modules-) { - warn "WARNING: base directory does not match ..../lib/modules\n"; -} - -# Find the list of .o files living under $basedir -#if ($verbose) { printf "Locating all modules\n"; } -my($file) = ""; -my(@liblist) = (); -find sub { - if ( -f $_ && ! -d $_ ) { - $file = $File::Find::name; - if ( $file =~ /.o$/ ) { - push(@liblist, $file); - if ($verbose) { printf "$file\n"; } - } - } -}, $basedir; -if ($verbose) { printf "Finished locating modules\n"; } - -foreach $obj ( @liblist, $kernel ){ - # turn the input file name into a target tag name - # vmlinux is a special that is only used to resolve symbols - if($obj =~ /vmlinux/) { - $tgtname = "vmlinux"; - } else { - ($tgtname) = $obj =~ m-(/lib/modules/.*)$-; - } - - warn "MODULE = $tgtname\n" if $verbose; - - # get a list of symbols - @output=`nm $obj`; - $ksymtab=grep m/ __ksymtab/, @output; - - # gather the exported symbols - if($ksymtab){ - # explicitly exported - foreach ( @output ) { - / __ksymtab_(.*)$/ and do { - warn "sym = $1\n" if $verbose; - $exp->{$1} = $tgtname; - }; - } - } else { - # exporting all symbols - foreach ( @output) { - / [ABCDGRST] (.*)$/ and do { - warn "syma = $1\n" if $verbose; - $exp->{$1} = $tgtname; - }; - } - } - # gather the unresolved symbols - foreach ( @output ) { - !/ __this_module/ && / U (.*)$/ and do { - warn "und = $1\n" if $verbose; - push @{$dep->{$tgtname}}, $1; - }; - } -} - - -# reduce dependancies: remove unresolvable and resolved from vmlinux -# remove duplicates -foreach $module (keys %$dep) { - $mod->{$module} = {}; - foreach (@{$dep->{$module}}) { - if( $exp->{$_} ) { - warn "resolved symbol $_ in file $exp->{$_}\n" if $verbose; - next if $exp->{$_} =~ /vmlinux/; - $mod->{$module}{$exp->{$_}} = 1; - } else { - warn "unresolved symbol $_ in file $module\n"; - } - } -} - -# resolve the dependancies for each module -foreach $module ( keys %$mod ) { - print "$module:\t"; - @sorted = sort bydep keys %{$mod->{$module}}; - print join(" \\\n\t",@sorted); -# foreach $m (@sorted ) { -# print "\t$m\n"; -# } - print "\n\n"; -} - -sub bydep -{ - foreach my $f ( keys %{$mod->{$b}} ) { - if($f eq $a) { - return 1; - } - } - return -1; -} - - - -__END__ - -=head1 NAME - -depmod.pl - a cross platform script to generate kernel module dependency - lists which can then be used by modprobe. - -=head1 SYNOPSIS - -depmod.pl [OPTION]... [FILE]... - -Example: - - depmod.pl -F linux/System.map target/lib/modules - -=head1 DESCRIPTION - -The purpose of this script is to automagically generate a list of of kernel -module dependancies. This script produces dependancy lists that should be -identical to the depmod program from the modutils package. Unlike the depmod -binary, however, depmod.pl is designed to be run on your host system, not -on your target system. - -This script was written by David Schleef to be used in -conjunction with the BusyBox modprobe applet. - -=head1 OPTIONS - -=over 4 - -=item B<-h --help> - -This displays the help message. - -=item B<-b --basedir> - -The base directory uner which the target's modules will be found. This -defaults to the /lib/modules directory. - -=item B<-k --kernel> - -Kernel binary for the target. You must either supply a kernel binary -or a kernel symbol file (using the -F option). - -=item B<-F --kernelsyms> - -Kernel symbol file for the target. You must supply either a kernel symbol file -kernel binary for the target (using the -k option). - -=item B<-n --stdout> - -Write to stdout instead of modules.dep. This is currently hard coded... -kernel binary for the target (using the -k option). - -=item B<--verbose> - -Be verbose (not implemented) - -=back - -=head1 COPYRIGHT - -Copyright (c) 2001 David Schleef -Copyright (c) 2001 Erik Andersen -Copyright (c) 2001 Stuart Hughes -This program is free software; you can redistribute it and/or modify it -under the same terms as Perl itself. - -=head1 AUTHOR - -David Schleef - -=cut - -# $Id: depmod.pl,v 1.1 2001/07/30 19:32:03 andersen Exp $ - diff --git a/busybox/examples/inittab b/busybox/examples/inittab deleted file mode 100644 index 8e7e945b3..000000000 --- a/busybox/examples/inittab +++ /dev/null @@ -1,86 +0,0 @@ -# /etc/inittab init(8) configuration for BusyBox -# -# Copyright (C) 1999 by Lineo, inc. Written by Erik Andersen -# , -# -# -# Note, BusyBox init doesn't support runlevels. The runlevels field is -# completely ignored by BusyBox init. If you want runlevels, use sysvinit. -# -# -# Format for each entry: ::: -# -# : WARNING: This field has a non-traditional meaning for BusyBox init! -# -# The id field is used by BusyBox init to specify the controlling tty for -# the specified process to run on. The contents of this field are -# appended to "/dev/" and used as-is. There is no need for this field to -# be unique, although if it isn't you may have strange results. If this -# field is left blank, it is completely ignored. Also note that if -# BusyBox detects that a serial console is in use, then all entries -# containing non-empty id fields will _not_ be run. BusyBox init does -# nothing with utmp. We don't need no stinkin' utmp. -# -# : The runlevels field is completely ignored. -# -# : Valid actions include: sysinit, respawn, askfirst, wait, once, -# ctrlaltdel, and shutdown. -# -# Note: askfirst acts just like respawn, but before running the specified -# process it displays the line "Please press Enter to activate this -# console." and then waits for the user to press enter before starting -# the specified process. -# -# Note: unrecognised actions (like initdefault) will cause init to emit -# an error message, and then go along with its business. -# -# : Specifies the process to be executed and it's command line. -# -# Note: BusyBox init works just fine without an inittab. If no inittab is -# found, it has the following default behavior: -# ::sysinit:/etc/init.d/rcS -# ::askfirst:/bin/sh -# ::ctrlaltdel:/sbin/reboot -# ::shutdown:/sbin/swapoff -a -# ::shutdown:/bin/umount -a -r -# if it detects that /dev/console is _not_ a serial console, it will -# also run: -# tty2::askfirst:/bin/sh -# tty3::askfirst:/bin/sh -# tty4::askfirst:/bin/sh -# -# Boot-time system configuration/initialization script. -# This is run first except when booting in single-user mode. -# -::sysinit:/etc/init.d/rcS - -# /bin/sh invocations on selected ttys -# -# Note below that we prefix the shell commands with a "-" to indicate to the -# shell that it is supposed to be a login shell. Normally this is handled by -# login, but since we are bypassing login in this case, BusyBox lets you do -# this yourself... -# -# Start an "askfirst" shell on the console (whatever that may be) -::askfirst:-/bin/sh -# Start an "askfirst" shell on /dev/tty2-4 -tty2::askfirst:-/bin/sh -tty3::askfirst:-/bin/sh -tty4::askfirst:-/bin/sh - -# /sbin/getty invocations for selected ttys -tty4::respawn:/sbin/getty 38400 tty5 -tty5::respawn:/sbin/getty 38400 tty6 - -# Example of how to put a getty on a serial line (for a terminal) -#::respawn:/sbin/getty -L ttyS0 9600 vt100 -#::respawn:/sbin/getty -L ttyS1 9600 vt100 -# -# Example how to put a getty on a modem line. -#::respawn:/sbin/getty 57600 ttyS2 - -# Stuff to do before rebooting -::ctrlaltdel:/sbin/reboot -::shutdown:/bin/umount -a -r -::shutdown:/sbin/swapoff -a - diff --git a/busybox/examples/kernel-patches/Will_devps_GoIntoTheKernel b/busybox/examples/kernel-patches/Will_devps_GoIntoTheKernel deleted file mode 100644 index 33ee8b47e..000000000 --- a/busybox/examples/kernel-patches/Will_devps_GoIntoTheKernel +++ /dev/null @@ -1,104 +0,0 @@ -I have been asked several times whether the devps patch will go into the -mainline Linux kernel. The following emails from Alan Cox and Linux Torvalds -make it clear that it is not going to happen. This does not mean this patch -had no value -- it does. It just means that those that like it get to apply it -themselves... - - -Erik - - -------------------------------- - -From alan@lxorguk.ukuu.org.uk Thu Apr 13 08:07:22 2000 -Return-Path: -Delivered-To: andersen@dillweed.dsl.xmission.com -Received: from localhost (dillweed.dsl.xmission.com [10.0.0.1]) - by dillweed.dsl.xmission.com (Postfix) with ESMTP id 1D57A11A4F5 - for ; Thu, 13 Apr 2000 08:07:22 -0600 (MDT) -Envelope-to: andersen@xmission.com -Received: from mail.xmission.com - by localhost with IMAP (fetchmail-5.3.3) - for andersen@dillweed.dsl.xmission.com (single-drop); Thu, 13 Apr 2000 08:07:22 -0600 (MDT) -Received: from [194.168.151.1] (helo=the-village.bc.nu) - by mail.xmission.com with esmtp (Exim 3.03 #3) - id 12fhQk-0002OZ-00 - for andersen@xmission.com; Thu, 13 Apr 2000 05:05:03 -0600 -Received: from alan by the-village.bc.nu with local (Exim 2.12 #1) - id 12fhQ9-0002nD-00 - for andersen@xmission.com; Thu, 13 Apr 2000 12:04:25 +0100 -Subject: Re: kernel ps drivers [Was: vm locking question] -To: andersen@xmission.com -Date: Thu, 13 Apr 2000 12:04:23 +0100 (BST) -In-Reply-To: <20000412224130.A2748@xmission.com> from "Erik Andersen" at Apr 12, 2000 10:41:30 PM -X-Mailer: ELM [version 2.5 PL1] -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Transfer-Encoding: 7bit -Message-Id: -From: Alan Cox -Status: RO -X-Status: A -Content-Length: 242 -Lines: 6 - -> On the subject of ps, would you be willing to accept my /dev/ps -> patch into the kernel? If no, any suggestions on what should -> be done differently (if anything) to make it worthy of inclusion? - -For 2.2.x no, for 2.3.x ask Linus not me - - -From torvalds@transmeta.com Thu Apr 13 09:18:16 2000 -Return-Path: -Delivered-To: andersen@dillweed.dsl.xmission.com -Received: from localhost (dillweed.dsl.xmission.com [10.0.0.1]) - by dillweed.dsl.xmission.com (Postfix) with ESMTP id 3776411A3DF - for ; Thu, 13 Apr 2000 09:18:16 -0600 (MDT) -Envelope-to: andersen@xmission.com -Received: from mail.xmission.com - by localhost with IMAP (fetchmail-5.3.3) - for andersen@dillweed.dsl.xmission.com (single-drop); Thu, 13 Apr 2000 09:18:16 -0600 (MDT) -Received: from [209.10.217.66] (helo=neon-gw.transmeta.com) - by mail.xmission.com with esmtp (Exim 3.03 #3) - id 12flK2-0004dd-00 - for andersen@xmission.com; Thu, 13 Apr 2000 09:14:22 -0600 -Received: (from root@localhost) - by neon-gw.transmeta.com (8.9.3/8.9.3) id IAA18635; - Thu, 13 Apr 2000 08:10:51 -0700 -Received: from mailhost.transmeta.com(10.1.1.15) by neon-gw.transmeta.com via smap (V2.1) - id xma018629; Thu, 13 Apr 00 08:10:25 -0700 -Received: from penguin.transmeta.com (root@penguin.transmeta.com [10.1.2.202]) - by deepthought.transmeta.com (8.9.3/8.9.3) with ESMTP id IAA12264; - Thu, 13 Apr 2000 08:13:53 -0700 (PDT) -Received: from localhost (torvalds@localhost) by penguin.transmeta.com (8.9.3/8.7.3) with ESMTP id IAA02051; Thu, 13 Apr 2000 08:13:53 -0700 -X-Authentication-Warning: penguin.transmeta.com: torvalds owned process doing -bs -Date: Thu, 13 Apr 2000 08:13:53 -0700 (PDT) -From: Linus Torvalds -To: Erik Andersen -Cc: Alan Cox -Subject: Re: kernel ps drivers [Was: vm locking question] -In-Reply-To: <20000413083127.A976@xmission.com> -Message-ID: -MIME-Version: 1.0 -Content-Type: TEXT/PLAIN; charset=US-ASCII -Status: RO -Content-Length: 659 -Lines: 16 - - - -On Thu, 13 Apr 2000, Erik Andersen wrote: -> -> For 2.3.x would you be willing to accept my /dev/ps driver into the kernel? -> (Assuming I remove the /dev/modules driver (since it was pointed out that there -> is a perfectly good syscall providing that interface). If no, is there anything -> that could be done differently (if anything) to make it worthy of inclusion? - -I do dislike /dev/ps mightily. If the problem is that /proc is too large, -then the right solution is to just clean up /proc. Which is getting done. -And yes, /proc will be larger than /dev/ps, but I still find that -preferable to having two incompatible ways to do the same thing. - - Linus - - diff --git a/busybox/examples/kernel-patches/devps.patch.9_25_2000 b/busybox/examples/kernel-patches/devps.patch.9_25_2000 deleted file mode 100644 index d74a26a99..000000000 --- a/busybox/examples/kernel-patches/devps.patch.9_25_2000 +++ /dev/null @@ -1,1478 +0,0 @@ -diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/Config.in linux/drivers/char/Config.in ---- linux-2.2.18-9.virgin/drivers/char/Config.in Mon Sep 18 15:02:30 2000 -+++ linux/drivers/char/Config.in Mon Sep 25 16:33:16 2000 -@@ -56,6 +56,8 @@ - dep_tristate 'Microgate SyncLink card support' CONFIG_SYNCLINK m - dep_tristate 'HDLC line discipline support' CONFIG_N_HDLC m - fi -+tristate 'Devps support' CONFIG_DEVPS -+tristate 'Devmounts support' CONFIG_DEVMTAB - bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS - if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then - int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 -diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/Makefile linux/drivers/char/Makefile ---- linux-2.2.18-9.virgin/drivers/char/Makefile Mon Sep 18 15:02:30 2000 -+++ linux/drivers/char/Makefile Mon Sep 25 18:01:12 2000 -@@ -697,6 +697,22 @@ - M_OBJS += $(sort $(filter $(module-list), $(obj-m))) - - -+ifeq ($(CONFIG_DEVPS),y) -+O_OBJS += devps.o -+else -+ ifeq ($(CONFIG_DEVPS),m) -+ M_OBJS += devps.o -+ endif -+endif -+ -+ifeq ($(CONFIG_DEVMTAB),y) -+O_OBJS += devmtab.o -+else -+ ifeq ($(CONFIG_DEVMTAB),m) -+ M_OBJS += devmtab.o -+ endif -+endif -+ - include $(TOPDIR)/Rules.make - - fastdep: -diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/devmtab.c linux/drivers/char/devmtab.c ---- linux-2.2.18-9.virgin/drivers/char/devmtab.c Wed Dec 31 17:00:00 1969 -+++ linux/drivers/char/devmtab.c Mon Sep 25 17:00:57 2000 -@@ -0,0 +1,295 @@ -+/* vi: set sw=8 ts=8: */ -+/* -+ * linux/drivers/char/devmtab.c -+ * -+ * Copyright (C) 2000 Erik Andersen -+ * -+ * May be copied or modified under the terms of the GNU General Public License. -+ * See linux/COPYING for more information. -+ * -+ * This driver implements an interface whereby programs such as mount(8), -+ * umount(8), and df(1) may obtain all the process information they need to do -+ * their jobs without needing to use /proc. This driver another step in my -+ * evil plan to completely dismantle /proc. Muhahahaha! -+ * -+ * Suggestions are welcome. Patches that work are more welcome though. ;-) -+ * -+ * -+ * When using this driver, running: -+ * mknod /dev/mtab c 10 22 -+ * could be considered helpful. -+ * -+ * ---------------------------------- -+ * 1.00 Mar 07, 2000 -- Initial version. -+ * -+ *************************************************************************/ -+ -+#define DEVMTAB_VERSION "1.00" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+/* Some variables used by this device */ -+static struct wait_queue *devmtab_waitq = NULL; -+static int devmtab_already_opened = 0; -+static char *mtabfile = NULL; -+static int mtab_ptr; -+static int mtab_size; -+ -+ -+ -+/**************************************************************************** -+ * Handle opening and closing of the device -+ */ -+ -+static long long -+devmtab_lseek (struct file *file, long long offset, int orig) -+{ -+ return -ESPIPE; -+} -+ -+static ssize_t -+devmtab_read (struct file *file, char *buf, size_t count, loff_t * ppos) -+{ -+ int n = mtab_size - mtab_ptr; -+ -+ if (mtab_size == 0) { -+ /* Make some space */ -+ if (!(mtabfile = (char *) get_free_page (GFP_KERNEL))) -+ return -ENOMEM; -+ /* Grab the mtab */ -+ get_filesystem_info (mtabfile); -+ mtab_ptr = 0; -+ mtab_size = strlen (mtabfile); -+ n = mtab_size - mtab_ptr; -+ } -+ -+ if (n > count) -+ n = count; -+ if (n <= 0) -+ return 0; -+ -+ if (copy_to_user (buf, mtabfile, n)) -+ return -EFAULT; -+ mtab_ptr += n; -+ return n; -+} -+ -+static int devmtab_open (struct inode *ip, struct file *fp) -+{ -+ /* Only let one process use us at any time -- putting other -+ * processes to sleep. Those opening us O_NONBLOCK will -+ * get an EAGAIN error */ -+ if ((fp->f_flags & O_NONBLOCK) && devmtab_already_opened) -+ return -EAGAIN; -+ -+ MOD_INC_USE_COUNT; -+ -+ while (devmtab_already_opened) { -+ int i, got_signal=0; -+ -+ /* Go to sleep until we get woken up -+ * by devmtab_close or we receive a signal */ -+ module_interruptible_sleep_on(&devmtab_waitq); -+ -+ for(i=0; i<_NSIG_WORDS && !got_signal; i++) -+ got_signal = current->signal.sig[i] & ~current->blocked.sig[i]; -+ -+ /* If we got a signal, decrement the use count -+ * and return to user space */ -+ if (got_signal) { -+ MOD_DEC_USE_COUNT; -+ return -EINTR; -+ } -+ } -+ -+ /* Since we got here, then devmtab_already_opened must equal 0 */ -+ devmtab_already_opened=1; -+ mtab_ptr = 0; -+ mtab_size = 0; -+ -+ return 0; -+} -+ -+static int devmtab_release (struct inode *ip, struct file *fp) -+{ -+ /* Clean up */ -+ if (mtabfile != NULL) { -+ free_page ((unsigned long) mtabfile); -+ mtabfile = NULL; -+ } -+ -+ /* Zero out the reference counter */ -+ devmtab_already_opened=0; -+ -+ /* Wake up anybody that is waiting to access this device */ -+ module_wake_up(&devmtab_waitq); -+ -+ MOD_DEC_USE_COUNT; -+ -+ return 0; -+} -+ -+static int -+devmtab_ioctl (struct inode *ip, struct file *fp, -+ unsigned int cmd, unsigned long arg) -+{ -+ switch (cmd) { -+ case DEVMTAB_COUNT_FILESYSTEMS:{ -+ return(count_kfstypes()); -+ } -+ -+ case DEVMTAB_GET_FILESYSTEMS:{ -+ int stat, count; -+ struct k_fstype* fstypelist; -+ -+ /* How many are there? */ -+ count = count_kfstypes(); -+ -+ /* Make some space */ -+ fstypelist = (struct k_fstype *)kmalloc(sizeof(struct k_fstype) * count, GFP_KERNEL); -+ if (!fstypelist) -+ return -ENOMEM; -+ memset(fstypelist, 0, sizeof(struct k_fstype) * count); -+ -+ /* Grab the mtab entries */ -+ get_kfstype_list(count, fstypelist); -+ -+ /* Make sure there is enough room */ -+ stat = verify_area (VERIFY_WRITE, (struct k_fstype *) arg, -+ sizeof(struct k_fstype) * count); -+ if (stat) { -+ printk (KERN_INFO -+ "devmtab: Insufficient space was provided.\n"); -+ return stat; -+ } -+ -+ /* Send it to user space */ -+ copy_to_user_ret ((struct k_fstype *) arg, fstypelist, -+ sizeof(struct k_fstype) * count, -+ -EFAULT); -+ -+ /* Clean up */ -+ kfree( fstypelist); -+ return 0; -+ } -+ -+ case DEVMTAB_COUNT_MOUNTS:{ -+ return(count_mounted_filesystems()); -+ } -+ -+ case DEVMTAB_GET_MOUNTS:{ -+ int stat, count; -+ struct k_mntent* mntentlist; -+ -+ /* How many are there? */ -+ count = count_mounted_filesystems(); -+ -+ /* Make some space */ -+ mntentlist = (struct k_mntent *)kmalloc(sizeof(struct k_mntent) * count, GFP_KERNEL); -+ if (!mntentlist) -+ return -ENOMEM; -+ memset(mntentlist, 0, sizeof(struct k_mntent) * count); -+ -+ /* Grab the mtab entries */ -+ get_mtab_entries (count, mntentlist); -+ -+ /* Make sure there is enough room */ -+ stat = verify_area (VERIFY_WRITE, (void*) arg, -+ sizeof(struct k_mntent) * count); -+ if (stat) { -+ printk (KERN_INFO -+ "devmtab: Insufficient space was provided.\n"); -+ return stat; -+ } -+ -+ /* Send it to user space */ -+ copy_to_user_ret ((struct k_mntent *) arg, mntentlist, -+ sizeof(struct k_mntent) * count, -+ -EFAULT); -+ -+ /* Clean up */ -+ kfree( mntentlist); -+ return 0; -+ } -+ -+ default: -+ return -EINVAL; -+ -+ } -+ return 0; -+} -+ -+ -+ -+/**************************************************************************** -+ * Set up the file operations devmtab will support -+ */ -+static struct file_operations devmtab_fops = { -+ devmtab_lseek, -+ devmtab_read, -+ NULL, /* No write */ -+ NULL, /* No readdir */ -+ NULL, /* No poll */ -+ devmtab_ioctl, -+ NULL, /* No mmap */ -+ devmtab_open, -+ NULL, /* flush */ -+ devmtab_release, -+ NULL, /* fsync */ -+ NULL, /* fasync */ -+ NULL, /* check_media_change */ -+ NULL /* revalidate */ -+}; -+ -+static struct miscdevice devmtab_misc_dev = { -+ DEVMTAB_MINOR, -+ "devmtab", -+ &devmtab_fops -+}; -+ -+/* The real driver initialization function */ -+extern int devmtab_init (void) -+{ -+ printk (KERN_INFO "devmtab: driver %s loaded\n", DEVMTAB_VERSION); -+ -+ if (misc_register (&devmtab_misc_dev)) { -+ printk ("devmtab: can't register misc device %d\n", -+ DEVMTAB_MINOR); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+#ifdef MODULE -+ -+MODULE_AUTHOR ("Erik Andersen "); -+MODULE_DESCRIPTION -+ ("devmtab driver -- exports filesystem and mount information to user space"); -+ -+/* Stub driver initialization function */ -+int init_module (void) -+{ -+ return (devmtab_init ()); -+} -+ -+void cleanup_module (void) -+{ -+ printk (KERN_INFO "devmtab: driver unloaded\n"); -+ misc_deregister (&devmtab_misc_dev); -+} -+ -+#endif /* MODULE */ -diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/devps.c linux/drivers/char/devps.c ---- linux-2.2.18-9.virgin/drivers/char/devps.c Wed Dec 31 17:00:00 1969 -+++ linux/drivers/char/devps.c Mon Sep 25 17:00:57 2000 -@@ -0,0 +1,518 @@ -+/* vi: set sw=8 ts=8: */ -+/* -+ * linux/drivers/char/devps.c -+ * -+ * Copyright (C) 2000 Erik Andersen -+ * -+ * May be copied or modified under the terms of the GNU General Public License. -+ * See linux/COPYING for more information. -+ * -+ * This driver implements an interface whereby programs such as ps(1), top(1), -+ * killall(1) and the like may obtain all the process information they need to -+ * do their jobs. Now you may ask, "Why not use /proc? BSD uses /proc.". -+ * Thanks for asking. /proc is designed as a virtual filesystem. As such it -+ * presents all of its information in a nice, human readable format. But not -+ * human readable enough that mere mortals can actually look at the /proc -+ * information and know what is happening on their computer (which is why we -+ * have nice programs like ps(1) to help us out. Additionally, for ps (using -+ * /proc) to do its job, it has to do something like: -+ * -+ * dir = opendir("/proc"); -+ * while ((entry = readdir(dir)) != NULL) { -+ * if (!isdigit(*entry->d_name)) -+ * continue; -+ * open_lots_of files(); -+ * parse_lots_of_strings(); -+ * close_lots_of_files(); -+ * print_stuff(); -+ * } -+ * -+ * -+ * This is bad, because: -+ * -+ * 1) opening and closing lots of files is slow, -+ * -+ * 2) parsing lots of strings is slow, -+ * -+ * 3) every one of those strings had to be carefully printed out and formatted -+ * by the kernel, which is slow, -+ * -+ * 4) using a virtual filesystem is not the traditional UN*X solution to -+ * getting information from the kernel out to userspace (ioctls and syscalls -+ * are the established way to do this), and worst of all -+ * -+ * 5) having a virtual filesystem around has been so inviting that everyone has -+ * put their own weird little files into it, causing /proc to become a -+ * cluttered rubbish heap of 64 flavors of strange that takes a ridiculous -+ * amount of memory. -+ * -+ * This driver is the first step in my evil plan to completely -+ * dismantle /proc. Muhahahaha! -+ * -+ * Suggestions are welcome. Patches that work are more welcome though. ;-) -+ * -+ * When using this driver, running: -+ * mknod /dev/ps c 10 21 -+ * could be considered helpful. -+ * -+ * ---------------------------------- -+ * 1.00 Mar 07, 2000 -- Initial version. -+ * -+ * -+ * TODO -+ * ---------------------------------- -+ * -+ * * Right now none of the vm or fd info is being returned to user space. -+ * * There is probably other stuff that should be exported to user space. -+ * -+ * -+ *************************************************************************/ -+ -+#define DEVPS_VERSION "1.00" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* Some variables used by this device */ -+static struct wait_queue *devps_waitq = NULL; -+static int devps_already_opened = 0; -+ -+/**************************************************************************** -+ * Handle opening and closing of the device -+ */ -+ -+static int devps_open (struct inode *ip, struct file *fp) -+{ -+ /* Only let one process use us at any time -- putting other -+ * processes to sleep. Those opening us O_NONBLOCK will -+ * get an EAGAIN error */ -+ if ((fp->f_flags & O_NONBLOCK) && devps_already_opened) -+ return -EAGAIN; -+ -+ MOD_INC_USE_COUNT; -+ -+ while (devps_already_opened) { -+ int i, got_signal=0; -+ -+ /* Go to sleep until we get woken up -+ * by devps_close or we receive a signal */ -+ module_interruptible_sleep_on(&devps_waitq); -+ -+ for(i=0; i<_NSIG_WORDS && !got_signal; i++) -+ got_signal = current->signal.sig[i] & ~current->blocked.sig[i]; -+ -+ /* If we got a signal, decrement the use count -+ * and return to user space */ -+ if (got_signal) { -+ MOD_DEC_USE_COUNT; -+ return -EINTR; -+ } -+ } -+ -+ /* Since we got here, then device_already_opened must equal 0 */ -+ devps_already_opened=1; -+ return 0; -+} -+ -+static int devps_release (struct inode *ip, struct file *fp) -+{ -+ /* Zero out the reference counter */ -+ devps_already_opened=0; -+ -+ /* Wake up anybody that is waiting to access this device */ -+ module_wake_up(&devps_waitq); -+ -+ MOD_DEC_USE_COUNT; -+ return 0; -+} -+ -+ -+/* -+ * This pretty-prints the pathname of a dentry, -+ * clarifying sockets etc. -+ */ -+static int -+get_name_from_dentry (struct dentry *dentry, char *buffer, int buflen) -+{ -+ struct inode *inode; -+ char *tmp = (char *) __get_free_page (GFP_KERNEL), *path, *pattern; -+ int len; -+ -+ if (tmp == NULL) -+ return -ENOMEM; -+ -+ /* Check for special dentries.. */ -+ pattern = NULL; -+ inode = dentry->d_inode; -+ if (inode && dentry->d_parent == dentry) { -+ if (S_ISSOCK (inode->i_mode)) -+ pattern = "socket:[%lu]"; -+ if (S_ISFIFO (inode->i_mode)) -+ pattern = "pipe:[%lu]"; -+ } -+ -+ if (pattern) { -+ len = sprintf (tmp, pattern, inode->i_ino); -+ path = tmp; -+ } else { -+ path = d_path (dentry, tmp, PAGE_SIZE); -+ len = tmp + PAGE_SIZE - 1 - path; -+ } -+ -+ if (len < buflen) -+ buflen = len; -+ dput (dentry); -+ strncpy (buffer, path, buflen); -+ free_page ((unsigned long) tmp); -+ return buflen; -+} -+ -+static unsigned long get_phys_addr (struct task_struct *p, -+ unsigned long ptr) -+{ -+ pgd_t *page_dir; -+ pmd_t *page_middle; -+ pte_t pte; -+ -+ if (!p || !p->mm || ptr >= TASK_SIZE) -+ return 0; -+ /* Check for NULL pgd .. shouldn't happen! */ -+ if (!p->mm->pgd) { -+ printk ("get_phys_addr: pid %d has NULL pgd!\n", p->pid); -+ return 0; -+ } -+ -+ page_dir = pgd_offset (p->mm, ptr); -+ if (pgd_none (*page_dir)) -+ return 0; -+ if (pgd_bad (*page_dir)) { -+ printk ("bad page directory entry %08lx\n", -+ pgd_val (*page_dir)); -+ pgd_clear (page_dir); -+ return 0; -+ } -+ page_middle = pmd_offset (page_dir, ptr); -+ if (pmd_none (*page_middle)) -+ return 0; -+ if (pmd_bad (*page_middle)) { -+ printk ("bad page middle entry %08lx\n", -+ pmd_val (*page_middle)); -+ pmd_clear (page_middle); -+ return 0; -+ } -+ pte = *pte_offset (page_middle, ptr); -+ if (!pte_present (pte)) -+ return 0; -+ return pte_page (pte) + (ptr & ~PAGE_MASK); -+} -+ -+static int get_array (struct task_struct *p, unsigned long start, -+ unsigned long end, char *buffer) -+{ -+ unsigned long addr; -+ int size = 0, result = 0; -+ char c; -+ -+ if (start >= end) -+ return result; -+ for (;;) { -+ addr = get_phys_addr (p, start); -+ if (!addr) -+ return result; -+ do { -+ c = *(char *) addr; -+ if (!c) -+ result = size; -+ if (size < PAGE_SIZE) -+ buffer[size++] = c; -+ else -+ return result; -+ addr++; -+ start++; -+ if (!c && start >= end) -+ return result; -+ } while (addr & ~PAGE_MASK); -+ } -+ return result; -+} -+ -+static int -+devps_ioctl (struct inode *ip, struct file *fp, -+ unsigned int cmd, unsigned long arg) -+{ -+ switch (cmd) { -+ -+ /* Count up the total number of processes, -+ * and then return that total */ -+ case DEVPS_GET_NUM_PIDS:{ -+ struct task_struct *p; -+ pid_t num_pids = 0; -+ -+ read_lock (&tasklist_lock); -+ for_each_task (p) { -+ if (!p->pid) -+ continue; -+ num_pids++; -+ } -+ read_unlock (&tasklist_lock); -+ -+ copy_to_user_ret ((pid_t *) arg, &num_pids, -+ sizeof (num_pids), -EFAULT); -+ return 0; -+ } -+ -+ /* Returns an array containing all current pids, where -+ pidlist[0]=number of PIDs in the array. pidlist[0] also -+ specifies the size of the array for the kernel to -+ fill... */ -+ case DEVPS_GET_PID_LIST:{ -+ struct task_struct *p; -+ pid_t *pid_array = NULL; -+ pid_t num_pids; -+ int stat; -+ -+ /* Grab the first element to see how many * entries -+ they want us to fill */ -+ stat = verify_area (VERIFY_READ, (char *) arg, -+ sizeof (pid_t)); -+ if (stat) { -+ printk (KERN_INFO -+ "devps: can't tell how many " -+ "to pid's to write.\n"); -+ return stat; -+ } -+ -+ copy_from_user (&num_pids, (void *) arg, -+ sizeof (num_pids)); -+ -+ /* Now make sure we can write the specified amount -+ of stuff into the array. If we can't we might -+ as well quit now and save ourselves the bother. */ -+ stat = verify_area (VERIFY_WRITE, (char *) arg, -+ sizeof (pid_t) * num_pids); -+ if (stat) { -+ printk (KERN_INFO -+ "devps: Insufficient space was " -+ "provided to write %d pid's.\n", -+ num_pids); -+ return stat; -+ } -+ -+ /* Allocate some memory to hold this stuff in before -+ * we copy it out to user-space */ -+ pid_array = (pid_t *) kmalloc (num_pids * -+ sizeof (pid_t), -+ GFP_KERNEL); -+ if (pid_array == NULL) -+ return -ENOMEM; -+ -+ /* Now march through the PID list */ -+ pid_array[0] = 0; -+ read_lock (&tasklist_lock); -+ for_each_task (p) { -+ if (!p->pid) -+ continue; -+ (pid_array[0])++; -+ if (pid_array[0] >= (num_pids - 1)) -+ continue; -+ pid_array[pid_array[0]] = p->pid; -+ } -+ read_unlock (&tasklist_lock); -+ -+ /* Copy out to the user the number we actually filled -+ */ -+ copy_to_user_ret ((void *) arg, pid_array, -+ sizeof (pid_t) * pid_array[0], -+ -EFAULT); -+ kfree (pid_array); -+ -+ return 0; -+ } -+ -+ /* Find the details on a particular pid, and fill out a -+ struct with all the gory details. */ -+ case DEVPS_GET_PID_INFO:{ -+ struct task_struct *p; -+ struct pid_info mypidinfo; -+ unsigned int state; -+ /* 'R' running */ -+ /* 'S' sleeping */ -+ /* 'D' disk sleep */ -+ /* 'Z' zombie */ -+ /* 'T' stopped */ -+ /* 'W' paging */ -+ const char *state_string = "RSDZTW"; -+ -+ copy_from_user_ret (&mypidinfo, -+ (struct pid_info *) arg, -+ sizeof (mypidinfo), -EFAULT); -+ -+ read_lock (&tasklist_lock); -+ p = find_task_by_pid (mypidinfo.pid); -+ read_unlock (&tasklist_lock); -+ -+ /* Now copy all this crap so we can tell user space -+ all about it. ick. */ -+ memset (mypidinfo.name, 0, -+ sizeof (mypidinfo.name)); -+ strcpy (mypidinfo.name, p->comm); -+ mypidinfo.flags = p->flags; -+ mypidinfo.pgrp = p->pgrp; -+ mypidinfo.tms_cutime = p->times.tms_cutime; -+ mypidinfo.tms_cstime = p->times.tms_cstime; -+ mypidinfo.tms_utime = p->times.tms_utime; -+ mypidinfo.tms_stime = p->times.tms_stime; -+ mypidinfo.min_flt = p->min_flt; -+ mypidinfo.cmin_flt = p->cmin_flt; -+ mypidinfo.maj_flt = p->maj_flt; -+ mypidinfo.cmaj_flt = p->cmaj_flt; -+ mypidinfo.session = p->session; -+ mypidinfo.pid = p->pid; -+ mypidinfo.ppid = p->p_pptr->pid; -+ mypidinfo.tty = -+ p->tty ? kdev_t_to_nr (p->tty->device) : 0; -+ mypidinfo.start_time = p->start_time; -+ mypidinfo.uid = p->uid; -+ mypidinfo.euid = p->euid; -+ mypidinfo.suid = p->suid; -+ mypidinfo.fsuid = p->fsuid; -+ mypidinfo.gid = p->gid; -+ mypidinfo.egid = p->egid; -+ mypidinfo.sgid = p->sgid; -+ mypidinfo.fsgid = p->fsgid; -+ mypidinfo.priority = 20 - (p->counter * 10 + -+ DEF_PRIORITY / 2) / DEF_PRIORITY; -+ mypidinfo.nice = 20 - (mypidinfo.priority * 20 + -+ DEF_PRIORITY / 2) / DEF_PRIORITY; -+ state = p-> state & (TASK_RUNNING | TASK_INTERRUPTIBLE -+ | TASK_UNINTERRUPTIBLE | -+ TASK_ZOMBIE | TASK_STOPPED | -+ TASK_SWAPPING); -+ while (state) { -+ state_string++; -+ state >>= 1; -+ } -+ mypidinfo.state = *state_string; -+ mypidinfo.processor = p->processor; -+ mypidinfo.nswap = p->nswap; -+ mypidinfo.cnswap = p->cnswap; -+ if (p && p->mm) { -+ char *page = NULL; -+ -+ /* Look for some elbow room */ -+ if (!(page = (char*)get_free_page (GFP_KERNEL))) -+ return -ENOMEM; -+ /* Grab the command line */ -+ get_array (p, p->mm->arg_start, -+ p->mm->arg_end, page); -+ memcpy( mypidinfo.command_line, page, sizeof( mypidinfo.command_line)); -+ mypidinfo.command_line[sizeof( mypidinfo.command_line)-1]='\0'; -+ -+ /* Grab the environment */ -+ memset (page, 0, PAGE_SIZE); -+ get_array (p, p->mm->env_start, -+ p->mm->env_end, page); -+ memcpy( mypidinfo.environment, page, sizeof( mypidinfo.environment)); -+ mypidinfo.command_line[sizeof( mypidinfo.environment)-1]='\0'; -+ free_page ((unsigned long) page); -+ } -+ memset (mypidinfo.cwd, 0, sizeof (mypidinfo.cwd)); -+ get_name_from_dentry (dget (p->fs->pwd), mypidinfo.cwd, -+ sizeof (mypidinfo.cwd)); -+ memset (mypidinfo.root, 0, sizeof (mypidinfo.root)); -+ get_name_from_dentry (dget (p->fs->root), -+ mypidinfo.root, -+ sizeof (mypidinfo.root)); -+ -+ copy_to_user_ret ((struct pid_info *) arg, -+ &mypidinfo, sizeof (mypidinfo), -+ -EFAULT); -+ -+ return 0; -+ } -+ -+ /* Return the PID of the current process */ -+ case DEVPS_GET_CURRENT_PID:{ -+ return current->pid; -+ } -+ -+ default: -+ return -EINVAL; -+ -+ } -+ return 0; -+} -+ -+ -+ -+/**************************************************************************** -+ * Set up the file operations devps will support -+ */ -+static struct file_operations devps_fops = { -+ NULL, /* No lseek */ -+ NULL, /* No read */ -+ NULL, /* No write */ -+ NULL, /* No readdir */ -+ NULL, /* No poll */ -+ devps_ioctl, -+ NULL, /* No mmap */ -+ devps_open, -+ NULL, /* flush */ -+ devps_release, -+ NULL, /* fsync */ -+ NULL, /* fasync */ -+ NULL, /* check_media_change */ -+ NULL /* revalidate */ -+}; -+ -+static struct miscdevice devps_misc_dev = { -+ DEVPS_MINOR, -+ "devps", -+ &devps_fops -+}; -+ -+/* The real driver initialization function */ -+extern int devps_init (void) -+{ -+ printk (KERN_INFO "devps driver %s loaded\n", DEVPS_VERSION); -+ -+ if (misc_register (&devps_misc_dev)) { -+ printk ("devps: unable to get misc device %d\n", -+ DEVPS_MINOR); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+#ifdef MODULE -+ -+MODULE_AUTHOR ("Erik Andersen "); -+MODULE_DESCRIPTION -+ ("devps driver -- exports kernel process information to user space"); -+ -+ -+/* Stub driver initialization function */ -+int init_module (void) -+{ -+ return (devps_init ()); -+} -+ -+void cleanup_module (void) -+{ -+ printk (KERN_INFO "devps driver unloaded\n"); -+ misc_deregister (&devps_misc_dev); -+} -+ -+#endif /* endif MODULE */ -diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/makedevps.sh linux/drivers/char/makedevps.sh ---- linux-2.2.18-9.virgin/drivers/char/makedevps.sh Wed Dec 31 17:00:00 1969 -+++ linux/drivers/char/makedevps.sh Mon Sep 25 17:00:57 2000 -@@ -0,0 +1,5 @@ -+#!/bin/sh -x -+ -+gcc -Wall -g -I /usr/src/linux/include ps-devps.c -o ps-devps -+gcc -Wall -g -I /usr/src/linux/include mounts.c -o mounts -+ -diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/misc.c linux/drivers/char/misc.c ---- linux-2.2.18-9.virgin/drivers/char/misc.c Mon Sep 18 15:02:31 2000 -+++ linux/drivers/char/misc.c Mon Sep 25 17:00:57 2000 -@@ -85,6 +85,8 @@ - extern int pmu_device_init(void); - extern int tosh_init(void); - extern int rng_init(void); -+extern int devps_init(void); -+extern int devmtab_init(void); - - static int misc_read_proc(char *buf, char **start, off_t offset, - int len, int *eof, void *private) -@@ -268,6 +270,12 @@ - #endif - #ifdef CONFIG_PMAC_PBOOK - pmu_device_init(); -+#endif -+#ifdef CONFIG_DEVPS -+ devps_init(); -+#endif -+#ifdef CONFIG_DEVMTAB -+ devmtab_init(); - #endif - #ifdef CONFIG_SGI_NEWPORT_GFX - gfx_register (); -diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/mounts.c linux/drivers/char/mounts.c ---- linux-2.2.18-9.virgin/drivers/char/mounts.c Wed Dec 31 17:00:00 1969 -+++ linux/drivers/char/mounts.c Mon Sep 25 17:00:57 2000 -@@ -0,0 +1,116 @@ -+/* vi: set sw=4 ts=4: */ -+/* -+ * devmtab tester -+ * -+ * -+ * Copyright (C) 2000 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 -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+int main (int argc, char **argv) -+{ -+ char device[80] = "/dev/mtab"; -+ int fd; /* file descriptor for devmtab device */ -+ int i, numfilesystems; -+ struct k_fstype *fslist; -+ struct k_mntent *mntentlist; -+ -+ if (argc > 1 && **(argv + 1) == '-') { -+ fprintf(stderr, "Usage: mounts\n\nReport mounted stuff\n\nThis version of mounts accepts no options.\n\n"); -+ exit(1); -+ } -+ -+ /* open device */ -+ if ((fd = open(device, O_RDONLY)) < 0) { -+ fprintf (stderr, "open failed for `%s': %s\n", -+ device, strerror (errno)); -+ exit (1); -+ } -+ -+ /* How many filesystems? We need to know to allocate -+ * enough space for later... */ -+ numfilesystems = ioctl (fd, DEVMTAB_COUNT_FILESYSTEMS); -+ if (numfilesystems<0) { -+ fprintf (stderr, "\nDEVMTAB_COUNT_FILESYSTEMS: %s\n", -+ strerror (errno)); -+ exit (1); -+ } -+ fslist = (struct k_fstype *) calloc ( numfilesystems, sizeof(struct k_fstype)); -+ -+ /* Grab the list of available filesystems */ -+ if (ioctl (fd, DEVMTAB_GET_FILESYSTEMS, fslist)<0) { -+ fprintf (stderr, "\nDEVMTAB_GET_FILESYSTEMS: %s\n", -+ strerror (errno)); -+ exit (1); -+ } -+ fprintf( stdout, "\nEquivalent of /proc/filesystems:\n"); -+ for( i = 0 ; i < numfilesystems ; i++) { -+ fprintf( stdout, "%s%s\n", fslist[i].mnt_type, -+ (fslist[i].mnt_nodev)? " nodev" : ""); -+ } -+ -+ -+ /* How many mounted filesystems? We need to know to -+ * allocate enough space for later... */ -+ numfilesystems = ioctl (fd, DEVMTAB_COUNT_MOUNTS); -+ if (numfilesystems<0) { -+ fprintf (stderr, "\nDEVMTAB_COUNT_MOUNTS: %s\n", -+ strerror (errno)); -+ exit (1); -+ } -+ mntentlist = (struct k_mntent *) calloc ( numfilesystems, sizeof(struct k_mntent)); -+ -+ /* Grab the list of mounted filesystems */ -+ if (ioctl (fd, DEVMTAB_GET_MOUNTS, mntentlist)<0) { -+ fprintf (stderr, "\nDEVMTAB_GET_MOUNTS: %s\n", -+ strerror (errno)); -+ exit (1); -+ } -+ -+ fprintf( stdout, "\nEquivalent of /proc/mounts:\n"); -+ for( i = 0 ; i < numfilesystems ; i++) { -+ fprintf( stdout, "%s %s %s %s %d %d\n", mntentlist[i].mnt_fsname, -+ mntentlist[i].mnt_dir, mntentlist[i].mnt_type, -+ mntentlist[i].mnt_opts, mntentlist[i].mnt_freq, -+ mntentlist[i].mnt_passno); -+ } -+ -+ -+ /* clean up */ -+ free( fslist); -+ free( mntentlist); -+ if (close (fd) != 0) { -+ fprintf (stderr, "close failed for `%s': %s\n", -+ device, strerror (errno)); -+ exit (1); -+ } -+ -+ exit (0); -+} -+ -diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/ps-devps.c linux/drivers/char/ps-devps.c ---- linux-2.2.18-9.virgin/drivers/char/ps-devps.c Wed Dec 31 17:00:00 1969 -+++ linux/drivers/char/ps-devps.c Mon Sep 25 17:32:19 2000 -@@ -0,0 +1,148 @@ -+/* vi: set sw=4 ts=4: */ -+/* -+ * Mini ps implementation for use with the Linux devps driver -+ * -+ * -+ * Copyright (C) 2000 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 -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+#define MAX_COLUMN 79 -+ -+int -+main (int argc, char **argv) -+{ -+ char device[80] = "/dev/ps"; -+ int i, j, len; -+ int fd; /* file descriptor for devps device */ -+ int status; /* return status for system calls */ -+ pid_t num_pids; -+ pid_t* pid_array = NULL; -+ struct pid_info info; -+ struct passwd *pwd; -+ struct group *grp; -+ char uidName[10] = ""; -+ char groupName[10] = ""; -+ -+ if (argc > 1 && **(argv + 1) == '-') { -+ fprintf(stderr, "Usage: ps-devps\n\nReport process status\n\nThis version of ps accepts no options.\n\n"); -+ exit(1); -+ } -+ -+ /* open device */ -+ //fd = open(device, O_RDWR); -+ fd = open(device, O_RDONLY); -+ if (fd < 0) { -+ fprintf (stderr, "open failed for `%s': %s\n", -+ device, strerror (errno)); -+ goto error; -+ } -+ -+ /* Find out how many processes there are */ -+ status = ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids); -+ if (status<0) { -+ fprintf (stderr, "\nDEVPS_GET_PID_LIST: %s\n", -+ strerror (errno)); -+ goto error; -+ } -+ -+ /* Allocate some memory -- grab a few extras just in case -+ * some new processes start up while we wait. The kernel will -+ * just ignore any extras if we give it too many, and will trunc. -+ * the list if we give it too few. */ -+ pid_array = (pid_t*) calloc( num_pids+10, sizeof(pid_t)); -+ pid_array[0] = num_pids+10; -+ -+ /* Now grab the pid list */ -+ status = ioctl (fd, DEVPS_GET_PID_LIST, pid_array); -+ if (status<0) { -+ fprintf (stderr, "\nDEVPS_GET_PID_LIST: %s\n", -+ strerror (errno)); -+ goto error; -+ } -+ -+ /* Print up a ps listing */ -+ fprintf(stdout, "%5s %-8s %-3s %5s %s\n", "PID", "Uid", "Gid", -+ "State", "Command"); -+ -+ for (i=1; ipw_name); -+ grp = getgrgid(info.egid); -+ if (grp == NULL) -+ sprintf(groupName, "%lu", info.egid); -+ else -+ sprintf(groupName, "%s", grp->gr_name); -+ -+ len = fprintf(stdout, "%5d %-8s %-8s %c ", info.pid, uidName, groupName, info.state); -+ -+ if (strlen(info.command_line) > 1) { -+ for( j=0; j<(sizeof(info.command_line)-1) && j < (MAX_COLUMN-len); j++) { -+ if (*(info.command_line+j) == '\0' && *(info.command_line+j+1) != '\0') { -+ *(info.command_line+j) = ' '; -+ } -+ } -+ *(info.command_line+j) = '\0'; -+ fprintf(stdout, "%s\n", info.command_line); -+ } else { -+ fprintf(stdout, "[%s]\n", info.name); -+ } -+ } -+ -+ /* Free memory */ -+ free( pid_array); -+ -+ /* close device */ -+ status = close (fd); -+ if (status != 0) { -+ fprintf (stderr, "close failed for `%s': %s\n", -+ device, strerror (errno)); -+ goto error; -+ } -+ -+ exit (0); -+error: -+ fflush(stdout); -+ fflush(stderr); -+ exit (1); -+} -+ -diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/fs/Makefile linux/fs/Makefile ---- linux-2.2.18-9.virgin/fs/Makefile Wed Aug 25 18:29:49 1999 -+++ linux/fs/Makefile Mon Sep 25 16:33:16 2000 -@@ -11,9 +11,10 @@ - L_OBJS = $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o)) - O_TARGET := fs.o - O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \ -- super.o block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ -+ block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ - ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \ - dcache.o inode.o attr.o bad_inode.o file.o $(BINFMTS) -+OX_OBJS = super.o - - MOD_LIST_NAME := FS_MODULES - ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \ -diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/fs/super.c linux/fs/super.c ---- linux-2.2.18-9.virgin/fs/super.c Mon Sep 18 15:02:34 2000 -+++ linux/fs/super.c Mon Sep 25 17:00:57 2000 -@@ -18,6 +18,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -25,6 +26,7 @@ - #include - #include - #include -+#include - - #include - -@@ -311,7 +313,57 @@ - { 0, NULL } - }; - --int get_filesystem_info( char *buf ) -+ -+extern int count_mounted_filesystems() -+{ -+ struct vfsmount *tmp = vfsmntlist; -+ int count = 0; -+ -+ while (tmp) -+ { -+ tmp = tmp->mnt_next; -+ count++; -+ } -+ -+ return count; -+} -+EXPORT_SYMBOL(count_mounted_filesystems); -+ -+ -+extern void get_mtab_entries( int count, struct k_mntent* mntentlist) -+{ -+ struct vfsmount *tmp = vfsmntlist; -+ struct proc_fs_info *fs_infop; -+ int i = 0, len; -+ -+ while (tmp && i < count) -+ { -+ strncpy(mntentlist[i].mnt_fsname, tmp->mnt_devname, -+ sizeof(mntentlist[i].mnt_fsname)); -+ strncpy(mntentlist[i].mnt_dir, tmp->mnt_dirname, -+ sizeof(mntentlist[i].mnt_dir)); -+ strncpy(mntentlist[i].mnt_type, tmp->mnt_sb->s_type->name, -+ sizeof(mntentlist[i].mnt_type)); -+ len = 0; -+ len+=sprintf(mntentlist[i].mnt_opts, "%s", -+ tmp->mnt_flags & MS_RDONLY ? "ro" : "rw"); -+ for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { -+ if (tmp->mnt_flags & fs_infop->flag) { -+ strncpy(mntentlist[i].mnt_opts+len, fs_infop->str, -+ sizeof(mntentlist[i].mnt_opts)-len); -+ len += strlen(fs_infop->str); -+ } -+ } -+ -+ /* TODO -- add in NFS stuff */ -+ -+ tmp = tmp->mnt_next; -+ i++; -+ } -+} -+EXPORT_SYMBOL(get_mtab_entries); -+ -+extern int get_filesystem_info( char *buf ) - { - struct vfsmount *tmp = vfsmntlist; - struct proc_fs_info *fs_infop; -@@ -383,8 +435,37 @@ - - return len; - } -+EXPORT_SYMBOL(get_filesystem_info); -+ -+extern int count_kfstypes() -+{ -+ struct file_system_type * tmp = file_systems; -+ int count = 0; -+ -+ while (tmp) { -+ count++; -+ tmp = tmp->next; -+ } -+ -+ return count; -+} -+EXPORT_SYMBOL(count_kfstypes); -+ -+extern void get_kfstype_list(int count, struct k_fstype* fstypelist) -+{ -+ int i = 0; -+ struct file_system_type * tmp = file_systems; -+ -+ while (tmp && i < count) { -+ strncpy(fstypelist[i].mnt_type, tmp->name, sizeof(fstypelist[i].mnt_type)); -+ fstypelist[i].mnt_nodev = (tmp->fs_flags & FS_REQUIRES_DEV)? 0 : 1; -+ tmp = tmp->next; -+ i++; -+ } -+} -+EXPORT_SYMBOL(get_kfstype_list); - --int get_filesystem_list(char * buf) -+extern int get_filesystem_list(char * buf) - { - int len = 0; - struct file_system_type * tmp; -@@ -398,6 +479,7 @@ - } - return len; - } -+EXPORT_SYMBOL(get_filesystem_list); - - struct file_system_type *get_fs_type(const char *name) - { -diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/devmtab.h linux/include/linux/devmtab.h ---- linux-2.2.18-9.virgin/include/linux/devmtab.h Wed Dec 31 17:00:00 1969 -+++ linux/include/linux/devmtab.h Mon Sep 25 17:00:57 2000 -@@ -0,0 +1,55 @@ -+/* vi: set sw=8 ts=8: */ -+/* -+ * -- -+ * -+ * Copyright (C) 2000 Erik Andersen -+ * -+ * May be copied or modified under the terms of the GNU General Public License. -+ * See linux/COPYING for more information. -+ * -+ * This driver implements an interface whereby programs such as mount(8), -+ * umount(8), and df(1) may obtain all the process information they need to do -+ * their jobs without needing to use /proc. -+ * -+ */ -+ -+#ifndef _LINUX_DEVMTAB_H -+#define _LINUX_DEVMTAB_H -+ -+ -+/******************************************************* -+ * The list of all ioctl(2) commands suported by devmtab. -+ * For the devmtab ioctls, I have commandeered some of the -+ * higher bits of byte 0xeb. -+ *******************************************************/ -+#define DEVMTAB_COUNT_FILESYSTEMS 0xebaa /* Get a list of all fs */ -+#define DEVMTAB_GET_FILESYSTEMS 0xebab /* Get a list of all fs */ -+#define DEVMTAB_COUNT_MOUNTS 0xebac /* Returns number of mounted filesystems */ -+#define DEVMTAB_GET_MOUNTS 0xebad /* Get a list of a mounted fs */ -+#define DEVMTAB_SET_ROOTFS_DEVNAME 0xebae /* Replace /dev/root with real name */ -+ -+/******************************************************* -+ * devmtab ioctl(2) structures -+ *******************************************************/ -+ -+/* An array of these is returned by the DEVMTAB_GET_FILESYSTEMS ioctl. -+ */ -+struct k_fstype { -+ char mnt_type[255]; /* filesystem type: ext2, nfs, etc. */ -+ int mnt_nodev; /* Is this a device-less filesystem? */ -+}; -+ -+/* An array of these is returned by the DEVMTAB_GET_MOUNTS ioctl. -+ * This struct should be the same as what libc returns via the -+ * getmntent(3) function (excat this comes from the kernel, not -+ * from whatever noise is in /etc/mtab at the moment... */ -+struct k_mntent { -+ char mnt_fsname[255]; /* name of mounted file system */ -+ char mnt_dir[255]; /* path of file system mount point */ -+ char mnt_type[255]; /* filesystem type: ext2, nfs, etc. */ -+ char mnt_opts[255]; /* Comma-separated list of mount options */ -+ int mnt_freq; /* dump frequency in days */ -+ int mnt_passno; /* pass number for parallel fsck */ -+}; -+ -+#endif /* _LINUX_DEVMTAB_H */ -diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/devps.h linux/include/linux/devps.h ---- linux-2.2.18-9.virgin/include/linux/devps.h Wed Dec 31 17:00:00 1969 -+++ linux/include/linux/devps.h Mon Sep 25 17:00:57 2000 -@@ -0,0 +1,78 @@ -+/* -+ * -- -+ * -+ * Copyright (C) 2000 Erik Andersen -+ * -+ * May be copied or modified under the terms of the GNU General Public License. -+ * See linux/COPYING for more information. -+ * -+ * This driver implements an interface whereby programs such as ps(1), top(1), -+ * killall(1) and the like may obtain all the process information they need to -+ * do their jobs. -+ * -+ */ -+ -+#ifndef _LINUX_DEVPS_H -+#define _LINUX_DEVPS_H -+ -+ -+/******************************************************* -+ * The list of all ioctl(2) commands suported by devps. -+ * For the devps ioctls, I have commandeered some of the -+ * higher bits of byte 0xeb. -+ *******************************************************/ -+#define DEVPS_GET_NUM_PIDS 0xeba1 /* Get a list of all PIDs */ -+#define DEVPS_GET_PID_LIST 0xeba2 /* Get a list of all PIDs */ -+#define DEVPS_GET_PID_INFO 0xeba3 /* Get info about a specific PID */ -+#define DEVPS_GET_CURRENT_PID 0xeba4 /* Get the current PID */ -+ -+/******************************************************* -+ * devps ioctl(2) structures -+ *******************************************************/ -+ -+ -+struct pid_info -+{ -+ char name[16]; -+ long flags; -+ pid_t pgrp; -+ clock_t tms_cutime; -+ clock_t tms_cstime; -+ clock_t tms_utime; -+ clock_t tms_stime; -+ unsigned long min_flt; -+ unsigned long cmin_flt; -+ unsigned long maj_flt; -+ unsigned long cmaj_flt; -+ pid_t session; -+ pid_t pid; -+ pid_t ppid; -+ int tty; -+ unsigned long start_time; -+ unsigned long uid,euid,suid,fsuid; -+ unsigned long gid,egid,sgid,fsgid; -+ long priority, nice; -+ char state; -+ int processor; -+ unsigned long nswap, cnswap; -+ char command_line[256]; -+ char environment[256]; -+ char root[256]; -+ char cwd[256]; -+#if 0 -+ /* TODO: Add in this (and probably more) stuff */ -+ -+ int resident; -+ int size; -+ int share; -+ unsigned long vsize; -+ char exe[MAX_PATH]; -+ unsigned long vm_total, vm_locked, vm_rss, vm_data, vm_stack, vm_exec, vm_lib; -+ unsigned long start_code, end_code, start_data, eip, esp; -+ unsigned long signal, blocked; -+#endif -+ -+ -+}; -+ -+#endif /* _LINUX_DEVPS_H */ -diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/fs.h linux/include/linux/fs.h ---- linux-2.2.18-9.virgin/include/linux/fs.h Mon Sep 18 15:08:47 2000 -+++ linux/include/linux/fs.h Mon Sep 25 17:37:50 2000 -@@ -573,6 +573,16 @@ - struct semaphore s_vfs_rename_sem; /* Kludge */ - }; - -+/* fs/super.c */ -+#include -+ -+extern int count_kfstypes( void); -+extern void get_kfstype_list( int count, struct k_fstype* fstypelist); -+extern int count_mounted_filesystems( void); -+extern int get_filesystem_info(char *buf); -+extern int get_filesystem_list(char *buf); -+extern void get_mtab_entries( int count, struct k_mntent* mntentlist); -+ - /* - * VFS helper functions.. - */ -diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/miscdevice.h linux/include/linux/miscdevice.h ---- linux-2.2.18-9.virgin/include/linux/miscdevice.h Mon Aug 9 13:04:41 1999 -+++ linux/include/linux/miscdevice.h Mon Sep 25 16:33:17 2000 -@@ -11,6 +11,8 @@ - #define APOLLO_MOUSE_MINOR 7 - #define PC110PAD_MINOR 9 - #define MAC_MOUSE_MINOR 10 -+#define DEVPS_MINOR 21 -+#define DEVMTAB_MINOR 22 - #define WATCHDOG_MINOR 130 /* Watchdog timer */ - #define TEMP_MINOR 131 /* Temperature Sensor */ - #define RTC_MINOR 135 diff --git a/busybox/examples/mk2knr.pl b/busybox/examples/mk2knr.pl deleted file mode 100755 index aaf4963b1..000000000 --- a/busybox/examples/mk2knr.pl +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/perl -w -# -# @(#) mk2knr.pl - generates a perl script that converts lexemes to K&R-style -# -# How to use this script: -# - In the busybox directory type 'scripts/mk2knr.pl files-you-want-to-convert' -# - Review the 'convertme.pl' script generated and remove / edit any of the -# substitutions in there (please especially check for false positives) -# - Type './convertme.pl same-files-as-before' -# - Compile and see if it works -# -# BUGS: This script does not ignore strings inside comments or strings inside -# quotes (it probably should). - -# set this to something else if you want -$convertme = 'convertme.pl'; - -# internal-use variables (don't touch) -$convert = 0; -%converted = (); - -# if no files were specified, print usage -die "usage: $0 file.c | file.h\n" if scalar(@ARGV) == 0; - -# prepare the "convert me" file -open(CM, ">$convertme") or die "convertme.pl $!"; -print CM "#!/usr/bin/perl -p -i\n\n"; - -# process each file passed on the cmd line -while (<>) { - - # if the line says "getopt" in it anywhere, we don't want to muck with it - # because option lists tend to include strings like "cxtzvOf:" which get - # matched by the "check for mixed case" regexps below - next if /getopt/; - - # tokenize the string into just the variables - while (/([a-zA-Z_][a-zA-Z0-9_]*)/g) { - $var = $1; - - # ignore the word "BusyBox" - next if ($var =~ /BusyBox/); - - # this checks for javaStyle or szHungarianNotation - $convert++ if ($var =~ /^[a-z]+[A-Z][a-z]+/); - - # this checks for PascalStyle - $convert++ if ($var =~ /^[A-Z][a-z]+[A-Z][a-z]+/); - - # if we want to add more checks, we can add 'em here, but the above - # checks catch "just enough" and not too much, so prolly not. - - if ($convert) { - $convert = 0; - - # skip ahead if we've already dealt with this one - next if ($converted{$var}); - - # record that we've dealt with this var - $converted{$var} = 1; - - print CM "s/\\b$var\\b/"; # more to come in just a minute - - # change the first letter to lower-case - $var = lcfirst($var); - - # put underscores before all remaining upper-case letters - $var =~ s/([A-Z])/_$1/g; - - # now change the remaining characters to lower-case - $var = lc($var); - - print CM "$var/g;\n"; - } - } -} - -# tidy up and make the $convertme script executable -close(CM); -chmod 0755, $convertme; - -# print a helpful help message -print "Done. Scheduled name changes are in $convertme.\n"; -print "Please review/modify it and then type ./$convertme to do the search & replace.\n"; diff --git a/busybox/examples/undeb b/busybox/examples/undeb deleted file mode 100644 index a72e1e2ba..000000000 --- a/busybox/examples/undeb +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh -# -# This should work with the GNU version of tar and gzip! -# This should work with the bash or ash shell! -# Requires the programs (ar, tar, gzip, and the pager more or less). -# -usage() { -echo "Usage: undeb -c package.deb " -echo " undeb -l package.deb " -echo " undeb -x package.deb /foo/boo " -exit -} - -deb=$2 - -exist() { -if [ "$deb" = "" ]; then -usage -elif [ ! -s "$deb" ]; then -echo "Can't find $deb!" -exit -fi -} - -if [ "$1" = "" ]; then -usage -elif [ "$1" = "-l" ]; then -exist -type more >/dev/null 2>&1 && pager=more -type less >/dev/null 2>&1 && pager=less -[ "$pager" = "" ] && echo "No pager found!" && exit -(ar -p $deb control.tar.gz | tar -xzO *control ; echo -e "\nPress enter to scroll, q to Quit!\n" ; ar -p $deb data.tar.gz | tar -tzv) | $pager -exit -elif [ "$1" = "-c" ]; then -exist -ar -p $deb control.tar.gz | tar -xzO *control -exit -elif [ "$1" = "-x" ]; then -exist -if [ "$3" = "" ]; then -usage -elif [ ! -d "$3" ]; then -echo "No such directory $3!" -exit -fi -ar -p $deb data.tar.gz | tar -xzvpf - -C $3 || exit -echo -echo "Extracted $deb to $3!" -exit -else -usage -fi diff --git a/busybox/examples/unrpm b/busybox/examples/unrpm deleted file mode 100644 index 376286a6f..000000000 --- a/busybox/examples/unrpm +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh -# -# This should work with the GNU version of cpio and gzip! -# This should work with the bash or ash shell! -# Requires the programs (cpio, gzip, and the pager more or less). -# -usage() { -echo "Usage: unrpm -l package.rpm " -echo " unrpm -x package.rpm /foo/boo " -exit -} - -rpm=$2 - -exist() { -if [ "$rpm" = "" ]; then -usage -elif [ ! -s "$rpm" ]; then -echo "Can't find $rpm!" -exit -fi -} - -if [ "$1" = "" ]; then -usage -elif [ "$1" = "-l" ]; then -exist -type more >/dev/null 2>&1 && pager=more -type less >/dev/null 2>&1 && pager=less -[ "$pager" = "" ] && echo "No pager found!" && exit -(echo -e "\nPress enter to scroll, q to Quit!\n" ; rpm2cpio $rpm | cpio -tv --quiet) | $pager -exit -elif [ "$1" = "-x" ]; then -exist -if [ "$3" = "" ]; then -usage -elif [ ! -d "$3" ]; then -echo "No such directory $3!" -exit -fi -rpm2cpio $rpm | (umask 0 ; cd $3 ; cpio -idmuv) || exit -echo -echo "Extracted $rpm to $3!" -exit -else -usage -fi diff --git a/busybox/expr.c b/busybox/expr.c deleted file mode 100644 index d6cc82e3e..000000000 --- a/busybox/expr.c +++ /dev/null @@ -1,535 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini expr implementation for busybox - * - * based on GNU expr Mike Parker. - * Copyright (C) 86, 1991-1997, 1999 Free Software Foundation, Inc. - * - * Busybox modifications - * 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 - * - */ - -/* This program evaluates expressions. Each token (operator, operand, - * parenthesis) of the expression must be a seperate argument. The - * parser used is a reasonably general one, though any incarnation of - * it is language-specific. It is especially nice for expressions. - * - * No parse tree is needed; a new node is evaluated immediately. - * One function can handle multiple operators all of equal precedence, - * provided they all associate ((x op x) op x). */ - -/* no getopt needed */ - -#include -#include -#include -#include -#include -#include "busybox.h" - - -/* The kinds of value we can have. */ -enum valtype { - integer, - string -}; -typedef enum valtype TYPE; - -/* A value is.... */ -struct valinfo { - TYPE type; /* Which kind. */ - union { /* The value itself. */ - int 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) { - error_msg_and_die("too few arguments"); - } - - args = argv + 1; - - v = eval (); - if (*args) - error_msg_and_die ("syntax error"); - - if (v->type == integer) - printf ("%d\n", v->u.i); - else - puts (v->u.s); - - exit (null (v)); -} - -/* Return a VALUE for I. */ - -static VALUE *int_value (int i) -{ - VALUE *v; - - v = xmalloc (sizeof(VALUE)); - v->type = integer; - v->u.i = i; - return v; -} - -/* Return a VALUE for S. */ - -static VALUE *str_value (char *s) -{ - VALUE *v; - - v = xmalloc (sizeof(VALUE)); - v->type = string; - v->u.s = strdup (s); - return v; -} - -/* Free VALUE V, including structure components. */ - -static void freev (VALUE *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) -{ - 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 (); - } -} - -/* Coerce V to a string value (can't fail). */ - -static void tostring (VALUE *v) -{ - char *temp; - - if (v->type == integer) { - temp = xmalloc (4 * (sizeof (int) / sizeof (char))); - sprintf (temp, "%d", v->u.i); - v->u.s = temp; - v->type = string; - } -} - -/* Coerce V to an integer value. Return 1 on success, 0 on failure. */ - -static int 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 (); - } -} - -/* Return nonzero if the next token matches STR exactly. - STR must not be NULL. */ - -static int -nextarg (char *str) -{ - if (*args == NULL) - return 0; - return strcmp (*args, str) == 0; -} - -/* The comparison operator handling functions. */ - -#define cmpf(name, rel) \ -static int name (l, r) 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; \ -} - 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 (l, r) VALUE *l; VALUE *r; \ -{ \ - if (!toarith (l) || !toarith (r)) \ - error_msg_and_die ("non-numeric argument"); \ - return l->u.i op r->u.i; \ -} - -#define arithdivf(name, op) \ -static int name (l, r) VALUE *l; VALUE *r; \ -{ \ - if (!toarith (l) || !toarith (r)) \ - error_msg_and_die ( "non-numeric argument"); \ - if (r->u.i == 0) \ - error_msg_and_die ( "division by zero"); \ - return l->u.i op r->u.i; \ -} - - 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) -{ - VALUE *v; - const char *errmsg; - struct re_pattern_buffer re_buffer; - struct re_registers re_regs; - int len; - - 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); - } - - 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) { - error_msg_and_die("%s", errmsg); - } - - len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs); - if (len >= 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]); - } - else - v = int_value (len); - } - else { - /* Match failed -- return the right kind of null. */ - if (re_buffer.re_nsub > 0) - v = str_value (""); - else - v = int_value (0); - } - free (re_buffer.buffer); - return v; -} - -/* Handle bare operands and ( expr ) syntax. */ - -static VALUE *eval7 (void) -{ - VALUE *v; - - if (!*args) - error_msg_and_die ( "syntax error"); - - if (nextarg ("(")) { - args++; - v = eval (); - if (!nextarg (")")) - error_msg_and_die ( "syntax error"); - args++; - return v; - } - - if (nextarg (")")) - error_msg_and_die ( "syntax error"); - - return str_value (*args++); -} - -/* Handle match, substr, index, length, and quote keywords. */ - -static VALUE *eval6 (void) -{ - VALUE *l, *r, *v, *i1, *i2; - - if (nextarg ("quote")) { - args++; - if (!*args) - error_msg_and_die ( "syntax error"); - return str_value (*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; - } - 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) - v->u.i = 0; - freev (l); - freev (r); - return v; - } - 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 (""); - else { - v = xmalloc (sizeof(VALUE)); - v->type = string; - v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1), - l->u.s + i1->u.i - 1, i2->u.i); - v->u.s[i2->u.i] = 0; - } - freev (l); - freev (i1); - freev (i2); - return v; - } - else - return eval7 (); -} - -/* Handle : operator (pattern matching). - Calls docolon to do the real work. */ - -static VALUE *eval5 (void) -{ - VALUE *l, *r, *v; - - l = eval6 (); - while (nextarg (":")) { - args++; - r = eval6 (); - v = docolon (l, r); - freev (l); - freev (r); - l = v; - } - return l; -} - -/* Handle *, /, % operators. */ - -static VALUE *eval4 (void) -{ - VALUE *l, *r; - int (*fxn) (), val; - - 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); - } -} - -/* Handle +, - operators. */ - -static VALUE *eval3 (void) -{ - VALUE *l, *r; - int (*fxn) (), val; - - 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); - } -} - -/* Handle comparisons. */ - -static VALUE *eval2 (void) -{ - VALUE *l, *r; - int (*fxn) (), val; - - 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); - } -} - -/* Handle &. */ - -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); - } - return l; -} - -/* Handle |. */ - -static VALUE *eval (void) -{ - VALUE *l, *r; - - l = eval1 (); - while (nextarg ("|")) { - args++; - r = eval1 (); - if (null (l)) { - freev (l); - l = r; - } - else - freev (r); - } - return l; -} diff --git a/busybox/fbset.c b/busybox/fbset.c deleted file mode 100644 index 5ccd80e79..000000000 --- a/busybox/fbset.c +++ /dev/null @@ -1,424 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini fbset implementation for busybox - * - * Copyright (C) 1999 by Randolph Chung - * - * 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 - * - * This is a from-scratch implementation of fbset; but the de facto fbset - * implementation was a good reference. fbset (original) is released under - * the GPL, and is (c) 1995-1999 by: - * Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#define DEFAULTFBDEV "/dev/fb0" -#define DEFAULTFBMODE "/etc/fb.modes" - -static const int OPT_CHANGE = (1 << 0); -static const int OPT_INFO = (1 << 1); -static const int OPT_READMODE = (1 << 2); - -enum { - CMD_FB = 1, - CMD_DB = 2, - CMD_GEOMETRY = 3, - CMD_TIMING = 4, - CMD_ACCEL = 5, - CMD_HSYNC = 6, - CMD_VSYNC = 7, - CMD_LACED = 8, - CMD_DOUBLE = 9, -/* CMD_XCOMPAT = 10, */ - CMD_ALL = 11, - CMD_INFO = 12, - CMD_CHANGE = 13, - -#ifdef BB_FEATURE_FBSET_FANCY - CMD_XRES = 100, - CMD_YRES = 101, - CMD_VXRES = 102, - CMD_VYRES = 103, - CMD_DEPTH = 104, - CMD_MATCH = 105, - CMD_PIXCLOCK = 106, - CMD_LEFT = 107, - CMD_RIGHT = 108, - CMD_UPPER = 109, - CMD_LOWER = 110, - CMD_HSLEN = 111, - CMD_VSLEN = 112, - CMD_CSYNC = 113, - CMD_GSYNC = 114, - CMD_EXTSYNC = 115, - CMD_BCAST = 116, - CMD_RGBA = 117, - CMD_STEP = 118, - CMD_MOVE = 119, -#endif -}; - -static unsigned int g_options = 0; - -/* Stuff stolen from the kernel's fb.h */ -static const int FBIOGET_VSCREENINFO = 0x4600; -static const int FBIOPUT_VSCREENINFO = 0x4601; -#define __u32 u_int32_t -struct fb_bitfield { - __u32 offset; /* beginning of bitfield */ - __u32 length; /* length of bitfield */ - __u32 msb_right; /* != 0 : Most significant bit is */ - /* right */ -}; -struct fb_var_screeninfo { - __u32 xres; /* visible resolution */ - __u32 yres; - __u32 xres_virtual; /* virtual resolution */ - __u32 yres_virtual; - __u32 xoffset; /* offset from virtual to visible */ - __u32 yoffset; /* resolution */ - - __u32 bits_per_pixel; /* guess what */ - __u32 grayscale; /* != 0 Graylevels instead of colors */ - - struct fb_bitfield red; /* bitfield in fb mem if true color, */ - struct fb_bitfield green; /* else only length is significant */ - struct fb_bitfield blue; - struct fb_bitfield transp; /* transparency */ - - __u32 nonstd; /* != 0 Non standard pixel format */ - - __u32 activate; /* see FB_ACTIVATE_* */ - - __u32 height; /* height of picture in mm */ - __u32 width; /* width of picture in mm */ - - __u32 accel_flags; /* acceleration flags (hints) */ - - /* Timing: All values in pixclocks, except pixclock (of course) */ - __u32 pixclock; /* pixel clock in ps (pico seconds) */ - __u32 left_margin; /* time from sync to picture */ - __u32 right_margin; /* time from picture to sync */ - __u32 upper_margin; /* time from sync to picture */ - __u32 lower_margin; - __u32 hsync_len; /* length of horizontal sync */ - __u32 vsync_len; /* length of vertical sync */ - __u32 sync; /* see FB_SYNC_* */ - __u32 vmode; /* see FB_VMODE_* */ - __u32 reserved[6]; /* Reserved for future compatibility */ -}; - - -static struct cmdoptions_t { - char *name; - unsigned char param_count; - unsigned char code; -} g_cmdoptions[] = { - { - "-fb", 1, CMD_FB}, { - "-db", 1, CMD_DB}, { - "-a", 0, CMD_ALL}, { - "-i", 0, CMD_INFO}, { - "-g", 5, CMD_GEOMETRY}, { - "-t", 7, CMD_TIMING}, { - "-accel", 1, CMD_ACCEL}, { - "-hsync", 1, CMD_HSYNC}, { - "-vsync", 1, CMD_VSYNC}, { - "-laced", 1, CMD_LACED}, { - "-double", 1, CMD_DOUBLE}, { - "-n", 0, CMD_CHANGE}, { -#ifdef BB_FEATURE_FBSET_FANCY - "-all", 0, CMD_ALL}, { - "-xres", 1, CMD_XRES}, { - "-yres", 1, CMD_YRES}, { - "-vxres", 1, CMD_VXRES}, { - "-vyres", 1, CMD_VYRES}, { - "-depth", 1, CMD_DEPTH}, { - "-match", 0, CMD_MATCH}, { - "-geometry", 5, CMD_GEOMETRY}, { - "-pixclock", 1, CMD_PIXCLOCK}, { - "-left", 1, CMD_LEFT}, { - "-right", 1, CMD_RIGHT}, { - "-upper", 1, CMD_UPPER}, { - "-lower", 1, CMD_LOWER}, { - "-hslen", 1, CMD_HSLEN}, { - "-vslen", 1, CMD_VSLEN}, { - "-timings", 7, CMD_TIMING}, { - "-csync", 1, CMD_CSYNC}, { - "-gsync", 1, CMD_GSYNC}, { - "-extsync", 1, CMD_EXTSYNC}, { - "-bcast", 1, CMD_BCAST}, { - "-rgba", 1, CMD_RGBA}, { - "-step", 1, CMD_STEP}, { - "-move", 1, CMD_MOVE}, { -#endif - 0, 0, 0} -}; - -#ifdef BB_FEATURE_FBSET_READMODE -/* taken from linux/fb.h */ -static const int FB_VMODE_INTERLACED = 1; /* interlaced */ -static const int FB_VMODE_DOUBLE = 2; /* double scan */ -static const int FB_SYNC_HOR_HIGH_ACT = 1; /* horizontal sync high active */ -static const int FB_SYNC_VERT_HIGH_ACT = 2; /* vertical sync high active */ -static const int FB_SYNC_EXT = 4; /* external sync */ -static const int FB_SYNC_COMP_HIGH_ACT = 8; /* composite sync high active */ -#endif -static int readmode(struct fb_var_screeninfo *base, const char *fn, - const char *mode) -{ -#ifdef BB_FEATURE_FBSET_READMODE - FILE *f; - char buf[256]; - char *p = buf; - - f = xfopen(fn, "r"); - while (!feof(f)) { - fgets(buf, sizeof(buf), f); - if ((p = strstr(buf, "mode ")) || (p = strstr(buf, "mode\t"))) { - p += 5; - if ((p = strstr(buf, mode))) { - p += strlen(mode); - if (!isspace(*p) && (*p != 0) && (*p != '"') - && (*p != '\r') && (*p != '\n')) - continue; /* almost, but not quite */ - while (!feof(f)) { - fgets(buf, sizeof(buf), f); - - if ((p = strstr(buf, "geometry "))) { - p += 9; - - sscanf(p, "%d %d %d %d %d", - &(base->xres), &(base->yres), - &(base->xres_virtual), &(base->yres_virtual), - &(base->bits_per_pixel)); - } else if ((p = strstr(buf, "timings "))) { - p += 8; - - sscanf(p, "%d %d %d %d %d %d %d", - &(base->pixclock), - &(base->left_margin), &(base->right_margin), - &(base->upper_margin), &(base->lower_margin), - &(base->hsync_len), &(base->vsync_len)); - } else if ((p = strstr(buf, "laced "))) { - p += 6; - - if (strstr(buf, "false")) { - base->vmode &= ~FB_VMODE_INTERLACED; - } else { - base->vmode |= FB_VMODE_INTERLACED; - } - } else if ((p = strstr(buf, "double "))) { - p += 7; - - if (strstr(buf, "false")) { - base->vmode &= ~FB_VMODE_DOUBLE; - } else { - base->vmode |= FB_VMODE_DOUBLE; - } - } else if ((p = strstr(buf, "vsync "))) { - p += 6; - - if (strstr(buf, "low")) { - base->sync &= ~FB_SYNC_VERT_HIGH_ACT; - } else { - base->sync |= FB_SYNC_VERT_HIGH_ACT; - } - } else if ((p = strstr(buf, "hsync "))) { - p += 6; - - if (strstr(buf, "low")) { - base->sync &= ~FB_SYNC_HOR_HIGH_ACT; - } else { - base->sync |= FB_SYNC_HOR_HIGH_ACT; - } - } else if ((p = strstr(buf, "csync "))) { - p += 6; - - if (strstr(buf, "low")) { - base->sync &= ~FB_SYNC_COMP_HIGH_ACT; - } else { - base->sync |= FB_SYNC_COMP_HIGH_ACT; - } - } else if ((p = strstr(buf, "extsync "))) { - p += 8; - - if (strstr(buf, "false")) { - base->sync &= ~FB_SYNC_EXT; - } else { - base->sync |= FB_SYNC_EXT; - } - } - - if (strstr(buf, "endmode")) - return 1; - } - } - } - } -#else - error_msg( "mode reading not compiled in"); -#endif - return 0; -} - -static void setmode(struct fb_var_screeninfo *base, - struct fb_var_screeninfo *set) -{ - if ((int) set->xres > 0) - base->xres = set->xres; - if ((int) set->yres > 0) - base->yres = set->yres; - if ((int) set->xres_virtual > 0) - base->xres_virtual = set->xres_virtual; - if ((int) set->yres_virtual > 0) - base->yres_virtual = set->yres_virtual; - if ((int) set->bits_per_pixel > 0) - base->bits_per_pixel = set->bits_per_pixel; -} - -static void showmode(struct fb_var_screeninfo *v) -{ - double drate = 0, hrate = 0, vrate = 0; - - if (v->pixclock) { - drate = 1e12 / v->pixclock; - hrate = - drate / (v->left_margin + v->xres + v->right_margin + - v->hsync_len); - vrate = - hrate / (v->upper_margin + v->yres + v->lower_margin + - v->vsync_len); - } - printf("\nmode \"%ux%u-%u\"\n", v->xres, v->yres, (int) (vrate + 0.5)); -#ifdef BB_FEATURE_FBSET_FANCY - printf("\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n", drate / 1e6, - hrate / 1e3, vrate); -#endif - printf("\tgeometry %u %u %u %u %u\n", v->xres, v->yres, - v->xres_virtual, v->yres_virtual, v->bits_per_pixel); - printf("\ttimings %u %u %u %u %u %u %u\n", v->pixclock, v->left_margin, - v->right_margin, v->upper_margin, v->lower_margin, v->hsync_len, - v->vsync_len); - printf("\taccel %s\n", (v->accel_flags > 0 ? "true" : "false")); - printf("\trgba %u/%u,%u/%u,%u/%u,%u/%u\n", v->red.length, - v->red.offset, v->green.length, v->green.offset, v->blue.length, - v->blue.offset, v->transp.length, v->transp.offset); - printf("endmode\n\n"); -} - -#ifdef STANDALONE -int main(int argc, char **argv) -#else -extern int fbset_main(int argc, char **argv) -#endif -{ - struct fb_var_screeninfo var, varset; - int fh, i; - char *fbdev = DEFAULTFBDEV; - char *modefile = DEFAULTFBMODE; - char *thisarg, *mode = NULL; - - memset(&varset, 0xFF, sizeof(varset)); - - /* parse cmd args.... why do they have to make things so difficult? */ - argv++; - argc--; - for (; argc > 0 && (thisarg = *argv); argc--, argv++) { - for (i = 0; g_cmdoptions[i].name; i++) { - if (!strcmp(thisarg, g_cmdoptions[i].name)) { - if (argc - 1 < g_cmdoptions[i].param_count) - show_usage(); - switch (g_cmdoptions[i].code) { - case CMD_FB: - fbdev = argv[1]; - break; - case CMD_DB: - modefile = argv[1]; - break; - case CMD_GEOMETRY: - varset.xres = strtoul(argv[1], 0, 0); - varset.yres = strtoul(argv[2], 0, 0); - varset.xres_virtual = strtoul(argv[3], 0, 0); - varset.yres_virtual = strtoul(argv[4], 0, 0); - varset.bits_per_pixel = strtoul(argv[5], 0, 0); - break; - case CMD_TIMING: - varset.pixclock = strtoul(argv[1], 0, 0); - varset.left_margin = strtoul(argv[2], 0, 0); - varset.right_margin = strtoul(argv[3], 0, 0); - varset.upper_margin = strtoul(argv[4], 0, 0); - varset.lower_margin = strtoul(argv[5], 0, 0); - varset.hsync_len = strtoul(argv[6], 0, 0); - varset.vsync_len = strtoul(argv[7], 0, 0); - break; - case CMD_CHANGE: - g_options |= OPT_CHANGE; - break; -#ifdef BB_FEATURE_FBSET_FANCY - case CMD_XRES: - varset.xres = strtoul(argv[1], 0, 0); - break; - case CMD_YRES: - varset.yres = strtoul(argv[1], 0, 0); - break; -#endif - } - argc -= g_cmdoptions[i].param_count; - argv += g_cmdoptions[i].param_count; - break; - } - } - if (!g_cmdoptions[i].name) { - if (argc == 1) { - mode = *argv; - g_options |= OPT_READMODE; - } else { - show_usage(); - } - } - } - - if ((fh = open(fbdev, O_RDONLY)) < 0) - perror_msg_and_die("fbset(open)"); - if (ioctl(fh, FBIOGET_VSCREENINFO, &var)) - perror_msg_and_die("fbset(ioctl)"); - if (g_options & OPT_READMODE) { - if (!readmode(&var, modefile, mode)) { - error_msg("Unknown video mode `%s'", mode); - return EXIT_FAILURE; - } - } - - setmode(&var, &varset); - if (g_options & OPT_CHANGE) - if (ioctl(fh, FBIOPUT_VSCREENINFO, &var)) - perror_msg_and_die("fbset(ioctl)"); - showmode(&var); - /* Don't close the file, as exiting will take care of that */ - /* close(fh); */ - - return EXIT_SUCCESS; -} diff --git a/busybox/fdflush.c b/busybox/fdflush.c deleted file mode 100644 index 28f5cb68a..000000000 --- a/busybox/fdflush.c +++ /dev/null @@ -1,47 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini fdflush implementation for busybox - * - * - * 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 - * - */ - -#include -#include -#include -#include -#include "busybox.h" - -/* From */ -#define FDFLUSH _IO(2,0x4b) - -extern int fdflush_main(int argc, char **argv) -{ - int fd; - - if (argc <= 1 || **(++argv) == '-') - show_usage(); - - if ((fd = open(*argv, 0)) < 0) - perror_msg_and_die("%s", *argv); - - if (ioctl(fd, FDFLUSH, 0)) - perror_msg_and_die("%s", *argv); - - return EXIT_SUCCESS; -} diff --git a/busybox/find.c b/busybox/find.c deleted file mode 100644 index e814c97b9..000000000 --- a/busybox/find.c +++ /dev/null @@ -1,200 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini find implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * Reworked by David Douthitt and - * 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - - -static char *pattern; - -#ifdef BB_FEATURE_FIND_TYPE -static int type_mask = 0; -#endif - -#ifdef BB_FEATURE_FIND_PERM -static char perm_char = 0; -static int perm_mask = 0; -#endif - -#ifdef BB_FEATURE_FIND_MTIME -static char mtime_char; -static int mtime_days; -#endif - -static int fileAction(const char *fileName, struct stat *statbuf, void* junk) -{ - if (pattern != NULL) { - const char *tmp = strrchr(fileName, '/'); - - if (tmp == NULL) - tmp = fileName; - else - tmp++; - if (!(fnmatch(pattern, tmp, FNM_PERIOD) == 0)) - goto no_match; - } -#ifdef BB_FEATURE_FIND_TYPE - if (type_mask != 0) { - if (!((statbuf->st_mode & S_IFMT) == type_mask)) - goto no_match; - } -#endif -#ifdef BB_FEATURE_FIND_PERM - if (perm_mask != 0) { - if (!((isdigit(perm_char) && (statbuf->st_mode & 07777) == perm_mask) || - (perm_char == '-' && (statbuf->st_mode & perm_mask) == perm_mask) || - (perm_char == '+' && (statbuf->st_mode & perm_mask) != 0))) - goto no_match; - } -#endif -#ifdef BB_FEATURE_FIND_MTIME - if (mtime_days != 0) { - time_t file_age = time(NULL) - statbuf->st_mtime; - time_t mtime_secs = mtime_days * 24 * 60 * 60; - if (!((isdigit(mtime_char) && mtime_secs >= file_age && - mtime_secs < file_age + 24 * 60 * 60) || - (mtime_char == '+' && mtime_secs >= file_age) || - (mtime_char == '-' && mtime_secs < file_age))) - goto no_match; - } -#endif - puts(fileName); -no_match: - return (TRUE); -} - -#ifdef BB_FEATURE_FIND_TYPE -static int find_type(char *type) -{ - int mask = 0; - - switch (type[0]) { - case 'b': - mask = S_IFBLK; - break; - case 'c': - mask = S_IFCHR; - break; - case 'd': - mask = S_IFDIR; - break; - case 'p': - mask = S_IFIFO; - break; - case 'f': - mask = S_IFREG; - break; - case 'l': - mask = S_IFLNK; - break; - case 's': - mask = S_IFSOCK; - break; - } - - if (mask == 0 || type[1] != '\0') - error_msg_and_die("invalid argument `%s' to `-type'", type); - - return mask; -} -#endif - -int find_main(int argc, char **argv) -{ - int dereference = FALSE; - int i, firstopt, status = EXIT_SUCCESS; - - for (firstopt = 1; firstopt < argc; firstopt++) { - if (argv[firstopt][0] == '-') - break; - } - - /* Parse any options */ - for (i = firstopt; i < argc; i++) { - if (strcmp(argv[i], "-follow") == 0) - dereference = TRUE; - else if (strcmp(argv[i], "-print") == 0) { - ; - } - else if (strcmp(argv[i], "-name") == 0) { - if (++i == argc) - error_msg_and_die("option `-name' requires an argument"); - pattern = argv[i]; -#ifdef BB_FEATURE_FIND_TYPE - } else if (strcmp(argv[i], "-type") == 0) { - if (++i == argc) - error_msg_and_die("option `-type' requires an argument"); - type_mask = find_type(argv[i]); -#endif -#ifdef BB_FEATURE_FIND_PERM - } else if (strcmp(argv[i], "-perm") == 0) { - char *end; - if (++i == argc) - error_msg_and_die("option `-perm' requires an argument"); - perm_mask = strtol(argv[i], &end, 8); - if (end[0] != '\0') - error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]); - if (perm_mask > 07777) - error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]); - if ((perm_char = argv[i][0]) == '-') - perm_mask = -perm_mask; -#endif -#ifdef BB_FEATURE_FIND_MTIME - } else if (strcmp(argv[i], "-mtime") == 0) { - char *end; - if (++i == argc) - error_msg_and_die("option `-mtime' requires an argument"); - mtime_days = strtol(argv[i], &end, 10); - if (end[0] != '\0') - error_msg_and_die("invalid argument `%s' to `-mtime'", argv[i]); - if ((mtime_char = argv[i][0]) == '-') - mtime_days = -mtime_days; -#endif - } else - show_usage(); - } - - if (firstopt == 1) { - if (recursive_action(".", TRUE, dereference, FALSE, fileAction, - fileAction, NULL) == FALSE) - status = EXIT_FAILURE; - } else { - for (i = 1; i < firstopt; i++) { - if (recursive_action(argv[i], TRUE, dereference, FALSE, fileAction, - fileAction, NULL) == FALSE) - status = EXIT_FAILURE; - } - } - - return status; -} diff --git a/busybox/findutils/find.c b/busybox/findutils/find.c deleted file mode 100644 index e814c97b9..000000000 --- a/busybox/findutils/find.c +++ /dev/null @@ -1,200 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini find implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * Reworked by David Douthitt and - * 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - - -static char *pattern; - -#ifdef BB_FEATURE_FIND_TYPE -static int type_mask = 0; -#endif - -#ifdef BB_FEATURE_FIND_PERM -static char perm_char = 0; -static int perm_mask = 0; -#endif - -#ifdef BB_FEATURE_FIND_MTIME -static char mtime_char; -static int mtime_days; -#endif - -static int fileAction(const char *fileName, struct stat *statbuf, void* junk) -{ - if (pattern != NULL) { - const char *tmp = strrchr(fileName, '/'); - - if (tmp == NULL) - tmp = fileName; - else - tmp++; - if (!(fnmatch(pattern, tmp, FNM_PERIOD) == 0)) - goto no_match; - } -#ifdef BB_FEATURE_FIND_TYPE - if (type_mask != 0) { - if (!((statbuf->st_mode & S_IFMT) == type_mask)) - goto no_match; - } -#endif -#ifdef BB_FEATURE_FIND_PERM - if (perm_mask != 0) { - if (!((isdigit(perm_char) && (statbuf->st_mode & 07777) == perm_mask) || - (perm_char == '-' && (statbuf->st_mode & perm_mask) == perm_mask) || - (perm_char == '+' && (statbuf->st_mode & perm_mask) != 0))) - goto no_match; - } -#endif -#ifdef BB_FEATURE_FIND_MTIME - if (mtime_days != 0) { - time_t file_age = time(NULL) - statbuf->st_mtime; - time_t mtime_secs = mtime_days * 24 * 60 * 60; - if (!((isdigit(mtime_char) && mtime_secs >= file_age && - mtime_secs < file_age + 24 * 60 * 60) || - (mtime_char == '+' && mtime_secs >= file_age) || - (mtime_char == '-' && mtime_secs < file_age))) - goto no_match; - } -#endif - puts(fileName); -no_match: - return (TRUE); -} - -#ifdef BB_FEATURE_FIND_TYPE -static int find_type(char *type) -{ - int mask = 0; - - switch (type[0]) { - case 'b': - mask = S_IFBLK; - break; - case 'c': - mask = S_IFCHR; - break; - case 'd': - mask = S_IFDIR; - break; - case 'p': - mask = S_IFIFO; - break; - case 'f': - mask = S_IFREG; - break; - case 'l': - mask = S_IFLNK; - break; - case 's': - mask = S_IFSOCK; - break; - } - - if (mask == 0 || type[1] != '\0') - error_msg_and_die("invalid argument `%s' to `-type'", type); - - return mask; -} -#endif - -int find_main(int argc, char **argv) -{ - int dereference = FALSE; - int i, firstopt, status = EXIT_SUCCESS; - - for (firstopt = 1; firstopt < argc; firstopt++) { - if (argv[firstopt][0] == '-') - break; - } - - /* Parse any options */ - for (i = firstopt; i < argc; i++) { - if (strcmp(argv[i], "-follow") == 0) - dereference = TRUE; - else if (strcmp(argv[i], "-print") == 0) { - ; - } - else if (strcmp(argv[i], "-name") == 0) { - if (++i == argc) - error_msg_and_die("option `-name' requires an argument"); - pattern = argv[i]; -#ifdef BB_FEATURE_FIND_TYPE - } else if (strcmp(argv[i], "-type") == 0) { - if (++i == argc) - error_msg_and_die("option `-type' requires an argument"); - type_mask = find_type(argv[i]); -#endif -#ifdef BB_FEATURE_FIND_PERM - } else if (strcmp(argv[i], "-perm") == 0) { - char *end; - if (++i == argc) - error_msg_and_die("option `-perm' requires an argument"); - perm_mask = strtol(argv[i], &end, 8); - if (end[0] != '\0') - error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]); - if (perm_mask > 07777) - error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]); - if ((perm_char = argv[i][0]) == '-') - perm_mask = -perm_mask; -#endif -#ifdef BB_FEATURE_FIND_MTIME - } else if (strcmp(argv[i], "-mtime") == 0) { - char *end; - if (++i == argc) - error_msg_and_die("option `-mtime' requires an argument"); - mtime_days = strtol(argv[i], &end, 10); - if (end[0] != '\0') - error_msg_and_die("invalid argument `%s' to `-mtime'", argv[i]); - if ((mtime_char = argv[i][0]) == '-') - mtime_days = -mtime_days; -#endif - } else - show_usage(); - } - - if (firstopt == 1) { - if (recursive_action(".", TRUE, dereference, FALSE, fileAction, - fileAction, NULL) == FALSE) - status = EXIT_FAILURE; - } else { - for (i = 1; i < firstopt; i++) { - if (recursive_action(argv[i], TRUE, dereference, FALSE, fileAction, - fileAction, NULL) == FALSE) - status = EXIT_FAILURE; - } - } - - return status; -} diff --git a/busybox/findutils/grep.c b/busybox/findutils/grep.c deleted file mode 100644 index 3254868be..000000000 --- a/busybox/findutils/grep.c +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Mini grep implementation for busybox using libc regex. - * - * 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 - * - */ - -#include -#include -#include -#include -#include /* for strerror() */ -#include -#include "busybox.h" - - -extern int optind; /* in unistd.h */ -extern int errno; /* for use with strerror() */ -extern void xregcomp(regex_t *preg, const char *regex, int cflags); /* in busybox.h */ - -/* options */ -static int reflags = REG_NOSUB; -static int print_filename = 0; -static int print_line_num = 0; -static int print_match_counts = 0; -static int be_quiet = 0; -static int invert_search = 0; -static int suppress_err_msgs = 0; -static int print_files_with_matches = 0; - -#ifdef BB_FEATURE_GREP_CONTEXT -extern char *optarg; /* in getopt.h */ -static int lines_before = 0; -static int lines_after = 0; -static char **before_buf = NULL; -static int last_line_printed = 0; -#endif /* BB_FEATURE_GREP_CONTEXT */ - -/* globals used internally */ -static regex_t *regexes = NULL; /* growable array of compiled regular expressions */ -static int nregexes = 0; /* number of elements in above arrary */ -static int matched; /* keeps track of whether we ever matched */ -static char *cur_file = NULL; /* the current file we are reading */ - - -static void print_line(const char *line, int linenum, char decoration) -{ -#ifdef BB_FEATURE_GREP_CONTEXT - /* possibly print the little '--' seperator */ - if ((lines_before || lines_after) && last_line_printed && - last_line_printed < linenum - 1) { - puts("--"); - } - last_line_printed = linenum; -#endif - if (print_filename) - printf("%s%c", cur_file, decoration); - if (print_line_num) - printf("%i%c", linenum, decoration); - puts(line); -} - - -static void grep_file(FILE *file) -{ - char *line = NULL; - int ret; - int linenum = 0; - int nmatches = 0; - int i; -#ifdef BB_FEATURE_GREP_CONTEXT - int print_n_lines_after = 0; - int curpos = 0; /* track where we are in the circular 'before' buffer */ - int idx = 0; /* used for iteration through the circular buffer */ -#endif /* BB_FEATURE_GREP_CONTEXT */ - - while ((line = get_line_from_file(file)) != NULL) { - chomp(line); - linenum++; - - for (i = 0; i < nregexes; i++) { - /* - * test for a postitive-assertion match (regexec returns success (0) - * and the user did not specify invert search), or a negative-assertion - * match (regexec returns failure (REG_NOMATCH) and the user specified - * invert search) - */ - ret = regexec(®exes[i], line, 0, NULL, 0); - if ((ret == 0 && !invert_search) || (ret == REG_NOMATCH && invert_search)) { - - /* if we found a match but were told to be quiet, stop here and - * return success */ - if (be_quiet) - exit(0); - - /* keep track of matches */ - nmatches++; - - /* if we're just printing filenames, we stop after the first match */ - if (print_files_with_matches) - break; - - /* print the matched line */ - if (print_match_counts == 0) { -#ifdef BB_FEATURE_GREP_CONTEXT - int prevpos = (curpos == 0) ? lines_before - 1 : curpos - 1; - - /* if we were told to print 'before' lines and there is at least - * one line in the circular buffer, print them */ - if (lines_before && before_buf[prevpos] != NULL) { - int first_buf_entry_line_num = linenum - lines_before; - - /* advance to the first entry in the circular buffer, and - * figure out the line number is of the first line in the - * buffer */ - idx = curpos; - while (before_buf[idx] == NULL) { - idx = (idx + 1) % lines_before; - first_buf_entry_line_num++; - } - - /* now print each line in the buffer, clearing them as we go */ - while (before_buf[idx] != NULL) { - print_line(before_buf[idx], first_buf_entry_line_num, '-'); - free(before_buf[idx]); - before_buf[idx] = NULL; - idx = (idx + 1) % lines_before; - first_buf_entry_line_num++; - } - } - - /* make a note that we need to print 'after' lines */ - print_n_lines_after = lines_after; -#endif /* BB_FEATURE_GREP_CONTEXT */ - print_line(line, linenum, ':'); - } - } -#ifdef BB_FEATURE_GREP_CONTEXT - else { /* no match */ - /* Add the line to the circular 'before' buffer */ - if(lines_before) { - if(before_buf[curpos]) - free(before_buf[curpos]); - before_buf[curpos] = strdup(line); - curpos = (curpos + 1) % lines_before; - } - } - - /* if we need to print some context lines after the last match, do so */ - if (print_n_lines_after && (last_line_printed != linenum)) { - print_line(line, linenum, '-'); - print_n_lines_after--; - } -#endif /* BB_FEATURE_GREP_CONTEXT */ - } /* for */ - free(line); - } - - - /* special-case file post-processing for options where we don't print line - * matches, just filenames and possibly match counts */ - - /* grep -c: print [filename:]count, even if count is zero */ - if (print_match_counts) { - if (print_filename) - printf("%s:", cur_file); - if (print_files_with_matches && nmatches > 0) - printf("1\n"); - else - printf("%d\n", nmatches); - } - - /* grep -l: print just the filename, but only if we grepped the line in the file */ - if (print_files_with_matches && nmatches > 0) { - puts(cur_file); - } - - - /* remember if we matched */ - if (nmatches != 0) - matched = 1; -} - - -static void add_regex(const char *restr) -{ - regexes = xrealloc(regexes, sizeof(regex_t) * (++nregexes)); - xregcomp(®exes[nregexes-1], restr, reflags); -} - - -static void load_regexes_from_file(const char *filename) -{ - char *line; - FILE *f = xfopen(filename, "r"); - while ((line = get_line_from_file(f)) != NULL) { - chomp(line); - add_regex(line); - free(line); - } -} - - -#ifdef BB_FEATURE_CLEAN_UP -static void destroy_regexes() -{ - if (regexes == NULL) - return; - - /* destroy all the elments in the array */ - while (--nregexes >= 0) { - regfree(®exes[nregexes]); - free(®exes[nregexes]); - } -} -#endif - - -extern int grep_main(int argc, char **argv) -{ - int opt; -#ifdef BB_FEATURE_GREP_CONTEXT - char *junk; -#endif - -#ifdef BB_FEATURE_CLEAN_UP - /* destroy command strings on exit */ - if (atexit(destroy_regexes) == -1) - perror_msg_and_die("atexit"); -#endif - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "iHhlnqvsce:f:" -#ifdef BB_FEATURE_GREP_CONTEXT -"A:B:C:" -#endif -)) > 0) { - switch (opt) { - case 'i': - reflags |= REG_ICASE; - break; - case 'l': - print_files_with_matches++; - break; - case 'H': - print_filename++; - break; - case 'h': - print_filename--; - break; - case 'n': - print_line_num++; - break; - case 'q': - be_quiet++; - break; - case 'v': - invert_search++; - break; - case 's': - suppress_err_msgs++; - break; - case 'c': - print_match_counts++; - break; - case 'e': - add_regex(optarg); - break; - case 'f': - load_regexes_from_file(optarg); - break; -#ifdef BB_FEATURE_GREP_CONTEXT - case 'A': - lines_after = strtoul(optarg, &junk, 10); - if(*junk != '\0') - error_msg_and_die("invalid context length argument"); - break; - case 'B': - lines_before = strtoul(optarg, &junk, 10); - if(*junk != '\0') - error_msg_and_die("invalid context length argument"); - before_buf = (char **)calloc(lines_before, sizeof(char *)); - break; - case 'C': - lines_after = lines_before = strtoul(optarg, &junk, 10); - if(*junk != '\0') - error_msg_and_die("invalid context length argument"); - before_buf = (char **)calloc(lines_before, sizeof(char *)); - break; -#endif /* BB_FEATURE_GREP_CONTEXT */ - default: - show_usage(); - } - } - - /* if we didn't get a pattern from a -e and no command file was specified, - * argv[optind] should be the pattern. no pattern, no worky */ - if (nregexes == 0) { - if (argv[optind] == NULL) - show_usage(); - else { - add_regex(argv[optind]); - optind++; - } - } - - /* sanity checks */ - if (print_match_counts || be_quiet || print_files_with_matches) { - print_line_num = 0; -#ifdef BB_FEATURE_GREP_CONTEXT - lines_before = 0; - lines_after = 0; -#endif - } - - /* argv[(optind)..(argc-1)] should be names of file to grep through. If - * there is more than one file to grep, we will print the filenames */ - if ((argc-1) - (optind) > 0) - print_filename++; - - /* If no files were specified, or '-' was specified, take input from - * stdin. Otherwise, we grep through all the files specified. */ - if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) { - grep_file(stdin); - } - else { - int i; - FILE *file; - for (i = optind; i < argc; i++) { - cur_file = argv[i]; - file = fopen(cur_file, "r"); - if (file == NULL) { - if (!suppress_err_msgs) - perror_msg("%s", cur_file); - } - else { - grep_file(file); - fclose(file); - } - } - } - - return !matched; /* invert return value 0 = success, 1 = failed */ -} diff --git a/busybox/findutils/which.c b/busybox/findutils/which.c deleted file mode 100644 index c460ffdd1..000000000 --- a/busybox/findutils/which.c +++ /dev/null @@ -1,80 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Which implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -/* getopt not needed */ -#include -#include -#include -#include "busybox.h" - -extern int which_main(int argc, char **argv) -{ - char *path_list, *path_n; - struct stat filestat; - int i, count=1, found, status = EXIT_SUCCESS; - - if (argc <= 1 || **(argv + 1) == '-') - show_usage(); - argc--; - - path_list = getenv("PATH"); - if (!path_list) - path_list = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin"; - - /* Replace colons with zeros in path_parsed and count them */ - for(i=strlen(path_list); i > 0; i--) - if (path_list[i]==':') { - path_list[i]=0; - count++; - } - - while(argc-- > 0) { - path_n = path_list; - argv++; - found = 0; - for (i = 0; i < count; i++) { - char *buf; - buf = concat_path_file(path_n, *argv); - if (stat (buf, &filestat) == 0 - && filestat.st_mode & S_IXUSR) - { - puts(buf); - found = 1; - break; - } - free(buf); - path_n += (strlen(path_n) + 1); - } - if (!found) - status = EXIT_FAILURE; - } - return status; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/findutils/xargs.c b/busybox/findutils/xargs.c deleted file mode 100644 index 48adae90a..000000000 --- a/busybox/findutils/xargs.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Mini xargs implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * Remixed 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 - * - */ - -#include -#include -#include -#include "busybox.h" - -int xargs_main(int argc, char **argv) -{ - char *cmd_to_be_executed = NULL; - char *file_to_act_on = NULL; - - /* - * No options are supported in this version of xargs; no getopt. - * - * Re: The missing -t flag: Most programs that produce output also print - * the filename, so xargs doesn't really need to do it again. Supporting - * the -t flag =greatly= bloats up the size of this app and the memory it - * uses because you have to buffer all the input file strings in memory. If - * you really want to see the filenames that xargs will act on, just run it - * once with no args and xargs will echo the filename. Simple. - */ - - /* Store the command to be executed (taken from the command line) */ - if (argc == 1) { - /* default behavior is to echo all the filenames */ - cmd_to_be_executed = xstrdup("/bin/echo "); - } else { - /* concatenate all the arguments passed to xargs together */ - int i; - int len = 1; /* for the '\0' */ - for (i = 1; i < argc; i++) { - len += strlen(argv[i]); - len += 1; /* for the space between the args */ - cmd_to_be_executed = xrealloc(cmd_to_be_executed, len); - strcat(cmd_to_be_executed, argv[i]); - strcat(cmd_to_be_executed, " "); - } - } - - /* Now, read in one line at a time from stdin, and store this - * line to be used later as an argument to the command */ - while ((file_to_act_on = get_line_from_file(stdin)) !=NULL) { - - FILE *cmd_output = NULL; - char *output_line = NULL; - char *execstr = NULL; - - /* eat the newline off the filename. */ - chomp(file_to_act_on); - - /* eat blank lines */ - if (strlen(file_to_act_on) == 0) - continue; - - /* assemble the command and execute it */ - execstr = xcalloc(strlen(cmd_to_be_executed) + - strlen(file_to_act_on) + 1, sizeof(char)); - strcat(execstr, cmd_to_be_executed); - strcat(execstr, file_to_act_on); - cmd_output = popen(execstr, "r"); - if (cmd_output == NULL) - perror_msg_and_die("popen"); - - /* harvest the output */ - while ((output_line = get_line_from_file(cmd_output)) != NULL) { - fputs(output_line, stdout); - free(output_line); - } - - /* clean up */ - pclose(cmd_output); - free(execstr); - free(file_to_act_on); - } - -#ifdef BB_FEATURE_CLEAN_UP - free(cmd_to_be_executed); -#endif - - return 0; -} - -/* vi: set sw=4 ts=4: */ diff --git a/busybox/free.c b/busybox/free.c deleted file mode 100644 index 2e34a972c..000000000 --- a/busybox/free.c +++ /dev/null @@ -1,69 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini free implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -/* getopt not needed */ - -#include -#include -#include -#include "busybox.h" - -extern int free_main(int argc, char **argv) -{ - struct sysinfo info; - sysinfo(&info); - - /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */ - if (info.mem_unit==0) { - info.mem_unit=1; - } - info.mem_unit*=1024; - - /* TODO: Make all this stuff not overflow when mem >= 4 Gib */ - info.totalram/=info.mem_unit; - info.freeram/=info.mem_unit; - info.totalswap/=info.mem_unit; - info.freeswap/=info.mem_unit; - info.sharedram/=info.mem_unit; - info.bufferram/=info.mem_unit; - - if (argc > 1 && **(argv + 1) == '-') - show_usage(); - - printf("%6s%13s%13s%13s%13s%13s\n", "", "total", "used", "free", - "shared", "buffers"); - - printf("%6s%13ld%13ld%13ld%13ld%13ld\n", "Mem:", info.totalram, - info.totalram-info.freeram, info.freeram, - info.sharedram, info.bufferram); - - printf("%6s%13ld%13ld%13ld\n", "Swap:", info.totalswap, - info.totalswap-info.freeswap, info.freeswap); - - printf("%6s%13ld%13ld%13ld\n", "Total:", info.totalram+info.totalswap, - (info.totalram-info.freeram)+(info.totalswap-info.freeswap), - info.freeram+info.freeswap); - return EXIT_SUCCESS; -} - - diff --git a/busybox/freeramdisk.c b/busybox/freeramdisk.c deleted file mode 100644 index cf25fae6a..000000000 --- a/busybox/freeramdisk.c +++ /dev/null @@ -1,65 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * freeramdisk implementation for busybox - * - * Copyright (C) 2000 and written by Emanuele Caratti - * Adjusted a bit 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - - -/* From linux/fs.h */ -#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */ - -extern int -freeramdisk_main(int argc, char **argv) -{ - int f; - - if (argc != 2 || *argv[1] == '-') { - show_usage(); - } - - if ((f = open(argv[1], O_RDWR)) == -1) { - perror_msg_and_die("cannot open %s", argv[1]); - } - if (ioctl(f, BLKFLSBUF) < 0) { - perror_msg_and_die("failed ioctl on %s", argv[1]); - } - /* Don't bother closing. Exit does - * that, so we can save a few bytes */ - /* close(f); */ - return EXIT_SUCCESS; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ - diff --git a/busybox/fsck_minix.c b/busybox/fsck_minix.c deleted file mode 100644 index 952968d85..000000000 --- a/busybox/fsck_minix.c +++ /dev/null @@ -1,1478 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * fsck.c - a file system consistency checker for Linux. - * - * (C) 1991, 1992 Linus Torvalds. This file may be redistributed - * as per the GNU copyleft. - */ - -/* - * 09.11.91 - made the first rudimetary functions - * - * 10.11.91 - updated, does checking, no repairs yet. - * Sent out to the mailing-list for testing. - * - * 14.11.91 - Testing seems to have gone well. Added some - * correction-code, and changed some functions. - * - * 15.11.91 - More correction code. Hopefully it notices most - * cases now, and tries to do something about them. - * - * 16.11.91 - More corrections (thanks to Mika Jalava). Most - * things seem to work now. Yeah, sure. - * - * - * 19.04.92 - Had to start over again from this old version, as a - * kernel bug ate my enhanced fsck in february. - * - * 28.02.93 - added support for different directory entry sizes.. - * - * Sat Mar 6 18:59:42 1993, faith@cs.unc.edu: Output namelen with - * super-block information - * - * Sat Oct 9 11:17:11 1993, faith@cs.unc.edu: make exit status conform - * to that required by fsutil - * - * Mon Jan 3 11:06:52 1994 - Dr. Wettstein (greg%wind.uucp@plains.nodak.edu) - * Added support for file system valid flag. Also - * added program_version variable and output of - * program name and version number when program - * is executed. - * - * 30.10.94 - added support for v2 filesystem - * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de) - * - * 10.12.94 - added test to prevent checking of mounted fs adapted - * from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck - * program. (Daniel Quinlan, quinlan@yggdrasil.com) - * - * 01.07.96 - Fixed the v2 fs stuff to use the right #defines and such - * for modern libcs (janl@math.uio.no, Nicolai Langfeldt) - * - * 02.07.96 - Added C bit fiddling routines from rmk@ecs.soton.ac.uk - * (Russell King). He made them for ARM. It would seem - * that the ARM is powerful enough to do this in C whereas - * i386 and m64k must use assembly to get it fast >:-) - * This should make minix fsck systemindependent. - * (janl@math.uio.no, Nicolai Langfeldt) - * - * 04.11.96 - Added minor fixes from Andreas Schwab to avoid compiler - * warnings. Added mc68k bitops from - * Joerg Dorchain . - * - * 06.11.96 - Added v2 code submitted by Joerg Dorchain, but written by - * Andreas Schwab. - * - * 1999-02-22 Arkadiusz Mi¶kiewicz - * - added Native Language Support - * - * - * I've had no time to add comments - hopefully the function names - * are comments enough. As with all file system checkers, this assumes - * the file system is quiescent - don't use it on a mounted device - * unless you can be sure nobody is writing to it (and remember that the - * kernel can write to it when it searches for files). - * - * Usuage: fsck [-larvsm] device - * -l for a listing of all the filenames - * -a for automatic repairs (not implemented) - * -r for repairs (interactive) (not implemented) - * -v for verbose (tells how many files) - * -s for super-block info - * -m for minix-like "mode not cleared" warnings - * -f force filesystem check even if filesystem marked as valid - * - * The device may be a block device or a image of one, but this isn't - * enforced (but it's not much fun on a character device :-). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -static const int MINIX_ROOT_INO = 1; -static const int MINIX_LINK_MAX = 250; -static const int MINIX2_LINK_MAX = 65530; - -static const int MINIX_I_MAP_SLOTS = 8; -static const int MINIX_Z_MAP_SLOTS = 64; -static const int MINIX_SUPER_MAGIC = 0x137F; /* original minix fs */ -static const int MINIX_SUPER_MAGIC2 = 0x138F; /* minix fs, 30 char names */ -static const int MINIX2_SUPER_MAGIC = 0x2468; /* minix V2 fs */ -static const int MINIX2_SUPER_MAGIC2 = 0x2478; /* minix V2 fs, 30 char names */ -static const int MINIX_VALID_FS = 0x0001; /* Clean fs. */ -static const int MINIX_ERROR_FS = 0x0002; /* fs has errors. */ - -#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) -#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode))) - -static const int MINIX_V1 = 0x0001; /* original minix fs */ -static const int MINIX_V2 = 0x0002; /* minix V2 fs */ - -#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version - -/* - * This is the original minix inode layout on disk. - * Note the 8-bit gid and atime and ctime. - */ -struct minix_inode { - u_int16_t i_mode; - u_int16_t i_uid; - u_int32_t i_size; - u_int32_t i_time; - u_int8_t i_gid; - u_int8_t i_nlinks; - u_int16_t i_zone[9]; -}; - -/* - * The new minix inode has all the time entries, as well as - * long block numbers and a third indirect block (7+1+1+1 - * instead of 7+1+1). Also, some previously 8-bit values are - * now 16-bit. The inode is now 64 bytes instead of 32. - */ -struct minix2_inode { - u_int16_t i_mode; - u_int16_t i_nlinks; - u_int16_t i_uid; - u_int16_t i_gid; - u_int32_t i_size; - u_int32_t i_atime; - u_int32_t i_mtime; - u_int32_t i_ctime; - u_int32_t i_zone[10]; -}; - -/* - * minix super-block data on disk - */ -struct minix_super_block { - u_int16_t s_ninodes; - u_int16_t s_nzones; - u_int16_t s_imap_blocks; - u_int16_t s_zmap_blocks; - u_int16_t s_firstdatazone; - u_int16_t s_log_zone_size; - u_int32_t s_max_size; - u_int16_t s_magic; - u_int16_t s_state; - u_int32_t s_zones; -}; - -struct minix_dir_entry { - u_int16_t inode; - char name[0]; -}; - -#define BLOCK_SIZE_BITS 10 -#define BLOCK_SIZE (1<> 3] & (1<<(i & 7))) != 0; -} -#define inode_in_use(x) (bit(inode_map,(x))) -#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1)) - -#define mark_inode(x) (setbit(inode_map,(x)),changed=1) -#define unmark_inode(x) (clrbit(inode_map,(x)),changed=1) - -#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1),changed=1) -#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1),changed=1) - -static void leave(int) __attribute__ ((noreturn)); -static void leave(int status) -{ - if (termios_set) - tcsetattr(0, TCSANOW, &termios); - exit(status); -} - -static void die(const char *str) -{ - error_msg("%s", str); - leave(8); -} - -/* - * This simply goes through the file-name data and prints out the - * current file. - */ -static void print_current_name(void) -{ - int i = 0; - - while (i < name_depth) - printf("/%.*s", namelen, name_list[i++]); - if (i == 0) - printf("/"); -} - -static int ask(const char *string, int def) -{ - int c; - - if (!repair) { - printf("\n"); - errors_uncorrected = 1; - return 0; - } - if (automatic) { - printf("\n"); - if (!def) - errors_uncorrected = 1; - return def; - } - printf(def ? "%s (y/n)? " : "%s (n/y)? ", string); - for (;;) { - fflush(stdout); - if ((c = getchar()) == EOF) { - if (!def) - errors_uncorrected = 1; - return def; - } - c = toupper(c); - if (c == 'Y') { - def = 1; - break; - } else if (c == 'N') { - def = 0; - break; - } else if (c == ' ' || c == '\n') - break; - } - if (def) - printf("y\n"); - else { - printf("n\n"); - errors_uncorrected = 1; - } - return def; -} - -/* - * Make certain that we aren't checking a filesystem that is on a - * mounted partition. Code adapted from e2fsck, Copyright (C) 1993, - * 1994 Theodore Ts'o. Also licensed under GPL. - */ -static void check_mount(void) -{ - FILE *f; - struct mntent *mnt; - int cont; - int fd; - - if ((f = setmntent(MOUNTED, "r")) == NULL) - return; - while ((mnt = getmntent(f)) != NULL) - if (strcmp(device_name, mnt->mnt_fsname) == 0) - break; - endmntent(f); - if (!mnt) - return; - - /* - * If the root is mounted read-only, then /etc/mtab is - * probably not correct; so we won't issue a warning based on - * it. - */ - fd = open(MOUNTED, O_RDWR); - if (fd < 0 && errno == EROFS) - return; - else - close(fd); - - printf("%s is mounted. ", device_name); - if (isatty(0) && isatty(1)) - cont = ask("Do you really want to continue", 0); - else - cont = 0; - if (!cont) { - printf("check aborted.\n"); - exit(0); - } - return; -} - -/* - * check_zone_nr checks to see that *nr is a valid zone nr. If it - * isn't, it will possibly be repaired. Check_zone_nr sets *corrected - * if an error was corrected, and returns the zone (0 for no zone - * or a bad zone-number). - */ -static int check_zone_nr(unsigned short *nr, int *corrected) -{ - if (!*nr) - return 0; - if (*nr < FIRSTZONE) - printf("Zone nr < FIRSTZONE in file `"); - else if (*nr >= ZONES) - printf("Zone nr >= ZONES in file `"); - else - return *nr; - print_current_name(); - printf("'."); - if (ask("Remove block", 1)) { - *nr = 0; - *corrected = 1; - } - return 0; -} - -#ifdef BB_FEATURE_MINIX2 -static int check_zone_nr2(unsigned int *nr, int *corrected) -{ - if (!*nr) - return 0; - if (*nr < FIRSTZONE) - printf("Zone nr < FIRSTZONE in file `"); - else if (*nr >= ZONES) - printf("Zone nr >= ZONES in file `"); - else - return *nr; - print_current_name(); - printf("'."); - if (ask("Remove block", 1)) { - *nr = 0; - *corrected = 1; - } - return 0; -} -#endif - -/* - * read-block reads block nr into the buffer at addr. - */ -static void read_block(unsigned int nr, char *addr) -{ - if (!nr) { - memset(addr, 0, BLOCK_SIZE); - return; - } - if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) { - printf("Read error: unable to seek to block in file '"); - print_current_name(); - printf("'\n"); - memset(addr, 0, BLOCK_SIZE); - errors_uncorrected = 1; - } else if (BLOCK_SIZE != read(IN, addr, BLOCK_SIZE)) { - printf("Read error: bad block in file '"); - print_current_name(); - printf("'\n"); - memset(addr, 0, BLOCK_SIZE); - errors_uncorrected = 1; - } -} - -/* - * write_block writes block nr to disk. - */ -static void write_block(unsigned int nr, char *addr) -{ - if (!nr) - return; - if (nr < FIRSTZONE || nr >= ZONES) { - printf("Internal error: trying to write bad block\n" - "Write request ignored\n"); - errors_uncorrected = 1; - return; - } - if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) - die("seek failed in write_block"); - if (BLOCK_SIZE != write(IN, addr, BLOCK_SIZE)) { - printf("Write error: bad block in file '"); - print_current_name(); - printf("'\n"); - errors_uncorrected = 1; - } -} - -/* - * map-block calculates the absolute block nr of a block in a file. - * It sets 'changed' if the inode has needed changing, and re-writes - * any indirect blocks with errors. - */ -static int map_block(struct minix_inode *inode, unsigned int blknr) -{ - unsigned short ind[BLOCK_SIZE >> 1]; - unsigned short dind[BLOCK_SIZE >> 1]; - int blk_chg, block, result; - - if (blknr < 7) - return check_zone_nr(inode->i_zone + blknr, &changed); - blknr -= 7; - if (blknr < 512) { - block = check_zone_nr(inode->i_zone + 7, &changed); - read_block(block, (char *) ind); - blk_chg = 0; - result = check_zone_nr(blknr + ind, &blk_chg); - if (blk_chg) - write_block(block, (char *) ind); - return result; - } - blknr -= 512; - block = check_zone_nr(inode->i_zone + 8, &changed); - read_block(block, (char *) dind); - blk_chg = 0; - result = check_zone_nr(dind + (blknr / 512), &blk_chg); - if (blk_chg) - write_block(block, (char *) dind); - block = result; - read_block(block, (char *) ind); - blk_chg = 0; - result = check_zone_nr(ind + (blknr % 512), &blk_chg); - if (blk_chg) - write_block(block, (char *) ind); - return result; -} - -#ifdef BB_FEATURE_MINIX2 -static int map_block2(struct minix2_inode *inode, unsigned int blknr) -{ - unsigned int ind[BLOCK_SIZE >> 2]; - unsigned int dind[BLOCK_SIZE >> 2]; - unsigned int tind[BLOCK_SIZE >> 2]; - int blk_chg, block, result; - - if (blknr < 7) - return check_zone_nr2(inode->i_zone + blknr, &changed); - blknr -= 7; - if (blknr < 256) { - block = check_zone_nr2(inode->i_zone + 7, &changed); - read_block(block, (char *) ind); - blk_chg = 0; - result = check_zone_nr2(blknr + ind, &blk_chg); - if (blk_chg) - write_block(block, (char *) ind); - return result; - } - blknr -= 256; - if (blknr >= 256 * 256) { - block = check_zone_nr2(inode->i_zone + 8, &changed); - read_block(block, (char *) dind); - blk_chg = 0; - result = check_zone_nr2(dind + blknr / 256, &blk_chg); - if (blk_chg) - write_block(block, (char *) dind); - block = result; - read_block(block, (char *) ind); - blk_chg = 0; - result = check_zone_nr2(ind + blknr % 256, &blk_chg); - if (blk_chg) - write_block(block, (char *) ind); - return result; - } - blknr -= 256 * 256; - block = check_zone_nr2(inode->i_zone + 9, &changed); - read_block(block, (char *) tind); - blk_chg = 0; - result = check_zone_nr2(tind + blknr / (256 * 256), &blk_chg); - if (blk_chg) - write_block(block, (char *) tind); - block = result; - read_block(block, (char *) dind); - blk_chg = 0; - result = check_zone_nr2(dind + (blknr / 256) % 256, &blk_chg); - if (blk_chg) - write_block(block, (char *) dind); - block = result; - read_block(block, (char *) ind); - blk_chg = 0; - result = check_zone_nr2(ind + blknr % 256, &blk_chg); - if (blk_chg) - write_block(block, (char *) ind); - return result; -} -#endif - -static void write_super_block(void) -{ - /* - * Set the state of the filesystem based on whether or not there - * are uncorrected errors. The filesystem valid flag is - * unconditionally set if we get this far. - */ - Super.s_state |= MINIX_VALID_FS; - if (errors_uncorrected) - Super.s_state |= MINIX_ERROR_FS; - else - Super.s_state &= ~MINIX_ERROR_FS; - - if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET)) - die("seek failed in write_super_block"); - if (BLOCK_SIZE != write(IN, super_block_buffer, BLOCK_SIZE)) - die("unable to write super-block"); - - return; -} - -static void write_tables(void) -{ - write_super_block(); - - if (IMAPS * BLOCK_SIZE != write(IN, inode_map, IMAPS * BLOCK_SIZE)) - die("Unable to write inode map"); - if (ZMAPS * BLOCK_SIZE != write(IN, zone_map, ZMAPS * BLOCK_SIZE)) - die("Unable to write zone map"); - if (INODE_BUFFER_SIZE != write(IN, inode_buffer, INODE_BUFFER_SIZE)) - die("Unable to write inodes"); -} - -static void get_dirsize(void) -{ - int block; - char blk[BLOCK_SIZE]; - int size; - -#ifdef BB_FEATURE_MINIX2 - if (version2) - block = Inode2[ROOT_INO].i_zone[0]; - else -#endif - block = Inode[ROOT_INO].i_zone[0]; - read_block(block, blk); - for (size = 16; size < BLOCK_SIZE; size <<= 1) { - if (strcmp(blk + size + 2, "..") == 0) { - dirsize = size; - namelen = size - 2; - return; - } - } - /* use defaults */ -} - -static void read_superblock(void) -{ - if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET)) - die("seek failed"); - if (BLOCK_SIZE != read(IN, super_block_buffer, BLOCK_SIZE)) - die("unable to read super block"); - if (MAGIC == MINIX_SUPER_MAGIC) { - namelen = 14; - dirsize = 16; - version2 = 0; - } else if (MAGIC == MINIX_SUPER_MAGIC2) { - namelen = 30; - dirsize = 32; - version2 = 0; -#ifdef BB_FEATURE_MINIX2 - } else if (MAGIC == MINIX2_SUPER_MAGIC) { - namelen = 14; - dirsize = 16; - version2 = 1; - } else if (MAGIC == MINIX2_SUPER_MAGIC2) { - namelen = 30; - dirsize = 32; - version2 = 1; -#endif - } else - die("bad magic number in super-block"); - if (ZONESIZE != 0 || BLOCK_SIZE != 1024) - die("Only 1k blocks/zones supported"); - if (IMAPS * BLOCK_SIZE * 8 < INODES + 1) - die("bad s_imap_blocks field in super-block"); - if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1) - die("bad s_zmap_blocks field in super-block"); -} - -static void read_tables(void) -{ - inode_map = xmalloc(IMAPS * BLOCK_SIZE); - zone_map = xmalloc(ZMAPS * BLOCK_SIZE); - memset(inode_map, 0, sizeof(inode_map)); - memset(zone_map, 0, sizeof(zone_map)); - inode_buffer = xmalloc(INODE_BUFFER_SIZE); - inode_count = xmalloc(INODES + 1); - zone_count = xmalloc(ZONES); - if (IMAPS * BLOCK_SIZE != read(IN, inode_map, IMAPS * BLOCK_SIZE)) - die("Unable to read inode map"); - if (ZMAPS * BLOCK_SIZE != read(IN, zone_map, ZMAPS * BLOCK_SIZE)) - die("Unable to read zone map"); - if (INODE_BUFFER_SIZE != read(IN, inode_buffer, INODE_BUFFER_SIZE)) - die("Unable to read inodes"); - if (NORM_FIRSTZONE != FIRSTZONE) { - printf("Warning: Firstzone != Norm_firstzone\n"); - errors_uncorrected = 1; - } - get_dirsize(); - if (show) { - printf("%ld inodes\n", INODES); - printf("%ld blocks\n", ZONES); - printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE); - printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE); - printf("Maxsize=%ld\n", MAXSIZE); - printf("Filesystem state=%d\n", Super.s_state); - printf("namelen=%d\n\n", namelen); - } -} - -static struct minix_inode *get_inode(unsigned int nr) -{ - struct minix_inode *inode; - - if (!nr || nr > INODES) - return NULL; - total++; - inode = Inode + nr; - if (!inode_count[nr]) { - if (!inode_in_use(nr)) { - printf("Inode %d marked not used, but used for file '", nr); - print_current_name(); - printf("'\n"); - if (repair) { - if (ask("Mark in use", 1)) - mark_inode(nr); - } else { - errors_uncorrected = 1; - } - } - if (S_ISDIR(inode->i_mode)) - directory++; - else if (S_ISREG(inode->i_mode)) - regular++; - else if (S_ISCHR(inode->i_mode)) - chardev++; - else if (S_ISBLK(inode->i_mode)) - blockdev++; - else if (S_ISLNK(inode->i_mode)) - symlinks++; - else if (S_ISSOCK(inode->i_mode)); - else if (S_ISFIFO(inode->i_mode)); - else { - print_current_name(); - printf(" has mode %05o\n", inode->i_mode); - } - - } else - links++; - if (!++inode_count[nr]) { - printf("Warning: inode count too big.\n"); - inode_count[nr]--; - errors_uncorrected = 1; - } - return inode; -} - -#ifdef BB_FEATURE_MINIX2 -static struct minix2_inode *get_inode2(unsigned int nr) -{ - struct minix2_inode *inode; - - if (!nr || nr > INODES) - return NULL; - total++; - inode = Inode2 + nr; - if (!inode_count[nr]) { - if (!inode_in_use(nr)) { - printf("Inode %d marked not used, but used for file '", nr); - print_current_name(); - printf("'\n"); - if (repair) { - if (ask("Mark in use", 1)) - mark_inode(nr); - else - errors_uncorrected = 1; - } - } - if (S_ISDIR(inode->i_mode)) - directory++; - else if (S_ISREG(inode->i_mode)) - regular++; - else if (S_ISCHR(inode->i_mode)) - chardev++; - else if (S_ISBLK(inode->i_mode)) - blockdev++; - else if (S_ISLNK(inode->i_mode)) - symlinks++; - else if (S_ISSOCK(inode->i_mode)); - else if (S_ISFIFO(inode->i_mode)); - else { - print_current_name(); - printf(" has mode %05o\n", inode->i_mode); - } - } else - links++; - if (!++inode_count[nr]) { - printf("Warning: inode count too big.\n"); - inode_count[nr]--; - errors_uncorrected = 1; - } - return inode; -} -#endif - -static void check_root(void) -{ - struct minix_inode *inode = Inode + ROOT_INO; - - if (!inode || !S_ISDIR(inode->i_mode)) - die("root inode isn't a directory"); -} - -#ifdef BB_FEATURE_MINIX2 -static void check_root2(void) -{ - struct minix2_inode *inode = Inode2 + ROOT_INO; - - if (!inode || !S_ISDIR(inode->i_mode)) - die("root inode isn't a directory"); -} -#endif - -static int add_zone(unsigned short *znr, int *corrected) -{ - int result; - int block; - - result = 0; - block = check_zone_nr(znr, corrected); - if (!block) - return 0; - if (zone_count[block]) { - printf("Block has been used before. Now in file `"); - print_current_name(); - printf("'."); - if (ask("Clear", 1)) { - *znr = 0; - block = 0; - *corrected = 1; - } - } - if (!block) - return 0; - if (!zone_in_use(block)) { - printf("Block %d in file `", block); - print_current_name(); - printf("' is marked not in use."); - if (ask("Correct", 1)) - mark_zone(block); - } - if (!++zone_count[block]) - zone_count[block]--; - return block; -} - -#ifdef BB_FEATURE_MINIX2 -static int add_zone2(unsigned int *znr, int *corrected) -{ - int result; - int block; - - result = 0; - block = check_zone_nr2(znr, corrected); - if (!block) - return 0; - if (zone_count[block]) { - printf("Block has been used before. Now in file `"); - print_current_name(); - printf("'."); - if (ask("Clear", 1)) { - *znr = 0; - block = 0; - *corrected = 1; - } - } - if (!block) - return 0; - if (!zone_in_use(block)) { - printf("Block %d in file `", block); - print_current_name(); - printf("' is marked not in use."); - if (ask("Correct", 1)) - mark_zone(block); - } - if (!++zone_count[block]) - zone_count[block]--; - return block; -} -#endif - -static void add_zone_ind(unsigned short *znr, int *corrected) -{ - static char blk[BLOCK_SIZE]; - int i, chg_blk = 0; - int block; - - block = add_zone(znr, corrected); - if (!block) - return; - read_block(block, blk); - for (i = 0; i < (BLOCK_SIZE >> 1); i++) - add_zone(i + (unsigned short *) blk, &chg_blk); - if (chg_blk) - write_block(block, blk); -} - -#ifdef BB_FEATURE_MINIX2 -static void add_zone_ind2(unsigned int *znr, int *corrected) -{ - static char blk[BLOCK_SIZE]; - int i, chg_blk = 0; - int block; - - block = add_zone2(znr, corrected); - if (!block) - return; - read_block(block, blk); - for (i = 0; i < BLOCK_SIZE >> 2; i++) - add_zone2(i + (unsigned int *) blk, &chg_blk); - if (chg_blk) - write_block(block, blk); -} -#endif - -static void add_zone_dind(unsigned short *znr, int *corrected) -{ - static char blk[BLOCK_SIZE]; - int i, blk_chg = 0; - int block; - - block = add_zone(znr, corrected); - if (!block) - return; - read_block(block, blk); - for (i = 0; i < (BLOCK_SIZE >> 1); i++) - add_zone_ind(i + (unsigned short *) blk, &blk_chg); - if (blk_chg) - write_block(block, blk); -} - -#ifdef BB_FEATURE_MINIX2 -static void add_zone_dind2(unsigned int *znr, int *corrected) -{ - static char blk[BLOCK_SIZE]; - int i, blk_chg = 0; - int block; - - block = add_zone2(znr, corrected); - if (!block) - return; - read_block(block, blk); - for (i = 0; i < BLOCK_SIZE >> 2; i++) - add_zone_ind2(i + (unsigned int *) blk, &blk_chg); - if (blk_chg) - write_block(block, blk); -} - -static void add_zone_tind2(unsigned int *znr, int *corrected) -{ - static char blk[BLOCK_SIZE]; - int i, blk_chg = 0; - int block; - - block = add_zone2(znr, corrected); - if (!block) - return; - read_block(block, blk); - for (i = 0; i < BLOCK_SIZE >> 2; i++) - add_zone_dind2(i + (unsigned int *) blk, &blk_chg); - if (blk_chg) - write_block(block, blk); -} -#endif - -static void check_zones(unsigned int i) -{ - struct minix_inode *inode; - - if (!i || i > INODES) - return; - if (inode_count[i] > 1) /* have we counted this file already? */ - return; - inode = Inode + i; - if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) && - !S_ISLNK(inode->i_mode)) return; - for (i = 0; i < 7; i++) - add_zone(i + inode->i_zone, &changed); - add_zone_ind(7 + inode->i_zone, &changed); - add_zone_dind(8 + inode->i_zone, &changed); -} - -#ifdef BB_FEATURE_MINIX2 -static void check_zones2(unsigned int i) -{ - struct minix2_inode *inode; - - if (!i || i > INODES) - return; - if (inode_count[i] > 1) /* have we counted this file already? */ - return; - inode = Inode2 + i; - if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) - && !S_ISLNK(inode->i_mode)) - return; - for (i = 0; i < 7; i++) - add_zone2(i + inode->i_zone, &changed); - add_zone_ind2(7 + inode->i_zone, &changed); - add_zone_dind2(8 + inode->i_zone, &changed); - add_zone_tind2(9 + inode->i_zone, &changed); -} -#endif - -static void check_file(struct minix_inode *dir, unsigned int offset) -{ - static char blk[BLOCK_SIZE]; - struct minix_inode *inode; - int ino; - char *name; - int block; - - block = map_block(dir, offset / BLOCK_SIZE); - read_block(block, blk); - name = blk + (offset % BLOCK_SIZE) + 2; - ino = *(unsigned short *) (name - 2); - if (ino > INODES) { - print_current_name(); - printf(" contains a bad inode number for file '"); - printf("%.*s'.", namelen, name); - if (ask(" Remove", 1)) { - *(unsigned short *) (name - 2) = 0; - write_block(block, blk); - } - ino = 0; - } - if (name_depth < MAX_DEPTH) - strncpy(name_list[name_depth], name, namelen); - name_depth++; - inode = get_inode(ino); - name_depth--; - if (!offset) { - if (!inode || strcmp(".", name)) { - print_current_name(); - printf(": bad directory: '.' isn't first\n"); - errors_uncorrected = 1; - } else - return; - } - if (offset == dirsize) { - if (!inode || strcmp("..", name)) { - print_current_name(); - printf(": bad directory: '..' isn't second\n"); - errors_uncorrected = 1; - } else - return; - } - if (!inode) - return; - if (name_depth < MAX_DEPTH) - strncpy(name_list[name_depth], name, namelen); - name_depth++; - if (list) { - if (verbose) - printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks); - print_current_name(); - if (S_ISDIR(inode->i_mode)) - printf(":\n"); - else - printf("\n"); - } - check_zones(ino); - if (inode && S_ISDIR(inode->i_mode)) - recursive_check(ino); - name_depth--; - return; -} - -#ifdef BB_FEATURE_MINIX2 -static void check_file2(struct minix2_inode *dir, unsigned int offset) -{ - static char blk[BLOCK_SIZE]; - struct minix2_inode *inode; - int ino; - char *name; - int block; - - block = map_block2(dir, offset / BLOCK_SIZE); - read_block(block, blk); - name = blk + (offset % BLOCK_SIZE) + 2; - ino = *(unsigned short *) (name - 2); - if (ino > INODES) { - print_current_name(); - printf(" contains a bad inode number for file '"); - printf("%.*s'.", namelen, name); - if (ask(" Remove", 1)) { - *(unsigned short *) (name - 2) = 0; - write_block(block, blk); - } - ino = 0; - } - if (name_depth < MAX_DEPTH) - strncpy(name_list[name_depth], name, namelen); - name_depth++; - inode = get_inode2(ino); - name_depth--; - if (!offset) { - if (!inode || strcmp(".", name)) { - print_current_name(); - printf(": bad directory: '.' isn't first\n"); - errors_uncorrected = 1; - } else - return; - } - if (offset == dirsize) { - if (!inode || strcmp("..", name)) { - print_current_name(); - printf(": bad directory: '..' isn't second\n"); - errors_uncorrected = 1; - } else - return; - } - if (!inode) - return; - name_depth++; - if (list) { - if (verbose) - printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks); - print_current_name(); - if (S_ISDIR(inode->i_mode)) - printf(":\n"); - else - printf("\n"); - } - check_zones2(ino); - if (inode && S_ISDIR(inode->i_mode)) - recursive_check2(ino); - name_depth--; - return; -} -#endif - -static void recursive_check(unsigned int ino) -{ - struct minix_inode *dir; - unsigned int offset; - - dir = Inode + ino; - if (!S_ISDIR(dir->i_mode)) - die("internal error"); - if (dir->i_size < 2 * dirsize) { - print_current_name(); - printf(": bad directory: size<32"); - errors_uncorrected = 1; - } - for (offset = 0; offset < dir->i_size; offset += dirsize) - check_file(dir, offset); -} - -#ifdef BB_FEATURE_MINIX2 -static void recursive_check2(unsigned int ino) -{ - struct minix2_inode *dir; - unsigned int offset; - - dir = Inode2 + ino; - if (!S_ISDIR(dir->i_mode)) - die("internal error"); - if (dir->i_size < 2 * dirsize) { - print_current_name(); - printf(": bad directory: size < 32"); - errors_uncorrected = 1; - } - for (offset = 0; offset < dir->i_size; offset += dirsize) - check_file2(dir, offset); -} -#endif - -static int bad_zone(int i) -{ - char buffer[1024]; - - if (BLOCK_SIZE * i != lseek(IN, BLOCK_SIZE * i, SEEK_SET)) - die("seek failed in bad_zone"); - return (BLOCK_SIZE != read(IN, buffer, BLOCK_SIZE)); -} - -static void check_counts(void) -{ - int i; - - for (i = 1; i <= INODES; i++) { - if (!inode_in_use(i) && Inode[i].i_mode && warn_mode) { - printf("Inode %d mode not cleared.", i); - if (ask("Clear", 1)) { - Inode[i].i_mode = 0; - changed = 1; - } - } - if (!inode_count[i]) { - if (!inode_in_use(i)) - continue; - printf("Inode %d not used, marked used in the bitmap.", i); - if (ask("Clear", 1)) - unmark_inode(i); - continue; - } - if (!inode_in_use(i)) { - printf("Inode %d used, marked unused in the bitmap.", i); - if (ask("Set", 1)) - mark_inode(i); - } - if (Inode[i].i_nlinks != inode_count[i]) { - printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.", - i, Inode[i].i_mode, Inode[i].i_nlinks, inode_count[i]); - if (ask("Set i_nlinks to count", 1)) { - Inode[i].i_nlinks = inode_count[i]; - changed = 1; - } - } - } - for (i = FIRSTZONE; i < ZONES; i++) { - if (zone_in_use(i) == zone_count[i]) - continue; - if (!zone_count[i]) { - if (bad_zone(i)) - continue; - printf("Zone %d: marked in use, no file uses it.", i); - if (ask("Unmark", 1)) - unmark_zone(i); - continue; - } - printf("Zone %d: %sin use, counted=%d\n", - i, zone_in_use(i) ? "" : "not ", zone_count[i]); - } -} - -#ifdef BB_FEATURE_MINIX2 -static void check_counts2(void) -{ - int i; - - for (i = 1; i <= INODES; i++) { - if (!inode_in_use(i) && Inode2[i].i_mode && warn_mode) { - printf("Inode %d mode not cleared.", i); - if (ask("Clear", 1)) { - Inode2[i].i_mode = 0; - changed = 1; - } - } - if (!inode_count[i]) { - if (!inode_in_use(i)) - continue; - printf("Inode %d not used, marked used in the bitmap.", i); - if (ask("Clear", 1)) - unmark_inode(i); - continue; - } - if (!inode_in_use(i)) { - printf("Inode %d used, marked unused in the bitmap.", i); - if (ask("Set", 1)) - mark_inode(i); - } - if (Inode2[i].i_nlinks != inode_count[i]) { - printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.", - i, Inode2[i].i_mode, Inode2[i].i_nlinks, - inode_count[i]); - if (ask("Set i_nlinks to count", 1)) { - Inode2[i].i_nlinks = inode_count[i]; - changed = 1; - } - } - } - for (i = FIRSTZONE; i < ZONES; i++) { - if (zone_in_use(i) == zone_count[i]) - continue; - if (!zone_count[i]) { - if (bad_zone(i)) - continue; - printf("Zone %d: marked in use, no file uses it.", i); - if (ask("Unmark", 1)) - unmark_zone(i); - continue; - } - printf("Zone %d: %sin use, counted=%d\n", - i, zone_in_use(i) ? "" : "not ", zone_count[i]); - } -} -#endif - -static void check(void) -{ - memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count)); - memset(zone_count, 0, ZONES * sizeof(*zone_count)); - check_zones(ROOT_INO); - recursive_check(ROOT_INO); - check_counts(); -} - -#ifdef BB_FEATURE_MINIX2 -static void check2(void) -{ - memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count)); - memset(zone_count, 0, ZONES * sizeof(*zone_count)); - check_zones2(ROOT_INO); - recursive_check2(ROOT_INO); - check_counts2(); -} -#endif - -/* Wed Feb 9 15:17:06 MST 2000 */ -/* dynamically allocate name_list (instead of making it static) */ -static void alloc_name_list(void) -{ - int i; - - name_list = xmalloc(sizeof(char *) * MAX_DEPTH); - for (i = 0; i < MAX_DEPTH; i++) - name_list[i] = xmalloc(sizeof(char) * BUFSIZ + 1); -} - -#ifdef BB_FEATURE_CLEAN_UP -/* execute this atexit() to deallocate name_list[] */ -/* piptigger was here */ -static void free_name_list(void) -{ - int i; - - if (name_list) { - for (i = 0; i < MAX_DEPTH; i++) { - if (name_list[i]) { - free(name_list[i]); - } - } - free(name_list); - } -} -#endif - -extern int fsck_minix_main(int argc, char **argv) -{ - struct termios tmp; - int count; - int retcode = 0; - - alloc_name_list(); -#ifdef BB_FEATURE_CLEAN_UP - /* Don't bother to free memory. Exit does - * that automagically, so we can save a few bytes */ - atexit(free_name_list); -#endif - - if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) - die("bad inode size"); -#ifdef BB_FEATURE_MINIX2 - if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) - die("bad v2 inode size"); -#endif - while (argc-- > 1) { - argv++; - if (argv[0][0] != '-') { - if (device_name) - show_usage(); - else - device_name = argv[0]; - } else - while (*++argv[0]) - switch (argv[0][0]) { - case 'l': - list = 1; - break; - case 'a': - automatic = 1; - repair = 1; - break; - case 'r': - automatic = 0; - repair = 1; - break; - case 'v': - verbose = 1; - break; - case 's': - show = 1; - break; - case 'm': - warn_mode = 1; - break; - case 'f': - force = 1; - break; - default: - show_usage(); - } - } - if (!device_name) - show_usage(); - check_mount(); /* trying to check a mounted filesystem? */ - if (repair && !automatic) { - if (!isatty(0) || !isatty(1)) - die("need terminal for interactive repairs"); - } - IN = open(device_name, repair ? O_RDWR : O_RDONLY); - if (IN < 0){ - fprintf(stderr,"unable to open device '%s'.\n",device_name); - leave(8); - } - for (count = 0; count < 3; count++) - sync(); - read_superblock(); - - /* - * Determine whether or not we should continue with the checking. - * This is based on the status of the filesystem valid and error - * flags and whether or not the -f switch was specified on the - * command line. - */ - printf("%s, %s\n", applet_name, program_version); - if (!(Super.s_state & MINIX_ERROR_FS) && - (Super.s_state & MINIX_VALID_FS) && !force) { - if (repair) - printf("%s is clean, no check.\n", device_name); - return retcode; - } else if (force) - printf("Forcing filesystem check on %s.\n", device_name); - else if (repair) - printf("Filesystem on %s is dirty, needs checking.\n", - device_name); - - read_tables(); - - if (repair && !automatic) { - tcgetattr(0, &termios); - tmp = termios; - tmp.c_lflag &= ~(ICANON | ECHO); - tcsetattr(0, TCSANOW, &tmp); - termios_set = 1; - } -#ifdef BB_FEATURE_MINIX2 - if (version2) { - check_root2(); - check2(); - } else -#endif - { - check_root(); - check(); - } - if (verbose) { - int i, free_cnt; - - for (i = 1, free_cnt = 0; i <= INODES; i++) - if (!inode_in_use(i)) - free_cnt++; - printf("\n%6ld inodes used (%ld%%)\n", (INODES - free_cnt), - 100 * (INODES - free_cnt) / INODES); - for (i = FIRSTZONE, free_cnt = 0; i < ZONES; i++) - if (!zone_in_use(i)) - free_cnt++; - printf("%6ld zones used (%ld%%)\n", (ZONES - free_cnt), - 100 * (ZONES - free_cnt) / ZONES); - printf("\n%6d regular files\n" - "%6d directories\n" - "%6d character device files\n" - "%6d block device files\n" - "%6d links\n" - "%6d symbolic links\n" - "------\n" - "%6d files\n", - regular, directory, chardev, blockdev, - links - 2 * directory + 1, symlinks, - total - 2 * directory + 1); - } - if (changed) { - write_tables(); - printf("----------------------------\n" - "FILE SYSTEM HAS BEEN CHANGED\n" - "----------------------------\n"); - for (count = 0; count < 3; count++) - sync(); - } else if (repair) - write_super_block(); - - if (repair && !automatic) - tcsetattr(0, TCSANOW, &termios); - - if (changed) - retcode += 3; - if (errors_uncorrected) - retcode += 4; - return retcode; -} diff --git a/busybox/getopt.c b/busybox/getopt.c deleted file mode 100644 index 95ecba6e6..000000000 --- a/busybox/getopt.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * getopt.c - Enhanced implementation of BSD getopt(1) - * Copyright (c) 1997, 1998, 1999, 2000 Frodo Looijaard - * - * 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. - */ - -/* - * Version 1.0-b4: Tue Sep 23 1997. First public release. - * Version 1.0: Wed Nov 19 1997. - * Bumped up the version number to 1.0 - * Fixed minor typo (CSH instead of TCSH) - * Version 1.0.1: Tue Jun 3 1998 - * Fixed sizeof instead of strlen bug - * Bumped up the version number to 1.0.1 - * Version 1.0.2: Thu Jun 11 1998 (not present) - * Fixed gcc-2.8.1 warnings - * Fixed --version/-V option (not present) - * Version 1.0.5: Tue Jun 22 1999 - * Make -u option work (not present) - * Version 1.0.6: Tue Jun 27 2000 - * No important changes - * Version 1.1.0: Tue Jun 30 2000 - * Added NLS support (partly written by Arkadiusz Mikiewicz - * ) - * Ported to Busybox - Alfred M. Szmidt - * Removed --version/-V and --help/-h in - * Removed prase_error(), using error_msg() from Busybox instead - * Replaced our_malloc with xmalloc and our_realloc with xrealloc - * - */ - -#include -#include -#include -#include -#include -#include - -#include "busybox.h" - -/* NON_OPT is the code that is returned when a non-option is found in '+' - mode */ -static const int NON_OPT = 1; -/* LONG_OPT is the code that is returned when a long option is found. */ -static const int LONG_OPT = 2; - -/* The shells recognized. */ -typedef enum {BASH,TCSH} shell_t; - - -/* Some global variables that tells us how to parse. */ -static shell_t shell=BASH; /* The shell we generate output for. */ -static int quiet_errors=0; /* 0 is not quiet. */ -static int quiet_output=0; /* 0 is not quiet. */ -static int quote=1; /* 1 is do quote. */ -static int alternative=0; /* 0 is getopt_long, 1 is getopt_long_only */ - -/* Function prototypes */ -static const char *normalize(const char *arg); -static int generate_output(char * argv[],int argc,const char *optstr, - const struct option *longopts); -static void add_long_options(char *options); -static void add_longopt(const char *name,int has_arg); -static void set_shell(const char *new_shell); - - -/* - * This function 'normalizes' a single argument: it puts single quotes around - * it and escapes other special characters. If quote is false, it just - * returns its argument. - * Bash only needs special treatment for single quotes; tcsh also recognizes - * exclamation marks within single quotes, and nukes whitespace. - * This function returns a pointer to a buffer that is overwritten by - * each call. - */ -const char *normalize(const char *arg) -{ - static char *BUFFER=NULL; - const char *argptr=arg; - char *bufptr; - - if (BUFFER != NULL) - free(BUFFER); - - if (!quote) { /* Just copy arg */ - BUFFER=xmalloc(strlen(arg)+1); - - strcpy(BUFFER,arg); - return BUFFER; - } - - /* Each character in arg may take upto four characters in the result: - For a quote we need a closing quote, a backslash, a quote and an - opening quote! We need also the global opening and closing quote, - and one extra character for '\0'. */ - BUFFER=xmalloc(strlen(arg)*4+3); - - bufptr=BUFFER; - *bufptr++='\''; - - while (*argptr) { - if (*argptr == '\'') { - /* Quote: replace it with: '\'' */ - *bufptr++='\''; - *bufptr++='\\'; - *bufptr++='\''; - *bufptr++='\''; - } else if (shell==TCSH && *argptr=='!') { - /* Exclamation mark: replace it with: \! */ - *bufptr++='\''; - *bufptr++='\\'; - *bufptr++='!'; - *bufptr++='\''; - } else if (shell==TCSH && *argptr=='\n') { - /* Newline: replace it with: \n */ - *bufptr++='\\'; - *bufptr++='n'; - } else if (shell==TCSH && isspace(*argptr)) { - /* Non-newline whitespace: replace it with \ */ - *bufptr++='\''; - *bufptr++='\\'; - *bufptr++=*argptr; - *bufptr++='\''; - } else - /* Just copy */ - *bufptr++=*argptr; - argptr++; - } - *bufptr++='\''; - *bufptr++='\0'; - return BUFFER; -} - -/* - * Generate the output. argv[0] is the program name (used for reporting errors). - * argv[1..] contains the options to be parsed. argc must be the number of - * elements in argv (ie. 1 if there are no options, only the program name), - * optstr must contain the short options, and longopts the long options. - * Other settings are found in global variables. - */ -int generate_output(char * argv[],int argc,const char *optstr, - const struct option *longopts) -{ - int exit_code = 0; /* We assume everything will be OK */ - int opt; - int longindex; - const char *charptr; - - if (quiet_errors) /* No error reporting from getopt(3) */ - opterr=0; - optind=0; /* Reset getopt(3) */ - - while ((opt = (alternative? - getopt_long_only(argc,argv,optstr,longopts,&longindex): - getopt_long(argc,argv,optstr,longopts,&longindex))) - != EOF) - if (opt == '?' || opt == ':' ) - exit_code = 1; - else if (!quiet_output) { - if (opt == LONG_OPT) { - printf(" --%s",longopts[longindex].name); - if (longopts[longindex].has_arg) - printf(" %s", - normalize(optarg?optarg:"")); - } else if (opt == NON_OPT) - printf(" %s",normalize(optarg)); - else { - printf(" -%c",opt); - charptr = strchr(optstr,opt); - if (charptr != NULL && *++charptr == ':') - printf(" %s", - normalize(optarg?optarg:"")); - } - } - - if (! quiet_output) { - printf(" --"); - while (optind < argc) - printf(" %s",normalize(argv[optind++])); - printf("\n"); - } - return exit_code; -} - -static struct option *long_options=NULL; -static int long_options_length=0; /* Length of array */ -static int long_options_nr=0; /* Nr of used elements in array */ -static const int LONG_OPTIONS_INCR = 10; -#define init_longopt() add_longopt(NULL,0) - -/* Register a long option. The contents of name is copied. */ -void add_longopt(const char *name,int has_arg) -{ - char *tmp; - if (!name) { /* init */ - free(long_options); - long_options=NULL; - long_options_length=0; - long_options_nr=0; - } - - if (long_options_nr == long_options_length) { - long_options_length += LONG_OPTIONS_INCR; - long_options=xrealloc(long_options, - sizeof(struct option) * - long_options_length); - } - - long_options[long_options_nr].name=NULL; - long_options[long_options_nr].has_arg=0; - long_options[long_options_nr].flag=NULL; - long_options[long_options_nr].val=0; - - if (long_options_nr) { /* Not for init! */ - long_options[long_options_nr-1].has_arg=has_arg; - long_options[long_options_nr-1].flag=NULL; - long_options[long_options_nr-1].val=LONG_OPT; - tmp = xmalloc(strlen(name)+1); - strcpy(tmp,name); - long_options[long_options_nr-1].name=tmp; - } - long_options_nr++; -} - - -/* - * Register several long options. options is a string of long options, - * separated by commas or whitespace. - * This nukes options! - */ -void add_long_options(char *options) -{ - int arg_opt, tlen; - char *tokptr=strtok(options,", \t\n"); - while (tokptr) { - arg_opt=no_argument; - tlen=strlen(tokptr); - if (tlen > 0) { - if (tokptr[tlen-1] == ':') { - if (tlen > 1 && tokptr[tlen-2] == ':') { - tokptr[tlen-2]='\0'; - tlen -= 2; - arg_opt=optional_argument; - } else { - tokptr[tlen-1]='\0'; - tlen -= 1; - arg_opt=required_argument; - } - if (tlen == 0) - error_msg("empty long option after -l or --long argument"); - } - add_longopt(tokptr,arg_opt); - } - tokptr=strtok(NULL,", \t\n"); - } -} - -void set_shell(const char *new_shell) -{ - if (!strcmp(new_shell,"bash")) - shell=BASH; - else if (!strcmp(new_shell,"tcsh")) - shell=TCSH; - else if (!strcmp(new_shell,"sh")) - shell=BASH; - else if (!strcmp(new_shell,"csh")) - shell=TCSH; - else - error_msg("unknown shell after -s or --shell argument"); -} - - -/* Exit codes: - * 0) No errors, succesful operation. - * 1) getopt(3) returned an error. - * 2) A problem with parameter parsing for getopt(1). - * 3) Internal error, out of memory - * 4) Returned for -T - */ - -static struct option longopts[]= -{ - {"options",required_argument,NULL,'o'}, - {"longoptions",required_argument,NULL,'l'}, - {"quiet",no_argument,NULL,'q'}, - {"quiet-output",no_argument,NULL,'Q'}, - {"shell",required_argument,NULL,'s'}, - {"test",no_argument,NULL,'T'}, - {"unquoted",no_argument,NULL,'u'}, - {"alternative",no_argument,NULL,'a'}, - {"name",required_argument,NULL,'n'}, - {NULL,0,NULL,0} -}; - -/* Stop scanning as soon as a non-option argument is found! */ -static const char *shortopts="+ao:l:n:qQs:Tu"; - - -int getopt_main(int argc, char *argv[]) -{ - char *optstr=NULL; - char *name=NULL; - int opt; - int compatible=0; - - init_longopt(); - - if (getenv("GETOPT_COMPATIBLE")) - compatible=1; - - if (argc == 1) { - if (compatible) { - /* For some reason, the original getopt gave no error - when there were no arguments. */ - printf(" --\n"); - exit(0); - } else - error_msg_and_die("missing optstring argument"); - } - - if (argv[1][0] != '-' || compatible) { - quote=0; - optstr=xmalloc(strlen(argv[1])+1); - strcpy(optstr,argv[1]+strspn(argv[1],"-+")); - argv[1]=argv[0]; - exit(generate_output(argv+1,argc-1,optstr,long_options)); - } - - while ((opt=getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF) - switch (opt) { - case 'a': - alternative=1; - break; - case 'o': - if (optstr) - free(optstr); - optstr=xmalloc(strlen(optarg)+1); - strcpy(optstr,optarg); - break; - case 'l': - add_long_options(optarg); - break; - case 'n': - if (name) - free(name); - name=xmalloc(strlen(optarg)+1); - strcpy(name,optarg); - break; - case 'q': - quiet_errors=1; - break; - case 'Q': - quiet_output=1; - break; - case 's': - set_shell(optarg); - break; - case 'T': - exit(4); - case 'u': - quote=0; - break; - default: - show_usage(); - } - - if (!optstr) { - if (optind >= argc) - error_msg_and_die("missing optstring argument"); - else { - optstr=xmalloc(strlen(argv[optind])+1); - strcpy(optstr,argv[optind]); - optind++; - } - } - if (name) - argv[optind-1]=name; - else - argv[optind-1]=argv[0]; - exit(generate_output(argv+optind-1,argc-optind+1,optstr,long_options)); -} - -/* - Local Variables: - c-file-style: "linux" - c-basic-offset: 4 - tab-width: 4 - End: -*/ diff --git a/busybox/grep.c b/busybox/grep.c deleted file mode 100644 index 3254868be..000000000 --- a/busybox/grep.c +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Mini grep implementation for busybox using libc regex. - * - * 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 - * - */ - -#include -#include -#include -#include -#include /* for strerror() */ -#include -#include "busybox.h" - - -extern int optind; /* in unistd.h */ -extern int errno; /* for use with strerror() */ -extern void xregcomp(regex_t *preg, const char *regex, int cflags); /* in busybox.h */ - -/* options */ -static int reflags = REG_NOSUB; -static int print_filename = 0; -static int print_line_num = 0; -static int print_match_counts = 0; -static int be_quiet = 0; -static int invert_search = 0; -static int suppress_err_msgs = 0; -static int print_files_with_matches = 0; - -#ifdef BB_FEATURE_GREP_CONTEXT -extern char *optarg; /* in getopt.h */ -static int lines_before = 0; -static int lines_after = 0; -static char **before_buf = NULL; -static int last_line_printed = 0; -#endif /* BB_FEATURE_GREP_CONTEXT */ - -/* globals used internally */ -static regex_t *regexes = NULL; /* growable array of compiled regular expressions */ -static int nregexes = 0; /* number of elements in above arrary */ -static int matched; /* keeps track of whether we ever matched */ -static char *cur_file = NULL; /* the current file we are reading */ - - -static void print_line(const char *line, int linenum, char decoration) -{ -#ifdef BB_FEATURE_GREP_CONTEXT - /* possibly print the little '--' seperator */ - if ((lines_before || lines_after) && last_line_printed && - last_line_printed < linenum - 1) { - puts("--"); - } - last_line_printed = linenum; -#endif - if (print_filename) - printf("%s%c", cur_file, decoration); - if (print_line_num) - printf("%i%c", linenum, decoration); - puts(line); -} - - -static void grep_file(FILE *file) -{ - char *line = NULL; - int ret; - int linenum = 0; - int nmatches = 0; - int i; -#ifdef BB_FEATURE_GREP_CONTEXT - int print_n_lines_after = 0; - int curpos = 0; /* track where we are in the circular 'before' buffer */ - int idx = 0; /* used for iteration through the circular buffer */ -#endif /* BB_FEATURE_GREP_CONTEXT */ - - while ((line = get_line_from_file(file)) != NULL) { - chomp(line); - linenum++; - - for (i = 0; i < nregexes; i++) { - /* - * test for a postitive-assertion match (regexec returns success (0) - * and the user did not specify invert search), or a negative-assertion - * match (regexec returns failure (REG_NOMATCH) and the user specified - * invert search) - */ - ret = regexec(®exes[i], line, 0, NULL, 0); - if ((ret == 0 && !invert_search) || (ret == REG_NOMATCH && invert_search)) { - - /* if we found a match but were told to be quiet, stop here and - * return success */ - if (be_quiet) - exit(0); - - /* keep track of matches */ - nmatches++; - - /* if we're just printing filenames, we stop after the first match */ - if (print_files_with_matches) - break; - - /* print the matched line */ - if (print_match_counts == 0) { -#ifdef BB_FEATURE_GREP_CONTEXT - int prevpos = (curpos == 0) ? lines_before - 1 : curpos - 1; - - /* if we were told to print 'before' lines and there is at least - * one line in the circular buffer, print them */ - if (lines_before && before_buf[prevpos] != NULL) { - int first_buf_entry_line_num = linenum - lines_before; - - /* advance to the first entry in the circular buffer, and - * figure out the line number is of the first line in the - * buffer */ - idx = curpos; - while (before_buf[idx] == NULL) { - idx = (idx + 1) % lines_before; - first_buf_entry_line_num++; - } - - /* now print each line in the buffer, clearing them as we go */ - while (before_buf[idx] != NULL) { - print_line(before_buf[idx], first_buf_entry_line_num, '-'); - free(before_buf[idx]); - before_buf[idx] = NULL; - idx = (idx + 1) % lines_before; - first_buf_entry_line_num++; - } - } - - /* make a note that we need to print 'after' lines */ - print_n_lines_after = lines_after; -#endif /* BB_FEATURE_GREP_CONTEXT */ - print_line(line, linenum, ':'); - } - } -#ifdef BB_FEATURE_GREP_CONTEXT - else { /* no match */ - /* Add the line to the circular 'before' buffer */ - if(lines_before) { - if(before_buf[curpos]) - free(before_buf[curpos]); - before_buf[curpos] = strdup(line); - curpos = (curpos + 1) % lines_before; - } - } - - /* if we need to print some context lines after the last match, do so */ - if (print_n_lines_after && (last_line_printed != linenum)) { - print_line(line, linenum, '-'); - print_n_lines_after--; - } -#endif /* BB_FEATURE_GREP_CONTEXT */ - } /* for */ - free(line); - } - - - /* special-case file post-processing for options where we don't print line - * matches, just filenames and possibly match counts */ - - /* grep -c: print [filename:]count, even if count is zero */ - if (print_match_counts) { - if (print_filename) - printf("%s:", cur_file); - if (print_files_with_matches && nmatches > 0) - printf("1\n"); - else - printf("%d\n", nmatches); - } - - /* grep -l: print just the filename, but only if we grepped the line in the file */ - if (print_files_with_matches && nmatches > 0) { - puts(cur_file); - } - - - /* remember if we matched */ - if (nmatches != 0) - matched = 1; -} - - -static void add_regex(const char *restr) -{ - regexes = xrealloc(regexes, sizeof(regex_t) * (++nregexes)); - xregcomp(®exes[nregexes-1], restr, reflags); -} - - -static void load_regexes_from_file(const char *filename) -{ - char *line; - FILE *f = xfopen(filename, "r"); - while ((line = get_line_from_file(f)) != NULL) { - chomp(line); - add_regex(line); - free(line); - } -} - - -#ifdef BB_FEATURE_CLEAN_UP -static void destroy_regexes() -{ - if (regexes == NULL) - return; - - /* destroy all the elments in the array */ - while (--nregexes >= 0) { - regfree(®exes[nregexes]); - free(®exes[nregexes]); - } -} -#endif - - -extern int grep_main(int argc, char **argv) -{ - int opt; -#ifdef BB_FEATURE_GREP_CONTEXT - char *junk; -#endif - -#ifdef BB_FEATURE_CLEAN_UP - /* destroy command strings on exit */ - if (atexit(destroy_regexes) == -1) - perror_msg_and_die("atexit"); -#endif - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "iHhlnqvsce:f:" -#ifdef BB_FEATURE_GREP_CONTEXT -"A:B:C:" -#endif -)) > 0) { - switch (opt) { - case 'i': - reflags |= REG_ICASE; - break; - case 'l': - print_files_with_matches++; - break; - case 'H': - print_filename++; - break; - case 'h': - print_filename--; - break; - case 'n': - print_line_num++; - break; - case 'q': - be_quiet++; - break; - case 'v': - invert_search++; - break; - case 's': - suppress_err_msgs++; - break; - case 'c': - print_match_counts++; - break; - case 'e': - add_regex(optarg); - break; - case 'f': - load_regexes_from_file(optarg); - break; -#ifdef BB_FEATURE_GREP_CONTEXT - case 'A': - lines_after = strtoul(optarg, &junk, 10); - if(*junk != '\0') - error_msg_and_die("invalid context length argument"); - break; - case 'B': - lines_before = strtoul(optarg, &junk, 10); - if(*junk != '\0') - error_msg_and_die("invalid context length argument"); - before_buf = (char **)calloc(lines_before, sizeof(char *)); - break; - case 'C': - lines_after = lines_before = strtoul(optarg, &junk, 10); - if(*junk != '\0') - error_msg_and_die("invalid context length argument"); - before_buf = (char **)calloc(lines_before, sizeof(char *)); - break; -#endif /* BB_FEATURE_GREP_CONTEXT */ - default: - show_usage(); - } - } - - /* if we didn't get a pattern from a -e and no command file was specified, - * argv[optind] should be the pattern. no pattern, no worky */ - if (nregexes == 0) { - if (argv[optind] == NULL) - show_usage(); - else { - add_regex(argv[optind]); - optind++; - } - } - - /* sanity checks */ - if (print_match_counts || be_quiet || print_files_with_matches) { - print_line_num = 0; -#ifdef BB_FEATURE_GREP_CONTEXT - lines_before = 0; - lines_after = 0; -#endif - } - - /* argv[(optind)..(argc-1)] should be names of file to grep through. If - * there is more than one file to grep, we will print the filenames */ - if ((argc-1) - (optind) > 0) - print_filename++; - - /* If no files were specified, or '-' was specified, take input from - * stdin. Otherwise, we grep through all the files specified. */ - if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) { - grep_file(stdin); - } - else { - int i; - FILE *file; - for (i = optind; i < argc; i++) { - cur_file = argv[i]; - file = fopen(cur_file, "r"); - if (file == NULL) { - if (!suppress_err_msgs) - perror_msg("%s", cur_file); - } - else { - grep_file(file); - fclose(file); - } - } - } - - return !matched; /* invert return value 0 = success, 1 = failed */ -} diff --git a/busybox/gunzip.c b/busybox/gunzip.c deleted file mode 100644 index 430bc630e..000000000 --- a/busybox/gunzip.c +++ /dev/null @@ -1,183 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Gzip implementation for busybox - * - * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly. - * - * Originally adjusted for busybox by Sven Rudolph - * based on gzip sources - * - * Adjusted further by Erik Andersen , - * to support files as well as stdin/stdout, and to generally behave itself wrt - * command line handling. - * - * General cleanup to better adhere to the style guide and make use of standard - * busybox functions by 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 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 - * - * - * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface - * Copyright (C) 1992-1993 Jean-loup Gailly - * The unzip code was written and put in the public domain by Mark Adler. - * Portions of the lzw code are derived from the public domain 'compress' - * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, - * Ken Turkowski, Dave Mack and Peter Jannesen. - * - * See the license_msg below and the file COPYING for the software license. - * See the file algorithm.doc for the compression algorithms and file formats. - */ - -#if 0 -static char *license_msg[] = { - " Copyright (C) 1992-1993 Jean-loup Gailly", - " 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., 675 Mass Ave, Cambridge, MA 02139, USA.", - 0 -}; -#endif - -#include -#include -#include -#include -#include "busybox.h" - -extern int gunzip_main(int argc, char **argv) -{ - FILE *in_file = stdin; - FILE *out_file = NULL; - struct stat stat_buf; - - char *if_name = NULL; - char *of_name = NULL; - char *delete_file_name = NULL; - - const int gunzip_to_stdout = 1; - const int gunzip_force = 2; - const int gunzip_test = 4; - - int flags = 0; - int opt = 0; - int delete_old_file = FALSE; - - /* if called as zcat */ - if (strcmp(applet_name, "zcat") == 0) - flags |= gunzip_to_stdout; - - while ((opt = getopt(argc, argv, "ctfhdq")) != -1) { - switch (opt) { - case 'c': - flags |= gunzip_to_stdout; - break; - case 'f': - flags |= gunzip_force; - break; - case 't': - flags |= gunzip_test; - break; - case 'd': /* Used to convert gzip to gunzip. */ - break; - case 'q': - error_msg("-q option not supported, ignored"); - break; - case 'h': - default: - show_usage(); /* exit's inside usage */ - } - } - - /* Set input filename and number */ - if (argv[optind] == NULL || strcmp(argv[optind], "-") == 0) { - flags |= gunzip_to_stdout; - } else { - if_name = strdup(argv[optind]); - /* Open input file */ - in_file = xfopen(if_name, "r"); - - /* set the buffer size */ - setvbuf(in_file, NULL, _IOFBF, 0x8000); - - /* Get the time stamp on the input file. */ - if (stat(if_name, &stat_buf) < 0) { - error_msg_and_die("Couldn't stat file %s", if_name); - } - } - - /* Check that the input is sane. */ - if (isatty(fileno(in_file)) && (flags & gunzip_force) == 0) - error_msg_and_die("compressed data not read from terminal. Use -f to force it."); - - /* Set output filename and number */ - if (flags & gunzip_test) { - out_file = xfopen("/dev/null", "w"); /* why does test use filenum 2 ? */ - } else if (flags & gunzip_to_stdout) { - out_file = stdout; - } else { - char *extension; - int length = strlen(if_name); - - delete_old_file = TRUE; - extension = strrchr(if_name, '.'); - if (extension && strcmp(extension, ".gz") == 0) { - length -= 3; - } else if (extension && strcmp(extension, ".tgz") == 0) { - length -= 4; - } else { - error_msg_and_die("Invalid extension"); - } - of_name = (char *) xcalloc(sizeof(char), length + 1); - strncpy(of_name, if_name, length); - - /* Open output file */ - out_file = xfopen(of_name, "w"); - - /* Set permissions on the file */ - chmod(of_name, stat_buf.st_mode); - } - - /* do the decompression, and cleanup */ - if (unzip(in_file, out_file) == 0) { - /* Success, remove .gz file */ - delete_file_name = if_name; - } else { - /* remove failed attempt */ - delete_file_name = of_name; - } - - fclose(out_file); - fclose(in_file); - - if (delete_old_file == TRUE) { - if (unlink(delete_file_name) < 0) { - error_msg_and_die("Couldnt remove %s", delete_file_name); - } - } - - free(of_name); - - return(EXIT_SUCCESS); -} diff --git a/busybox/gzip.c b/busybox/gzip.c deleted file mode 100644 index 54bb72745..000000000 --- a/busybox/gzip.c +++ /dev/null @@ -1,2550 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Gzip implementation for busybox - * - * Based on GNU gzip Copyright (C) 1992-1993 Jean-loup Gailly. - * - * Originally adjusted for busybox by Charles P. Wright - * "this is a stripped down version of gzip I put into busybox, it does - * only standard in to standard out with -9 compression. It also requires - * the zcat module for some important functions." - * - * Adjusted further by Erik Andersen , - * to support files as well as stdin/stdout, and to generally behave itself wrt - * command line handling. - * - * 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 - * - */ - -/* These defines are very important for BusyBox. Without these, - * huge chunks of ram are pre-allocated making the BusyBox bss - * size Freaking Huge(tm), which is a bad thing.*/ -#define SMALL_MEM -#define DYN_ALLOC - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#define memzero(s, n) memset ((void *)(s), 0, (n)) - -#ifndef RETSIGTYPE -# define RETSIGTYPE void -#endif - -typedef unsigned char uch; -typedef unsigned short ush; -typedef unsigned long ulg; - -/* Return codes from gzip */ -#define OK 0 -#define ERROR 1 -#define WARNING 2 - -/* Compression methods (see algorithm.doc) */ -/* Only STORED and DEFLATED are supported by this BusyBox module */ -#define STORED 0 -/* methods 4 to 7 reserved */ -#define DEFLATED 8 -static int method; /* compression method */ - -/* To save memory for 16 bit systems, some arrays are overlaid between - * the various modules: - * deflate: prev+head window d_buf l_buf outbuf - * unlzw: tab_prefix tab_suffix stack inbuf outbuf - * For compression, input is done in window[]. For decompression, output - * is done in window except for unlzw. - */ - -#ifndef INBUFSIZ -# ifdef SMALL_MEM -# define INBUFSIZ 0x2000 /* input buffer size */ -# else -# define INBUFSIZ 0x8000 /* input buffer size */ -# endif -#endif -#define INBUF_EXTRA 64 /* required by unlzw() */ - -#ifndef OUTBUFSIZ -# ifdef SMALL_MEM -# define OUTBUFSIZ 8192 /* output buffer size */ -# else -# define OUTBUFSIZ 16384 /* output buffer size */ -# endif -#endif -#define OUTBUF_EXTRA 2048 /* required by unlzw() */ - -#ifndef DIST_BUFSIZE -# ifdef SMALL_MEM -# define DIST_BUFSIZE 0x2000 /* buffer for distances, see trees.c */ -# else -# define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */ -# endif -#endif - -#ifdef DYN_ALLOC -# define DECLARE(type, array, size) static type * array -# define ALLOC(type, array, size) { \ - array = (type*)calloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \ - if (array == NULL) error_msg(memory_exhausted); \ - } -# define FREE(array) {if (array != NULL) free(array), array=NULL;} -#else -# define DECLARE(type, array, size) static type array[size] -# define ALLOC(type, array, size) -# define FREE(array) -#endif - -#define tab_suffix window -#define tab_prefix prev /* hash link (see deflate.c) */ -#define head (prev+WSIZE) /* hash head (see deflate.c) */ - -static long bytes_in; /* number of input bytes */ - -#define isize bytes_in -/* for compatibility with old zip sources (to be cleaned) */ - -typedef int file_t; /* Do not use stdio */ - -#define NO_FILE (-1) /* in memory compression */ - - -#define PACK_MAGIC "\037\036" /* Magic header for packed files */ -#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */ -#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */ -#define LZH_MAGIC "\037\240" /* Magic header for SCO LZH Compress files */ -#define PKZIP_MAGIC "\120\113\003\004" /* Magic header for pkzip files */ - -/* gzip flag byte */ -#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ -#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ -#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define COMMENT 0x10 /* bit 4 set: file comment present */ -#define RESERVED 0xC0 /* bit 6,7: reserved */ - -/* internal file attribute */ -#define UNKNOWN 0xffff -#define BINARY 0 -#define ASCII 1 - -#ifndef WSIZE -# define WSIZE 0x8000 /* window size--must be a power of two, and */ -#endif /* at least 32K for zip's deflate method */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST (WSIZE-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - -/* put_byte is used for the compressed output */ -#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\ - flush_outbuf();} - -/* Output a 16 bit value, lsb first */ -#define put_short(w) \ -{ if (outcnt < OUTBUFSIZ-2) { \ - outbuf[outcnt++] = (uch) ((w) & 0xff); \ - outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \ - } else { \ - put_byte((uch)((w) & 0xff)); \ - put_byte((uch)((ush)(w) >> 8)); \ - } \ -} - -/* Output a 32 bit value to the bit stream, lsb first */ -#define put_long(n) { \ - put_short((n) & 0xffff); \ - put_short(((ulg)(n)) >> 16); \ -} - -#define seekable() 0 /* force sequential output */ -#define translate_eol 0 /* no option -a yet */ - -/* Diagnostic functions */ -#ifdef DEBUG -# define Assert(cond,msg) {if(!(cond)) error_msg(msg);} -# define Trace(x) fprintf x -# define Tracev(x) {if (verbose) fprintf x ;} -# define Tracevv(x) {if (verbose>1) fprintf x ;} -# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} -# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - -#define WARN(msg) {if (!quiet) fprintf msg ; \ - if (exit_code == OK) exit_code = WARNING;} - -#ifndef MAX_PATH_LEN -# define MAX_PATH_LEN 1024 /* max pathname length */ -#endif - - - - /* from zip.c: */ -static int zip (int in, int out); -static int file_read (char *buf, unsigned size); - - /* from gzip.c */ -static RETSIGTYPE abort_gzip (void); - - /* from deflate.c */ -static void lm_init (ush * flags); -static ulg deflate (void); - - /* from trees.c */ -static void ct_init (ush * attr, int *methodp); -static int ct_tally (int dist, int lc); -static ulg flush_block (char *buf, ulg stored_len, int eof); - - /* from bits.c */ -static void bi_init (file_t zipfile); -static void send_bits (int value, int length); -static unsigned bi_reverse (unsigned value, int length); -static void bi_windup (void); -static void copy_block (char *buf, unsigned len, int header); -static int (*read_buf) (char *buf, unsigned size); - - /* from util.c: */ -static void flush_outbuf (void); - -/* lzw.h -- define the lzw functions. - * Copyright (C) 1992-1993 Jean-loup Gailly. - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License, see the file COPYING. - */ - -#if !defined(OF) && defined(lint) -# include "gzip.h" -#endif - -#ifndef BITS -# define BITS 16 -#endif -#define INIT_BITS 9 /* Initial number of bits per code */ - -#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */ -/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free. - * It's a pity that old uncompress does not check bit 0x20. That makes - * extension of the format actually undesirable because old compress - * would just crash on the new format instead of giving a meaningful - * error message. It does check the number of bits, but it's more - * helpful to say "unsupported format, get a new version" than - * "can only handle 16 bits". - */ - -/* tailor.h -- target dependent definitions - * Copyright (C) 1992-1993 Jean-loup Gailly. - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License, see the file COPYING. - */ - -/* The target dependent definitions should be defined here only. - * The target dependent functions should be defined in tailor.c. - */ - - - /* Common defaults */ - -#ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ -#endif - -#ifndef PATH_SEP -# define PATH_SEP '/' -#endif - -#ifndef OPTIONS_VAR -# define OPTIONS_VAR "GZIP" -#endif - -#ifndef Z_SUFFIX -# define Z_SUFFIX ".gz" -#endif - -#ifdef MAX_EXT_CHARS -# define MAX_SUFFIX MAX_EXT_CHARS -#else -# define MAX_SUFFIX 30 -#endif - - /* global buffers */ - -DECLARE(uch, inbuf, INBUFSIZ + INBUF_EXTRA); -DECLARE(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA); -DECLARE(ush, d_buf, DIST_BUFSIZE); -DECLARE(uch, window, 2L * WSIZE); -DECLARE(ush, tab_prefix, 1L << BITS); - -static int crc_table_empty = 1; - -static int foreground; /* set if program run in foreground */ -static int method = DEFLATED; /* compression method */ -static int exit_code = OK; /* program exit code */ -static int part_nb; /* number of parts in .gz file */ -static long time_stamp; /* original time stamp (modification time) */ -static long ifile_size; /* input file size, -1 for devices (debug only) */ -static char z_suffix[MAX_SUFFIX + 1]; /* default suffix (can be set with --suffix) */ -static int z_len; /* strlen(z_suffix) */ - -static char ifname[MAX_PATH_LEN]; /* input file name */ -static char ofname[MAX_PATH_LEN]; /* output file name */ -static int ifd; /* input file descriptor */ -static int ofd; /* output file descriptor */ -static unsigned insize; /* valid bytes in inbuf */ -static unsigned outcnt; /* bytes in output buffer */ - -/* ======================================================================== - * Signal and error handler. - */ -static void abort_gzip() -{ - exit(ERROR); -} - -/* =========================================================================== - * Clear input and output buffers - */ -static void clear_bufs(void) -{ - outcnt = 0; - insize = 0; - bytes_in = 0L; -} - -static void write_error_msg() -{ - fprintf(stderr, "\n"); - perror(""); - abort_gzip(); -} - -/* =========================================================================== - * Does the same as write(), but also handles partial pipe writes and checks - * for error return. - */ -static void write_buf(int fd, void *buf, unsigned cnt) -{ - unsigned n; - - while ((n = write(fd, buf, cnt)) != cnt) { - if (n == (unsigned) (-1)) { - write_error_msg(); - } - cnt -= n; - buf = (void *) ((char *) buf + n); - } -} - -/* =========================================================================== - * Run a set of bytes through the crc shift register. If s is a NULL - * pointer, then initialize the crc shift register contents instead. - * Return the current crc in either case. - */ -static ulg updcrc(uch *s, unsigned n) -{ - static ulg crc = (ulg) 0xffffffffL; /* shift register contents */ - register ulg c; /* temporary variable */ - static unsigned long crc_32_tab[256]; - if (crc_table_empty) { - unsigned long csr; /* crc shift register */ - unsigned long e=0; /* polynomial exclusive-or pattern */ - int i; /* counter for all possible eight bit values */ - int k; /* byte being shifted into crc apparatus */ - - /* terms of polynomial defining this crc (except x^32): */ - static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* Make exclusive-or pattern from polynomial (0xedb88320) */ - for (i = 0; i < sizeof(p)/sizeof(int); i++) - e |= 1L << (31 - p[i]); - - /* Compute and print table of CRC's, five per line */ - crc_32_tab[0] = 0x00000000L; - for (i = 1; i < 256; i++) { - csr = i; - /* The idea to initialize the register with the byte instead of - * zero was stolen from Haruhiko Okumura's ar002 - */ - for (k = 8; k; k--) - csr = csr & 1 ? (csr >> 1) ^ e : csr >> 1; - crc_32_tab[i]=csr; - } - } - - if (s == NULL) { - c = 0xffffffffL; - } else { - c = crc; - if (n) - do { - c = crc_32_tab[((int) c ^ (*s++)) & 0xff] ^ (c >> 8); - } while (--n); - } - crc = c; - return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */ -} - -/* bits.c -- output variable-length bit strings - * Copyright (C) 1992-1993 Jean-loup Gailly - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License, see the file COPYING. - */ - - -/* - * PURPOSE - * - * Output variable-length bit strings. Compression can be done - * to a file or to memory. (The latter is not supported in this version.) - * - * DISCUSSION - * - * The PKZIP "deflate" file format interprets compressed file data - * as a sequence of bits. Multi-bit strings in the file may cross - * byte boundaries without restriction. - * - * The first bit of each byte is the low-order bit. - * - * The routines in this file allow a variable-length bit value to - * be output right-to-left (useful for literal values). For - * left-to-right output (useful for code strings from the tree routines), - * the bits must have been reversed first with bi_reverse(). - * - * For in-memory compression, the compressed bit stream goes directly - * into the requested output buffer. The input data is read in blocks - * by the mem_read() function. The buffer is limited to 64K on 16 bit - * machines. - * - * INTERFACE - * - * void bi_init (FILE *zipfile) - * Initialize the bit string routines. - * - * void send_bits (int value, int length) - * Write out a bit string, taking the source bits right to - * left. - * - * int bi_reverse (int value, int length) - * Reverse the bits of a bit string, taking the source bits left to - * right and emitting them right to left. - * - * void bi_windup (void) - * Write out any remaining bits in an incomplete byte. - * - * void copy_block(char *buf, unsigned len, int header) - * Copy a stored block to the zip file, storing first the length and - * its one's complement if requested. - * - */ - -/* =========================================================================== - * Local data used by the "bit string" routines. - */ - -static file_t zfile; /* output gzip file */ - -static unsigned short bi_buf; - -/* Output buffer. bits are inserted starting at the bottom (least significant - * bits). - */ - -#define Buf_size (8 * 2*sizeof(char)) -/* Number of bits used within bi_buf. (bi_buf might be implemented on - * more than 16 bits on some systems.) - */ - -static int bi_valid; - -/* Current input function. Set to mem_read for in-memory compression */ - -#ifdef DEBUG -ulg bits_sent; /* bit length of the compressed data */ -#endif - -/* =========================================================================== - * Initialize the bit string routines. - */ -static void bi_init(file_t zipfile) -{ - zfile = zipfile; - bi_buf = 0; - bi_valid = 0; -#ifdef DEBUG - bits_sent = 0L; -#endif - - /* Set the defaults for file compression. They are set by memcompress - * for in-memory compression. - */ - if (zfile != NO_FILE) { - read_buf = file_read; - } -} - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -static void send_bits(int value, int length) -{ -#ifdef DEBUG - Tracev((stderr, " l %2d v %4x ", length, value)); - Assert(length > 0 && length <= 15, "invalid length"); - bits_sent += (ulg) length; -#endif - /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) - * unused bits in value. - */ - if (bi_valid > (int) Buf_size - length) { - bi_buf |= (value << bi_valid); - put_short(bi_buf); - bi_buf = (ush) value >> (Buf_size - bi_valid); - bi_valid += length - Buf_size; - } else { - bi_buf |= value << bi_valid; - bi_valid += length; - } -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -static unsigned bi_reverse(unsigned code, int len) -{ - register unsigned res = 0; - - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Write out any remaining bits in an incomplete byte. - */ -static void bi_windup() -{ - if (bi_valid > 8) { - put_short(bi_buf); - } else if (bi_valid > 0) { - put_byte(bi_buf); - } - bi_buf = 0; - bi_valid = 0; -#ifdef DEBUG - bits_sent = (bits_sent + 7) & ~7; -#endif -} - -/* =========================================================================== - * Copy a stored block to the zip file, storing first the length and its - * one's complement if requested. - */ -static void copy_block(char *buf, unsigned len, int header) -{ - bi_windup(); /* align on byte boundary */ - - if (header) { - put_short((ush) len); - put_short((ush) ~ len); -#ifdef DEBUG - bits_sent += 2 * 16; -#endif - } -#ifdef DEBUG - bits_sent += (ulg) len << 3; -#endif - while (len--) { - put_byte(*buf++); - } -} - -/* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1992-1993 Jean-loup Gailly - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License, see the file COPYING. - */ - -/* - * PURPOSE - * - * Identify new text as repetitions of old text within a fixed- - * length sliding window trailing behind the new text. - * - * DISCUSSION - * - * The "deflation" process depends on being able to identify portions - * of the input text which are identical to earlier input (within a - * sliding window trailing behind the input currently being processed). - * - * The most straightforward technique turns out to be the fastest for - * most input files: try all possible matches and select the longest. - * The key feature of this algorithm is that insertions into the string - * dictionary are very simple and thus fast, and deletions are avoided - * completely. Insertions are performed at each input character, whereas - * string matches are performed only when the previous match ends. So it - * is preferable to spend more time in matches to allow very fast string - * insertions and avoid deletions. The matching algorithm for small - * strings is inspired from that of Rabin & Karp. A brute force approach - * is used to find longer strings when a small match has been found. - * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze - * (by Leonid Broukhis). - * A previous version of this file used a more sophisticated algorithm - * (by Fiala and Greene) which is guaranteed to run in linear amortized - * time, but has a larger average cost, uses more memory and is patented. - * However the F&G algorithm may be faster for some highly redundant - * files if the parameter max_chain_length (described below) is too large. - * - * ACKNOWLEDGEMENTS - * - * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and - * I found it in 'freeze' written by Leonid Broukhis. - * Thanks to many info-zippers for bug reports and testing. - * - * REFERENCES - * - * APPNOTE.TXT documentation file in PKZIP 1.93a distribution. - * - * A description of the Rabin and Karp algorithm is given in the book - * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. - * - * Fiala,E.R., and Greene,D.H. - * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 - * - * INTERFACE - * - * void lm_init (int pack_level, ush *flags) - * Initialize the "longest match" routines for a new file - * - * ulg deflate (void) - * Processes a new input file and return its compressed length. Sets - * the compressed length, crc, deflate flags and internal file - * attributes. - */ - - -/* =========================================================================== - * Configuration parameters - */ - -/* Compile with MEDIUM_MEM to reduce the memory requirements or - * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the - * entire input file can be held in memory (not possible on 16 bit systems). - * Warning: defining these symbols affects HASH_BITS (see below) and thus - * affects the compression ratio. The compressed output - * is still correct, and might even be smaller in some cases. - */ - -#ifdef SMALL_MEM -# define HASH_BITS 13 /* Number of bits used to hash strings */ -#endif -#ifdef MEDIUM_MEM -# define HASH_BITS 14 -#endif -#ifndef HASH_BITS -# define HASH_BITS 15 - /* For portability to 16 bit machines, do not use values above 15. */ -#endif - -/* To save space (see unlzw.c), we overlay prev+head with tab_prefix and - * window with tab_suffix. Check that we can do this: - */ -#if (WSIZE<<1) > (1< BITS-1 -# error cannot overlay head with tab_prefix1 -#endif -#define HASH_SIZE (unsigned)(1<= HASH_BITS - */ - -static unsigned int prev_length; - -/* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - -static unsigned strstart; /* start of string to insert */ -static unsigned match_start; /* start of matching string */ -static int eofile; /* flag set at end of input file */ -static unsigned lookahead; /* number of valid bytes ahead in window */ - -static const unsigned max_chain_length=4096; - -/* To speed up deflation, hash chains are never searched beyond this length. - * A higher limit improves compression ratio but degrades the speed. - */ - -static const unsigned int max_lazy_match=258; - -/* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ -#define max_insert_length max_lazy_match -/* Insert new strings in the hash table only if the match length - * is not greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - -static const unsigned good_match=32; - -/* Use a faster search when the previous match is longer than this */ - - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ - -static const int nice_match=258; /* Stop searching when current match exceeds this */ - -/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 - * For deflate_fast() (levels <= 3) good is ignored and lazy has a different - * meaning. - */ - -#define EQUAL 0 -/* result of memcmp for equal strings */ - -/* =========================================================================== - * Prototypes for local functions. - */ -static void fill_window (void); - -static int longest_match (IPos cur_match); - -#ifdef DEBUG -static void check_match (IPos start, IPos match, int length); -#endif - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. - */ -#define UPDATE_HASH(h,c) (h = (((h)<= 1 - */ - -/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or - * match.s. The code is functionally equivalent, so you can use the C version - * if desired. - */ -static int longest_match(IPos cur_match) -{ - unsigned chain_length = max_chain_length; /* max hash chain length */ - register uch *scan = window + strstart; /* current string */ - register uch *match; /* matched string */ - register int len; /* length of current match */ - int best_len = prev_length; /* best match length so far */ - IPos limit = - - strstart > (IPos) MAX_DIST ? strstart - (IPos) MAX_DIST : NIL; - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - -/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ -#if HASH_BITS < 8 || MAX_MATCH != 258 -# error Code too clever -#endif - register uch *strend = window + strstart + MAX_MATCH; - register uch scan_end1 = scan[best_len - 1]; - register uch scan_end = scan[best_len]; - - /* Do not waste too much time if we already have a good match: */ - if (prev_length >= good_match) { - chain_length >>= 2; - } - Assert(strstart <= window_size - MIN_LOOKAHEAD, - "insufficient lookahead"); - - do { - Assert(cur_match < strstart, "no future"); - match = window + cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2: - */ - if (match[best_len] != scan_end || - match[best_len - 1] != scan_end1 || - *match != *scan || *++match != scan[1]) - continue; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match++; - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - len = MAX_MATCH - (int) (strend - scan); - scan = strend - MAX_MATCH; - - if (len > best_len) { - match_start = cur_match; - best_len = len; - if (len >= nice_match) - break; - scan_end1 = scan[best_len - 1]; - scan_end = scan[best_len]; - } - } while ((cur_match = prev[cur_match & WMASK]) > limit - && --chain_length != 0); - - return best_len; -} - -#ifdef DEBUG -/* =========================================================================== - * Check that the match at match_start is indeed a match. - */ -static void check_match(IPos start, IPos match, int length) -{ - /* check that the match is indeed a match */ - if (memcmp((char *) window + match, - (char *) window + start, length) != EQUAL) { - fprintf(stderr, - " start %d, match %d, length %d\n", start, match, length); - error_msg("invalid match"); - } - if (verbose > 1) { - fprintf(stderr, "\\[%d,%d]", start - match, length); - do { - putc(window[start++], stderr); - } while (--length != 0); - } -} -#else -# define check_match(start, match, length) -#endif - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead, and sets eofile if end of input file. - * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0 - * OUT assertions: at least one byte has been read, or eofile is set; - * file reads are performed for at least two bytes (required for the - * translate_eol option). - */ -static void fill_window() -{ - register unsigned n, m; - unsigned more = - - (unsigned) (window_size - (ulg) lookahead - (ulg) strstart); - /* Amount of free space at the end of the window. */ - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (more == (unsigned) EOF) { - /* Very unlikely, but possible on 16 bit machine if strstart == 0 - * and lookahead == 1 (input done one byte at time) - */ - more--; - } else if (strstart >= WSIZE + MAX_DIST) { - /* By the IN assertion, the window is not empty so we can't confuse - * more == 0 with more == 64K on a 16 bit machine. - */ - Assert(window_size == (ulg) 2 * WSIZE, "no sliding with BIG_MEM"); - - memcpy((char *) window, (char *) window + WSIZE, (unsigned) WSIZE); - match_start -= WSIZE; - strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */ - - block_start -= (long) WSIZE; - - for (n = 0; n < HASH_SIZE; n++) { - m = head[n]; - head[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL); - } - for (n = 0; n < WSIZE; n++) { - m = prev[n]; - prev[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } - more += WSIZE; - } - /* At this point, more >= 2 */ - if (!eofile) { - n = read_buf((char *) window + strstart + lookahead, more); - if (n == 0 || n == (unsigned) EOF) { - eofile = 1; - } else { - lookahead += n; - } - } -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK(eof) \ - flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \ - (char*)NULL, (long)strstart - block_start, (eof)) - -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -static ulg deflate() -{ - IPos hash_head; /* head of hash chain */ - IPos prev_match; /* previous match */ - int flush; /* set if current block must be flushed */ - int match_available = 0; /* set if previous match exists */ - register unsigned match_length = MIN_MATCH - 1; /* length of best match */ - - /* Process the input block. */ - while (lookahead != 0) { - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - INSERT_STRING(strstart, hash_head); - - /* Find the longest match, discarding those <= prev_length. - */ - prev_length = match_length, prev_match = match_start; - match_length = MIN_MATCH - 1; - - if (hash_head != NIL && prev_length < max_lazy_match && - strstart - hash_head <= MAX_DIST) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - match_length = longest_match(hash_head); - /* longest_match() sets match_start */ - if (match_length > lookahead) - match_length = lookahead; - - /* Ignore a length 3 match if it is too distant: */ - if (match_length == MIN_MATCH - && strstart - match_start > TOO_FAR) { - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - match_length--; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (prev_length >= MIN_MATCH && match_length <= prev_length) { - - check_match(strstart - 1, prev_match, prev_length); - - flush = - ct_tally(strstart - 1 - prev_match, - prev_length - MIN_MATCH); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. - */ - lookahead -= prev_length - 1; - prev_length -= 2; - do { - strstart++; - INSERT_STRING(strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH - * these bytes are garbage, but it does not matter since the - * next lookahead bytes will always be emitted as literals. - */ - } while (--prev_length != 0); - match_available = 0; - match_length = MIN_MATCH - 1; - strstart++; - if (flush) - FLUSH_BLOCK(0), block_start = strstart; - - } else if (match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - Tracevv((stderr, "%c", window[strstart - 1])); - if (ct_tally(0, window[strstart - 1])) { - FLUSH_BLOCK(0), block_start = strstart; - } - strstart++; - lookahead--; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - match_available = 1; - strstart++; - lookahead--; - } - Assert(strstart <= isize && lookahead <= isize, "a bit too far"); - - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - while (lookahead < MIN_LOOKAHEAD && !eofile) - fill_window(); - } - if (match_available) - ct_tally(0, window[strstart - 1]); - - return FLUSH_BLOCK(1); /* eof */ -} - -/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface - * Copyright (C) 1992-1993 Jean-loup Gailly - * The unzip code was written and put in the public domain by Mark Adler. - * Portions of the lzw code are derived from the public domain 'compress' - * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, - * Ken Turkowski, Dave Mack and Peter Jannesen. - * - * See the license_msg below and the file COPYING for the software license. - * See the file algorithm.doc for the compression algorithms and file formats. - */ - -/* Compress files with zip algorithm and 'compress' interface. - * See usage() and help() functions below for all options. - * Outputs: - * file.gz: compressed file with same mode, owner, and utimes - * or stdout with -c option or if stdin used as input. - * If the output file name had to be truncated, the original name is kept - * in the compressed file. - */ - - /* configuration */ - -typedef struct dirent dir_type; - -typedef RETSIGTYPE(*sig_type) (int); - - -/* ======================================================================== */ -// int main (argc, argv) -// int argc; -// char **argv; -int gzip_main(int argc, char **argv) -{ - int result; - int inFileNum; - int outFileNum; - struct stat statBuf; - char *delFileName; - int tostdout = 0; - int fromstdin = 0; - int force = 0; - int opt; - - while ((opt = getopt(argc, argv, "cf123456789dq")) != -1) { - switch (opt) { - case 'c': - tostdout = 1; - break; - case 'f': - force = 1; - break; - /* Ignore 1-9 (compression level) options */ - case '1': case '2': case '3': case '4': case '5': - case '6': case '7': case '8': case '9': - break; - case 'q': - break; -#ifdef BB_GUNZIP - case 'd': - optind = 1; - return gunzip_main(argc, argv); -#endif - default: - show_usage(); - } - } - if ((optind == argc) || (strcmp(argv[optind], "-") == 0)) { - fromstdin = 1; - tostdout = 1; - } - - if (isatty(fileno(stdout)) && tostdout==1 && force==0) - error_msg_and_die( "compressed data not written to terminal. Use -f to force it."); - - foreground = signal(SIGINT, SIG_IGN) != SIG_IGN; - if (foreground) { - (void) signal(SIGINT, (sig_type) abort_gzip); - } -#ifdef SIGTERM - if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { - (void) signal(SIGTERM, (sig_type) abort_gzip); - } -#endif -#ifdef SIGHUP - if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { - (void) signal(SIGHUP, (sig_type) abort_gzip); - } -#endif - - strncpy(z_suffix, Z_SUFFIX, sizeof(z_suffix) - 1); - z_len = strlen(z_suffix); - - /* Allocate all global buffers (for DYN_ALLOC option) */ - ALLOC(uch, inbuf, INBUFSIZ + INBUF_EXTRA); - ALLOC(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA); - ALLOC(ush, d_buf, DIST_BUFSIZE); - ALLOC(uch, window, 2L * WSIZE); - ALLOC(ush, tab_prefix, 1L << BITS); - - if (fromstdin == 1) { - strcpy(ofname, "stdin"); - - inFileNum = fileno(stdin); - time_stamp = 0; /* time unknown by default */ - ifile_size = -1L; /* convention for unknown size */ - } else { - /* Open up the input file */ - strncpy(ifname, argv[optind], MAX_PATH_LEN); - - /* Open input file */ - inFileNum = open(ifname, O_RDONLY); - if (inFileNum < 0) - perror_msg_and_die("%s", ifname); - /* Get the time stamp on the input file. */ - if (stat(ifname, &statBuf) < 0) - perror_msg_and_die("%s", ifname); - time_stamp = statBuf.st_ctime; - ifile_size = statBuf.st_size; - } - - - if (tostdout == 1) { - /* And get to work */ - strcpy(ofname, "stdout"); - outFileNum = fileno(stdout); - - clear_bufs(); /* clear input and output buffers */ - part_nb = 0; - - /* Actually do the compression/decompression. */ - zip(inFileNum, outFileNum); - - } else { - - /* And get to work */ - strncpy(ofname, ifname, MAX_PATH_LEN - 4); - strcat(ofname, ".gz"); - - - /* Open output fille */ -#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) - outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW); -#else - outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL); -#endif - if (outFileNum < 0) - perror_msg_and_die("%s", ofname); - /* Set permissions on the file */ - fchmod(outFileNum, statBuf.st_mode); - - clear_bufs(); /* clear input and output buffers */ - part_nb = 0; - - /* Actually do the compression/decompression. */ - result = zip(inFileNum, outFileNum); - close(outFileNum); - close(inFileNum); - /* Delete the original file */ - if (result == OK) - delFileName = ifname; - else - delFileName = ofname; - - if (unlink(delFileName) < 0) - perror_msg_and_die("%s", delFileName); - } - - return(exit_code); -} - -/* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1992-1993 Jean-loup Gailly - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License, see the file COPYING. - */ - -/* - * PURPOSE - * - * Encode various sets of source values using variable-length - * binary code trees. - * - * DISCUSSION - * - * The PKZIP "deflation" process uses several Huffman trees. The more - * common source values are represented by shorter bit sequences. - * - * Each code tree is stored in the ZIP file in a compressed form - * which is itself a Huffman encoding of the lengths of - * all the code strings (in ascending order by source values). - * The actual code strings are reconstructed from the lengths in - * the UNZIP process, as described in the "application note" - * (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program. - * - * REFERENCES - * - * Lynch, Thomas J. - * Data Compression: Techniques and Applications, pp. 53-55. - * Lifetime Learning Publications, 1985. ISBN 0-534-03418-7. - * - * Storer, James A. - * Data Compression: Methods and Theory, pp. 49-50. - * Computer Science Press, 1988. ISBN 0-7167-8156-5. - * - * Sedgewick, R. - * Algorithms, p290. - * Addison-Wesley, 1983. ISBN 0-201-06672-6. - * - * INTERFACE - * - * void ct_init (ush *attr, int *methodp) - * Allocate the match buffer, initialize the various tables and save - * the location of the internal file attribute (ascii/binary) and - * method (DEFLATE/STORE) - * - * void ct_tally (int dist, int lc); - * Save the match info and tally the frequency counts. - * - * long flush_block (char *buf, ulg stored_len, int eof) - * Determine the best encoding for the current block: dynamic trees, - * static trees or store, and output the encoded block to the zip - * file. Returns the total compressed length for the file so far. - * - */ - -/* =========================================================================== - * Constants - */ - -#define MAX_BITS 15 -/* All codes must not exceed MAX_BITS bits */ - -#define MAX_BL_BITS 7 -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -#define LENGTH_CODES 29 -/* number of length codes, not counting the special END_BLOCK code */ - -#define LITERALS 256 -/* number of literal bytes 0..255 */ - -#define END_BLOCK 256 -/* end of block literal code */ - -#define L_CODES (LITERALS+1+LENGTH_CODES) -/* number of Literal or Length codes, including the END_BLOCK code */ - -#define D_CODES 30 -/* number of distance codes */ - -#define BL_CODES 19 -/* number of codes used to transfer the bit lengths */ - - -static const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ - = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, - 4, 4, 5, 5, 5, 5, 0 }; - -static const int extra_dbits[D_CODES] /* extra bits for each distance code */ - = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, - 10, 10, 11, 11, 12, 12, 13, 13 }; - -static const int extra_blbits[BL_CODES] /* extra bits for each bit length code */ -= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 }; - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#ifndef LIT_BUFSIZE -# ifdef SMALL_MEM -# define LIT_BUFSIZE 0x2000 -# else -# ifdef MEDIUM_MEM -# define LIT_BUFSIZE 0x4000 -# else -# define LIT_BUFSIZE 0x8000 -# endif -# endif -#endif -#ifndef DIST_BUFSIZE -# define DIST_BUFSIZE LIT_BUFSIZE -#endif -/* Sizes of match buffers for literals/lengths and distances. There are - * 4 reasons for limiting LIT_BUFSIZE to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input data is - * still in the window so we can still emit a stored block even when input - * comes from standard input. (This can also be done for all blocks if - * LIT_BUFSIZE is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting trees - * more frequently. - * - I can't count above 4 - * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save - * memory at the expense of compression). Some optimizations would be possible - * if we rely on DIST_BUFSIZE == LIT_BUFSIZE. - */ -#if LIT_BUFSIZE > INBUFSIZ -error cannot overlay l_buf and inbuf -#endif -#define REP_3_6 16 -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ -#define REPZ_3_10 17 -/* repeat a zero length 3-10 times (3 bits of repeat count) */ -#define REPZ_11_138 18 -/* repeat a zero length 11-138 times (7 bits of repeat count) *//* =========================================================================== - * Local data - *//* Data structure describing a single value and its code string. */ typedef struct ct_data { - union { - ush freq; /* frequency count */ - ush code; /* bit string */ - } fc; - union { - ush dad; /* father node in Huffman tree */ - ush len; /* length of bit string */ - } dl; -} ct_data; - -#define Freq fc.freq -#define Code fc.code -#define Dad dl.dad -#define Len dl.len - -#define HEAP_SIZE (2*L_CODES+1) -/* maximum heap size */ - -static ct_data dyn_ltree[HEAP_SIZE]; /* literal and length tree */ -static ct_data dyn_dtree[2 * D_CODES + 1]; /* distance tree */ - -static ct_data static_ltree[L_CODES + 2]; - -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see ct_init - * below). - */ - -static ct_data static_dtree[D_CODES]; - -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -static ct_data bl_tree[2 * BL_CODES + 1]; - -/* Huffman tree for the bit lengths */ - -typedef struct tree_desc { - ct_data *dyn_tree; /* the dynamic tree */ - ct_data *static_tree; /* corresponding static tree or NULL */ - const int *extra_bits; /* extra bits for each code or NULL */ - int extra_base; /* base index for extra_bits */ - int elems; /* max number of elements in the tree */ - int max_length; /* max bit length for the codes */ - int max_code; /* largest code with non zero frequency */ -} tree_desc; - -static tree_desc l_desc = - { dyn_ltree, static_ltree, extra_lbits, LITERALS + 1, L_CODES, - MAX_BITS, 0 }; - -static tree_desc d_desc = - { dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0 }; - -static tree_desc bl_desc = - { bl_tree, (ct_data *) 0, extra_blbits, 0, BL_CODES, MAX_BL_BITS, - 0 }; - - -static ush bl_count[MAX_BITS + 1]; - -/* number of codes at each bit length for an optimal tree */ - -static const uch bl_order[BL_CODES] -= { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -static int heap[2 * L_CODES + 1]; /* heap used to build the Huffman trees */ -static int heap_len; /* number of elements in the heap */ -static int heap_max; /* element of largest frequency */ - -/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - -static uch depth[2 * L_CODES + 1]; - -/* Depth of each subtree used as tie breaker for trees of equal frequency */ - -static uch length_code[MAX_MATCH - MIN_MATCH + 1]; - -/* length code for each normalized match length (0 == MIN_MATCH) */ - -static uch dist_code[512]; - -/* distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -static int base_length[LENGTH_CODES]; - -/* First normalized length for each code (0 = MIN_MATCH) */ - -static int base_dist[D_CODES]; - -/* First normalized distance for each code (0 = distance of 1) */ - -#define l_buf inbuf -/* DECLARE(uch, l_buf, LIT_BUFSIZE); buffer for literals or lengths */ - -/* DECLARE(ush, d_buf, DIST_BUFSIZE); buffer for distances */ - -static uch flag_buf[(LIT_BUFSIZE / 8)]; - -/* flag_buf is a bit array distinguishing literals from lengths in - * l_buf, thus indicating the presence or absence of a distance. - */ - -static unsigned last_lit; /* running index in l_buf */ -static unsigned last_dist; /* running index in d_buf */ -static unsigned last_flags; /* running index in flag_buf */ -static uch flags; /* current flags not yet saved in flag_buf */ -static uch flag_bit; /* current bit used in flags */ - -/* bits are filled in flags starting at bit 0 (least significant). - * Note: these flags are overkill in the current code since we don't - * take advantage of DIST_BUFSIZE == LIT_BUFSIZE. - */ - -static ulg opt_len; /* bit length of current block with optimal trees */ -static ulg static_len; /* bit length of current block with static trees */ - -static ulg compressed_len; /* total bit length of compressed file */ - - -static ush *file_type; /* pointer to UNKNOWN, BINARY or ASCII */ -static int *file_method; /* pointer to DEFLATE or STORE */ - -/* =========================================================================== - * Local (static) routines in this file. - */ - -static void init_block (void); -static void pqdownheap (ct_data * tree, int k); -static void gen_bitlen (tree_desc * desc); -static void gen_codes (ct_data * tree, int max_code); -static void build_tree (tree_desc * desc); -static void scan_tree (ct_data * tree, int max_code); -static void send_tree (ct_data * tree, int max_code); -static int build_bl_tree (void); -static void send_all_trees (int lcodes, int dcodes, int blcodes); -static void compress_block (ct_data * ltree, ct_data * dtree); -static void set_file_type (void); - - -#ifndef DEBUG -# define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len) - /* Send a code of the given tree. c and tree must not have side effects */ - -#else /* DEBUG */ -# define send_code(c, tree) \ - { if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \ - send_bits(tree[c].Code, tree[c].Len); } -#endif - -#define d_code(dist) \ - ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. dist_code[256] and dist_code[257] are never - * used. - */ - -/* the arguments must not have side effects */ - -/* =========================================================================== - * Allocate the match buffer, initialize the various tables and save the - * location of the internal file attribute (ascii/binary) and method - * (DEFLATE/STORE). - */ -static void ct_init(ush *attr, int *methodp) -{ - int n; /* iterates over tree elements */ - int bits; /* bit counter */ - int length; /* length value */ - int code; /* code value */ - int dist; /* distance index */ - - file_type = attr; - file_method = methodp; - compressed_len = 0L; - - if (static_dtree[0].Len != 0) - return; /* ct_init already called */ - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES - 1; code++) { - base_length[code] = length; - for (n = 0; n < (1 << extra_lbits[code]); n++) { - length_code[length++] = (uch) code; - } - } - Assert(length == 256, "ct_init: length != 256"); - /* Note that the length 255 (match length 258) can be represented - * in two different ways: code 284 + 5 bits or code 285, so we - * overwrite length_code[255] to use the best encoding: - */ - length_code[length - 1] = (uch) code; - - /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ - dist = 0; - for (code = 0; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1 << extra_dbits[code]); n++) { - dist_code[dist++] = (uch) code; - } - } - Assert(dist == 256, "ct_init: dist != 256"); - dist >>= 7; /* from now on, all distances are divided by 128 */ - for (; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { - dist_code[256 + dist++] = (uch) code; - } - } - Assert(dist == 256, "ct_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) - bl_count[bits] = 0; - n = 0; - while (n <= 143) - static_ltree[n++].Len = 8, bl_count[8]++; - while (n <= 255) - static_ltree[n++].Len = 9, bl_count[9]++; - while (n <= 279) - static_ltree[n++].Len = 7, bl_count[7]++; - while (n <= 287) - static_ltree[n++].Len = 8, bl_count[8]++; - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes((ct_data *) static_ltree, L_CODES + 1); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n].Len = 5; - static_dtree[n].Code = bi_reverse(n, 5); - } - - /* Initialize the first block of the first file: */ - init_block(); -} - -/* =========================================================================== - * Initialize a new block. - */ -static void init_block() -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) - dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) - dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) - bl_tree[n].Freq = 0; - - dyn_ltree[END_BLOCK].Freq = 1; - opt_len = static_len = 0L; - last_lit = last_dist = last_flags = 0; - flags = 0; - flag_bit = 1; -} - -#define SMALLEST 1 -/* Index within the heap array of least frequent node in the Huffman tree */ - - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. - */ -#define pqremove(tree, top) \ -{\ - top = heap[SMALLEST]; \ - heap[SMALLEST] = heap[heap_len--]; \ - pqdownheap(tree, SMALLEST); \ -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -#define smaller(tree, n, m) \ - (tree[n].Freq < tree[m].Freq || \ - (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -static void pqdownheap(ct_data *tree, int k) -{ - int v = heap[k]; - int j = k << 1; /* left son of k */ - - while (j <= heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < heap_len && smaller(tree, heap[j + 1], heap[j])) - j++; - - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, heap[j])) - break; - - /* Exchange v with the smallest son */ - heap[k] = heap[j]; - k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - heap[k] = v; -} - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -static void gen_bitlen(tree_desc *desc) -{ - ct_data *tree = desc->dyn_tree; - const int *extra = desc->extra_bits; - int base = desc->extra_base; - int max_code = desc->max_code; - int max_length = desc->max_length; - ct_data *stree = desc->static_tree; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) - bl_count[bits] = 0; - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[heap[heap_max]].Len = 0; /* root of the heap */ - - for (h = heap_max + 1; h < HEAP_SIZE; h++) { - n = heap[h]; - bits = tree[tree[n].Dad].Len + 1; - if (bits > max_length) - bits = max_length, overflow++; - tree[n].Len = (ush) bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) - continue; /* not a leaf node */ - - bl_count[bits]++; - xbits = 0; - if (n >= base) - xbits = extra[n - base]; - f = tree[n].Freq; - opt_len += (ulg) f *(bits + xbits); - - if (stree) - static_len += (ulg) f *(stree[n].Len + xbits); - } - if (overflow == 0) - return; - - Trace((stderr, "\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length - 1; - while (bl_count[bits] == 0) - bits--; - bl_count[bits]--; /* move one leaf down the tree */ - bl_count[bits + 1] += 2; /* move one overflow item as its brother */ - bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits != 0; bits--) { - n = bl_count[bits]; - while (n != 0) { - m = heap[--h]; - if (m > max_code) - continue; - if (tree[m].Len != (unsigned) bits) { - Trace( - (stderr, "code %d bits %d->%d\n", m, tree[m].Len, - bits)); - opt_len += - ((long) bits - - (long) tree[m].Len) * (long) tree[m].Freq; - tree[m].Len = (ush) bits; - } - n--; - } - } -} - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -static void gen_codes(ct_data *tree, int max_code) -{ - ush next_code[MAX_BITS + 1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits - 1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert(code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, - "inconsistent bit counts"); - Tracev((stderr, "\ngen_codes: max_code %d ", max_code)); - - for (n = 0; n <= max_code; n++) { - int len = tree[n].Len; - - if (len == 0) - continue; - /* Now reverse the bits */ - tree[n].Code = bi_reverse(next_code[len]++, len); - - Tracec(tree != static_ltree, - (stderr, "\nn %3d %c l %2d c %4x (%x) ", n, - (isgraph(n) ? n : ' '), len, tree[n].Code, - next_code[len] - 1)); - } -} - -/* =========================================================================== - * Construct one Huffman tree and assigns the code bit strings and lengths. - * Update the total bit length for the current block. - * IN assertion: the field freq is set for all tree elements. - * OUT assertions: the fields len and code are set to the optimal bit length - * and corresponding code. The length opt_len is updated; static_len is - * also updated if stree is not null. The field max_code is set. - */ -static void build_tree(tree_desc *desc) -{ - ct_data *tree = desc->dyn_tree; - ct_data *stree = desc->static_tree; - int elems = desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node = elems; /* next internal node of the tree */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - heap_len = 0, heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].Freq != 0) { - heap[++heap_len] = max_code = n; - depth[n] = 0; - } else { - tree[n].Len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (heap_len < 2) { - int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0); - - tree[new].Freq = 1; - depth[new] = 0; - opt_len--; - if (stree) - static_len -= stree[new].Len; - /* new is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = heap_len / 2; n >= 1; n--) - pqdownheap(tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - do { - pqremove(tree, n); /* n = node of least frequency */ - m = heap[SMALLEST]; /* m = node of next least frequency */ - - heap[--heap_max] = n; /* keep the nodes sorted by frequency */ - heap[--heap_max] = m; - - /* Create a new node father of n and m */ - tree[node].Freq = tree[n].Freq + tree[m].Freq; - depth[node] = (uch) (MAX(depth[n], depth[m]) + 1); - tree[n].Dad = tree[m].Dad = (ush) node; -#ifdef DUMP_BL_TREE - if (tree == bl_tree) { - fprintf(stderr, "\nnode %d(%d), sons %d(%d) %d(%d)", - node, tree[node].Freq, n, tree[n].Freq, m, - tree[m].Freq); - } -#endif - /* and insert the new node in the heap */ - heap[SMALLEST] = node++; - pqdownheap(tree, SMALLEST); - - } while (heap_len >= 2); - - heap[--heap_max] = heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen((tree_desc *) desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes((ct_data *) tree, max_code); -} - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. Updates opt_len to take into account the repeat - * counts. (The contribution of the bit length codes will be added later - * during the construction of bl_tree.) - */ -static void scan_tree(ct_data *tree, int max_code) -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - if (nextlen == 0) - max_count = 138, min_count = 3; - tree[max_code + 1].Len = (ush) 0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[n + 1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - bl_tree[curlen].Freq += count; - } else if (curlen != 0) { - if (curlen != prevlen) - bl_tree[curlen].Freq++; - bl_tree[REP_3_6].Freq++; - } else if (count <= 10) { - bl_tree[REPZ_3_10].Freq++; - } else { - bl_tree[REPZ_11_138].Freq++; - } - count = 0; - prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -static void send_tree(ct_data *tree, int max_code) -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - -/* tree[max_code+1].Len = -1; *//* guard already set */ - if (nextlen == 0) - max_count = 138, min_count = 3; - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[n + 1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - do { - send_code(curlen, bl_tree); - } while (--count != 0); - - } else if (curlen != 0) { - if (curlen != prevlen) { - send_code(curlen, bl_tree); - count--; - } - Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(REP_3_6, bl_tree); - send_bits(count - 3, 2); - - } else if (count <= 10) { - send_code(REPZ_3_10, bl_tree); - send_bits(count - 3, 3); - - } else { - send_code(REPZ_11_138, bl_tree); - send_bits(count - 11, 7); - } - count = 0; - prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -static const int build_bl_tree() -{ - int max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree((ct_data *) dyn_ltree, l_desc.max_code); - scan_tree((ct_data *) dyn_dtree, d_desc.max_code); - - /* Build the bit length tree: */ - build_tree((tree_desc *) (&bl_desc)); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) { - if (bl_tree[bl_order[max_blindex]].Len != 0) - break; - } - /* Update opt_len to include the bit length tree and counts */ - opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; - Tracev( - (stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len, - static_len)); - - return max_blindex; -} - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -static void send_all_trees(int lcodes, int dcodes, int blcodes) -{ - int rank; /* index in bl_order */ - - Assert(lcodes >= 257 && dcodes >= 1 - && blcodes >= 4, "not enough codes"); - Assert(lcodes <= L_CODES && dcodes <= D_CODES - && blcodes <= BL_CODES, "too many codes"); - Tracev((stderr, "\nbl counts: ")); - send_bits(lcodes - 257, 5); /* not +255 as stated in appnote.txt */ - send_bits(dcodes - 1, 5); - send_bits(blcodes - 4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(bl_tree[bl_order[rank]].Len, 3); - } - Tracev((stderr, "\nbl tree: sent %ld", bits_sent)); - - send_tree((ct_data *) dyn_ltree, lcodes - 1); /* send the literal tree */ - Tracev((stderr, "\nlit tree: sent %ld", bits_sent)); - - send_tree((ct_data *) dyn_dtree, dcodes - 1); /* send the distance tree */ - Tracev((stderr, "\ndist tree: sent %ld", bits_sent)); -} - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. This function - * returns the total compressed length for the file so far. - */ -static ulg flush_block(char *buf, ulg stored_len, int eof) -{ - ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - int max_blindex; /* index of last bit length code of non zero freq */ - - flag_buf[last_flags] = flags; /* Save the flags for the last 8 items */ - - /* Check if the file is ascii or binary */ - if (*file_type == (ush) UNKNOWN) - set_file_type(); - - /* Construct the literal and distance trees */ - build_tree((tree_desc *) (&l_desc)); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len)); - - build_tree((tree_desc *) (&d_desc)); - Tracev( - (stderr, "\ndist data: dyn %ld, stat %ld", opt_len, - static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(); - - /* Determine the best encoding. Compute first the block length in bytes */ - opt_lenb = (opt_len + 3 + 7) >> 3; - static_lenb = (static_len + 3 + 7) >> 3; - - Trace( - (stderr, - "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ", - opt_lenb, opt_len, static_lenb, static_len, stored_len, - last_lit, last_dist)); - - if (static_lenb <= opt_lenb) - opt_lenb = static_lenb; - - /* If compression failed and this is the first and last block, - * and if the zip file can be seeked (to rewrite the local header), - * the whole file is transformed into a stored file: - */ - if (stored_len <= opt_lenb && eof && compressed_len == 0L - && seekable()) { - /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */ - if (buf == (char *) 0) - error_msg("block vanished"); - - copy_block(buf, (unsigned) stored_len, 0); /* without header */ - compressed_len = stored_len << 3; - *file_method = STORED; - - } else if (stored_len + 4 <= opt_lenb && buf != (char *) 0) { - /* 4: two words for the lengths */ - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - send_bits((STORED_BLOCK << 1) + eof, 3); /* send block type */ - compressed_len = (compressed_len + 3 + 7) & ~7L; - compressed_len += (stored_len + 4) << 3; - - copy_block(buf, (unsigned) stored_len, 1); /* with header */ - - } else if (static_lenb == opt_lenb) { - send_bits((STATIC_TREES << 1) + eof, 3); - compress_block((ct_data *) static_ltree, - (ct_data *) static_dtree); - compressed_len += 3 + static_len; - } else { - send_bits((DYN_TREES << 1) + eof, 3); - send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1, - max_blindex + 1); - compress_block((ct_data *) dyn_ltree, - (ct_data *) dyn_dtree); - compressed_len += 3 + opt_len; - } - Assert(compressed_len == bits_sent, "bad compressed size"); - init_block(); - - if (eof) { - bi_windup(); - compressed_len += 7; /* align on byte boundary */ - } - Tracev((stderr, "\ncomprlen %lu(%lu) ", compressed_len >> 3, - compressed_len - 7 * eof)); - - return compressed_len >> 3; -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -static int ct_tally(int dist, int lc) -{ - l_buf[last_lit++] = (uch) lc; - if (dist == 0) { - /* lc is the unmatched char */ - dyn_ltree[lc].Freq++; - } else { - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - Assert((ush) dist < (ush) MAX_DIST && - (ush) lc <= (ush) (MAX_MATCH - MIN_MATCH) && - (ush) d_code(dist) < (ush) D_CODES, "ct_tally: bad match"); - - dyn_ltree[length_code[lc] + LITERALS + 1].Freq++; - dyn_dtree[d_code(dist)].Freq++; - - d_buf[last_dist++] = (ush) dist; - flags |= flag_bit; - } - flag_bit <<= 1; - - /* Output the flags if they fill a byte: */ - if ((last_lit & 7) == 0) { - flag_buf[last_flags++] = flags; - flags = 0, flag_bit = 1; - } - /* Try to guess if it is profitable to stop the current block here */ - if ((last_lit & 0xfff) == 0) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg) last_lit * 8L; - ulg in_length = (ulg) strstart - block_start; - int dcode; - - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += - (ulg) dyn_dtree[dcode].Freq * (5L + extra_dbits[dcode]); - } - out_length >>= 3; - Trace( - (stderr, - "\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ", - last_lit, last_dist, in_length, out_length, - 100L - out_length * 100L / in_length)); - if (last_dist < last_lit / 2 && out_length < in_length / 2) - return 1; - } - return (last_lit == LIT_BUFSIZE - 1 || last_dist == DIST_BUFSIZE); - /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -static void compress_block(ct_data *ltree, ct_data *dtree) -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned dx = 0; /* running index in d_buf */ - unsigned fx = 0; /* running index in flag_buf */ - uch flag = 0; /* current flags */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (last_lit != 0) - do { - if ((lx & 7) == 0) - flag = flag_buf[fx++]; - lc = l_buf[lx++]; - if ((flag & 1) == 0) { - send_code(lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr, " '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = length_code[lc]; - send_code(code + LITERALS + 1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(lc, extra); /* send the extra length bits */ - } - dist = d_buf[dx++]; - /* Here, dist is the match distance - 1 */ - code = d_code(dist); - Assert(code < D_CODES, "bad d_code"); - - send_code(code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= base_dist[code]; - send_bits(dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - flag >>= 1; - } while (lx < last_lit); - - send_code(END_BLOCK, ltree); -} - -/* =========================================================================== - * Set the file type to ASCII or BINARY, using a crude approximation: - * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - * IN assertion: the fields freq of dyn_ltree are set and the total of all - * frequencies does not exceed 64K (to fit in an int on 16 bit machines). - */ -static void set_file_type() -{ - int n = 0; - unsigned ascii_freq = 0; - unsigned bin_freq = 0; - - while (n < 7) - bin_freq += dyn_ltree[n++].Freq; - while (n < 128) - ascii_freq += dyn_ltree[n++].Freq; - while (n < LITERALS) - bin_freq += dyn_ltree[n++].Freq; - *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII; - if (*file_type == BINARY && translate_eol) { - error_msg("-l used on binary file"); - } -} - -/* zip.c -- compress files to the gzip or pkzip format - * Copyright (C) 1992-1993 Jean-loup Gailly - * This is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License, see the file COPYING. - */ - - -static ulg crc; /* crc on uncompressed file data */ -static long header_bytes; /* number of bytes in gzip header */ - -/* =========================================================================== - * Deflate in to out. - * IN assertions: the input and output buffers are cleared. - * The variables time_stamp and save_orig_name are initialized. - */ -static int zip(int in, int out) -{ - uch my_flags = 0; /* general purpose bit flags */ - ush attr = 0; /* ascii/binary flag */ - ush deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */ - - ifd = in; - ofd = out; - outcnt = 0; - - /* Write the header to the gzip file. See algorithm.doc for the format */ - - - method = DEFLATED; - put_byte(GZIP_MAGIC[0]); /* magic header */ - put_byte(GZIP_MAGIC[1]); - put_byte(DEFLATED); /* compression method */ - - put_byte(my_flags); /* general flags */ - put_long(time_stamp); - - /* Write deflated file to zip file */ - crc = updcrc(0, 0); - - bi_init(out); - ct_init(&attr, &method); - lm_init(&deflate_flags); - - put_byte((uch) deflate_flags); /* extra flags */ - put_byte(OS_CODE); /* OS identifier */ - - header_bytes = (long) outcnt; - - (void) deflate(); - - /* Write the crc and uncompressed size */ - put_long(crc); - put_long(isize); - header_bytes += 2 * sizeof(long); - - flush_outbuf(); - return OK; -} - - -/* =========================================================================== - * Read a new buffer from the current input file, perform end-of-line - * translation, and update the crc and input file size. - * IN assertion: size >= 2 (for end-of-line translation) - */ -static int file_read(char *buf, unsigned size) -{ - unsigned len; - - Assert(insize == 0, "inbuf not empty"); - - len = read(ifd, buf, size); - if (len == (unsigned) (-1) || len == 0) - return (int) len; - - crc = updcrc((uch *) buf, len); - isize += (ulg) len; - return (int) len; -} - -/* =========================================================================== - * Write the output buffer outbuf[0..outcnt-1] and update bytes_out. - * (used for the compressed data only) - */ -static void flush_outbuf() -{ - if (outcnt == 0) - return; - - write_buf(ofd, (char *) outbuf, outcnt); - outcnt = 0; -} diff --git a/busybox/halt.c b/busybox/halt.c deleted file mode 100644 index d66e28d0e..000000000 --- a/busybox/halt.c +++ /dev/null @@ -1,41 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini halt implementation for busybox - * - * - * 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 - * - */ - -#include "busybox.h" -#include - -extern int halt_main(int argc, char **argv) -{ -#ifdef BB_FEATURE_LINUXRC - /* don't assume init's pid == 1 */ - pid_t *pid = find_pid_by_name("init"); - if (!pid || *pid<=0) { - pid = find_pid_by_name("linuxrc"); - if (!pid || *pid<=0) - error_msg_and_die("no process killed"); - } - return(kill(*pid, SIGUSR1)); -#else - return(kill(1, SIGUSR1)); -#endif -} diff --git a/busybox/head.c b/busybox/head.c deleted file mode 100644 index 688c250b1..000000000 --- a/busybox/head.c +++ /dev/null @@ -1,97 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini head implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by John Beppu - * - * 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 "busybox.h" - -static int head(int len, FILE *fp) -{ - int i; - char *input; - - for (i = 0; i < len; i++) { - if ((input = get_line_from_file(fp)) == NULL) - break; - fputs(input, stdout); - free(input); - } - return 0; -} - -/* BusyBoxed head(1) */ -int head_main(int argc, char **argv) -{ - FILE *fp; - int need_headers, opt, len = 10, status = EXIT_SUCCESS; - - /* parse argv[] */ - while ((opt = getopt(argc, argv, "n:")) > 0) { - switch (opt) { - case 'n': - len = atoi(optarg); - if (len >= 1) - break; - /* fallthrough */ - default: - show_usage(); - } - } - - /* get rest of argv[] or stdin if nothing's left */ - if (argv[optind] == NULL) { - head(len, stdin); - return status; - } - - need_headers = optind != (argc - 1); - while (argv[optind]) { - if (strcmp(argv[optind], "-") == 0) { - fp = stdin; - argv[optind] = "standard input"; - } else { - if ((fp = wfopen(argv[optind], "r")) == NULL) - status = EXIT_FAILURE; - } - if (fp) { - if (need_headers) { - printf("==> %s <==\n", argv[optind]); - } - head(len, fp); - if (ferror(fp)) { - perror_msg("%s", argv[optind]); - status = EXIT_FAILURE; - } - if (optind < argc - 1) - putchar('\n'); - if (fp != stdin) - fclose(fp); - } - optind++; - } - - return status; -} diff --git a/busybox/hostid.c b/busybox/hostid.c deleted file mode 100644 index 68a2cc659..000000000 --- a/busybox/hostid.c +++ /dev/null @@ -1,32 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini hostid implementation for busybox - * - * 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 - * - */ - -#include -#include -#include -#include "busybox.h" - -extern int hostid_main(int argc, char **argv) -{ - printf("%lx\n", gethostid()); - return EXIT_SUCCESS; -} diff --git a/busybox/hostname.c b/busybox/hostname.c deleted file mode 100644 index d87851509..000000000 --- a/busybox/hostname.c +++ /dev/null @@ -1,128 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * $Id: hostname.c,v 1.30 2001/06/26 02:06:08 bug1 Exp $ - * Mini hostname implementation for busybox - * - * Copyright (C) 1999 by Randolph Chung - * - * adjusted by Erik Andersen to remove - * use of long options and GNU getopt. Improved the usage info. - * - * 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 "busybox.h" - -static void do_sethostname(char *s, int isfile) -{ - FILE *f; - char buf[255]; - - if (!s) - return; - if (!isfile) { - if (sethostname(s, strlen(s)) < 0) { - if (errno == EPERM) - error_msg_and_die("you must be root to change the hostname"); - else - perror_msg_and_die("sethostname"); - } - } else { - f = xfopen(s, "r"); - fgets(buf, 255, f); -#ifdef BB_FEATURE_CLEAN_UP - fclose(f); -#endif - chomp(buf); - do_sethostname(buf, 0); - } -} - -int hostname_main(int argc, char **argv) -{ - int opt_short = 0; - int opt_domain = 0; - int opt_ip = 0; - struct hostent *h; - char *filename = NULL; - char buf[255]; - char *s = NULL; - - if (argc < 1) - show_usage(); - - while (--argc > 0 && **(++argv) == '-') { - while (*(++(*argv))) { - switch (**argv) { - case 's': - opt_short = 1; - break; - case 'i': - opt_ip = 1; - break; - case 'd': - opt_domain = 1; - break; - case 'F': - if (--argc == 0) { - show_usage(); - } - filename = *(++argv); - break; - case '-': - if (strcmp(++(*argv), "file") || --argc ==0 ) { - show_usage(); - } - filename = *(++argv); - break; - default: - show_usage(); - } - if (filename != NULL) - break; - } - } - - if (argc >= 1) { - do_sethostname(*argv, 0); - } else if (filename != NULL) { - do_sethostname(filename, 1); - } else { - gethostname(buf, 255); - if (opt_short) { - s = strchr(buf, '.'); - if (!s) - s = buf; - *s = 0; - puts(buf); - } else if (opt_domain) { - s = strchr(buf, '.'); - puts(s ? s + 1 : ""); - } else if (opt_ip) { - h = xgethostbyname(buf); - puts(inet_ntoa(*(struct in_addr *) (h->h_addr))); - } else { - puts(buf); - } - } - return(0); -} diff --git a/busybox/hush.c b/busybox/hush.c deleted file mode 100644 index 0e619f80e..000000000 --- a/busybox/hush.c +++ /dev/null @@ -1,2692 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * sh.c -- a prototype Bourne shell grammar parser - * Intended to follow the original Thompson and Ritchie - * "small and simple is beautiful" philosophy, which - * incidentally is a good match to today's BusyBox. - * - * Copyright (C) 2000,2001 Larry Doolittle - * - * Credits: - * The parser routines proper are all original material, first - * written Dec 2000 and Jan 2001 by Larry Doolittle. - * The execution engine, the builtins, and much of the underlying - * support has been adapted from busybox-0.49pre's lash, - * which is Copyright (C) 2000 by Lineo, Inc., and - * written by Erik Andersen , . - * That, in turn, is based in part on ladsh.c, by Michael K. Johnson and - * Erik W. Troan, which they placed in the public domain. I don't know - * how much of the Johnson/Troan code has survived the repeated rewrites. - * Other credits: - * simple_itoa() was lifted from boa-0.93.15 - * b_addchr() derived from similar w_addchar function in glibc-2.2 - * setup_redirect(), redirect_opt_num(), and big chunks of main() - * and many builtins derived from contributions by Erik Andersen - * miscellaneous bugfixes from Matt Kraai - * - * There are two big (and related) architecture differences between - * this parser and the lash parser. One is that this version is - * actually designed from the ground up to understand nearly all - * of the Bourne grammar. The second, consequential change is that - * the parser and input reader have been turned inside out. Now, - * the parser is in control, and asks for input as needed. The old - * way had the input reader in control, and it asked for parsing to - * take place as needed. The new way makes it much easier to properly - * handle the recursion implicit in the various substitutions, especially - * across continuation lines. - * - * Bash grammar not implemented: (how many of these were in original sh?) - * $@ (those sure look like weird quoting rules) - * $_ - * ! negation operator for pipes - * &> and >& redirection of stdout+stderr - * Brace Expansion - * Tilde Expansion - * fancy forms of Parameter Expansion - * aliases - * Arithmetic Expansion - * <(list) and >(list) Process Substitution - * reserved words: case, esac, select, function - * Here Documents ( << word ) - * Functions - * Major bugs: - * job handling woefully incomplete and buggy - * reserved word execution woefully incomplete and buggy - * to-do: - * port selected bugfixes from post-0.49 busybox lash - done? - * finish implementing reserved words: for, while, until, do, done - * change { and } from special chars to reserved words - * builtins: break, continue, eval, return, set, trap, ulimit - * test magic exec - * handle children going into background - * clean up recognition of null pipes - * check setting of global_argc and global_argv - * control-C handling, probably with longjmp - * follow IFS rules more precisely, including update semantics - * figure out what to do with backslash-newline - * explain why we use signal instead of sigaction - * propagate syntax errors, die on resource errors? - * continuation lines, both explicit and implicit - done? - * memory leak finding and plugging - done? - * more testing, especially quoting rules and redirection - * document how quoting rules not precisely followed for variable assignments - * maybe change map[] to use 2-bit entries - * (eventually) remove all the printf's - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include /* isalpha, isdigit */ -#include /* getpid */ -#include /* getenv, atoi */ -#include /* strchr */ -#include /* popen etc. */ -#include /* glob, of course */ -#include /* va_list */ -#include -#include -#include /* should be pretty obvious */ - -#include /* ulimit */ -#include -#include -#include - -/* #include */ -/* #define DEBUG_SHELL */ - -#ifdef BB_VER -#include "busybox.h" -#include "cmdedit.h" -#else -#define applet_name "hush" -#include "standalone.h" -#define hush_main main -#undef BB_FEATURE_SH_FANCY_PROMPT -#endif - -typedef enum { - REDIRECT_INPUT = 1, - REDIRECT_OVERWRITE = 2, - REDIRECT_APPEND = 3, - REDIRECT_HEREIS = 4, - REDIRECT_IO = 5 -} redir_type; - -/* The descrip member of this structure is only used to make debugging - * output pretty */ -struct {int mode; int default_fd; char *descrip;} redir_table[] = { - { 0, 0, "()" }, - { O_RDONLY, 0, "<" }, - { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" }, - { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" }, - { O_RDONLY, -1, "<<" }, - { O_RDWR, 1, "<>" } -}; - -typedef enum { - PIPE_SEQ = 1, - PIPE_AND = 2, - PIPE_OR = 3, - PIPE_BG = 4, -} pipe_style; - -/* might eventually control execution */ -typedef enum { - RES_NONE = 0, - RES_IF = 1, - RES_THEN = 2, - RES_ELIF = 3, - RES_ELSE = 4, - RES_FI = 5, - RES_FOR = 6, - RES_WHILE = 7, - RES_UNTIL = 8, - RES_DO = 9, - RES_DONE = 10, - RES_XXXX = 11, - RES_SNTX = 12 -} reserved_style; -#define FLAG_END (1<, but protected with __USE_GNU */ - -/* "globals" within this file */ -static char *ifs; -static char map[256]; -static int fake_mode; -static int interactive; -static struct close_me *close_me_head; -static const char *cwd; -static struct pipe *job_list; -static unsigned int last_bg_pid; -static unsigned int last_jobid; -static unsigned int shell_terminal; -static char *PS1; -static char *PS2; -struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 }; -struct variables *top_vars = &shell_ver; - - -#define B_CHUNK (100) -#define B_NOSPAC 1 - -typedef struct { - char *data; - int length; - int maxlen; - int quote; - int nonnull; -} o_string; -#define NULL_O_STRING {NULL,0,0,0,0} -/* used for initialization: - o_string foo = NULL_O_STRING; */ - -/* I can almost use ordinary FILE *. Is open_memstream() universally - * available? Where is it documented? */ -struct in_str { - const char *p; - char peek_buf[2]; - int __promptme; - int promptmode; - FILE *file; - int (*get) (struct in_str *); - int (*peek) (struct in_str *); -}; -#define b_getch(input) ((input)->get(input)) -#define b_peek(input) ((input)->peek(input)) - -#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" - -struct built_in_command { - char *cmd; /* name */ - char *descr; /* description */ - int (*function) (struct child_prog *); /* function ptr */ -}; - -/* belongs in busybox.h */ -static inline int max(int a, int b) { - return (a>b)?a:b; -} - -/* This should be in utility.c */ -#ifdef DEBUG_SHELL -static void debug_printf(const char *format, ...) -{ - va_list args; - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); -} -#else -static inline void debug_printf(const char *format, ...) { } -#endif -#define final_printf debug_printf - -static void __syntax(char *file, int line) { - error_msg("syntax error %s:%d", file, line); -} -#define syntax() __syntax(__FILE__, __LINE__) - -/* Index of subroutines: */ -/* function prototypes for builtins */ -static int builtin_cd(struct child_prog *child); -static int builtin_env(struct child_prog *child); -static int builtin_exec(struct child_prog *child); -static int builtin_exit(struct child_prog *child); -static int builtin_export(struct child_prog *child); -static int builtin_fg_bg(struct child_prog *child); -static int builtin_help(struct child_prog *child); -static int builtin_jobs(struct child_prog *child); -static int builtin_pwd(struct child_prog *child); -static int builtin_read(struct child_prog *child); -static int builtin_set(struct child_prog *child); -static int builtin_shift(struct child_prog *child); -static int builtin_source(struct child_prog *child); -static int builtin_umask(struct child_prog *child); -static int builtin_unset(struct child_prog *child); -static int builtin_not_written(struct child_prog *child); -/* o_string manipulation: */ -static int b_check_space(o_string *o, int len); -static int b_addchr(o_string *o, int ch); -static void b_reset(o_string *o); -static int b_addqchr(o_string *o, int ch, int quote); -static int b_adduint(o_string *o, unsigned int i); -/* in_str manipulations: */ -static int static_get(struct in_str *i); -static int static_peek(struct in_str *i); -static int file_get(struct in_str *i); -static int file_peek(struct in_str *i); -static void setup_file_in_str(struct in_str *i, FILE *f); -static void setup_string_in_str(struct in_str *i, const char *s); -/* close_me manipulations: */ -static void mark_open(int fd); -static void mark_closed(int fd); -static void close_all(); -/* "run" the final data structures: */ -static char *indenter(int i); -static int free_pipe_list(struct pipe *head, int indent); -static int free_pipe(struct pipe *pi, int indent); -/* really run the final data structures: */ -static int setup_redirects(struct child_prog *prog, int squirrel[]); -static int run_list_real(struct pipe *pi); -static void pseudo_exec(struct child_prog *child) __attribute__ ((noreturn)); -static int run_pipe_real(struct pipe *pi); -/* extended glob support: */ -static int globhack(const char *src, int flags, glob_t *pglob); -static int glob_needed(const char *s); -static int xglob(o_string *dest, int flags, glob_t *pglob); -/* variable assignment: */ -static int is_assignment(const char *s); -/* data structure manipulation: */ -static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input); -static void initialize_context(struct p_context *ctx); -static int done_word(o_string *dest, struct p_context *ctx); -static int done_command(struct p_context *ctx); -static int done_pipe(struct p_context *ctx, pipe_style type); -/* primary string parsing: */ -static int redirect_dup_num(struct in_str *input); -static int redirect_opt_num(o_string *o); -static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end); -static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); -static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src); -static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); -static int parse_string(o_string *dest, struct p_context *ctx, const char *src); -static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger); -/* setup: */ -static int parse_stream_outer(struct in_str *inp); -static int parse_string_outer(const char *s); -static int parse_file_outer(FILE *f); -/* job management: */ -static int checkjobs(struct pipe* fg_pipe); -static void insert_bg_job(struct pipe *pi); -static void remove_bg_job(struct pipe *pi); -/* local variable support */ -static char *get_local_var(const char *var); -static void unset_local_var(const char *name); -static int set_local_var(const char *s, int flg_export); - -/* Table of built-in functions. They can be forked or not, depending on - * context: within pipes, they fork. As simple commands, they do not. - * When used in non-forking context, they can change global variables - * in the parent shell process. If forked, of course they can not. - * For example, 'unset foo | whatever' will parse and run, but foo will - * still be set at the end. */ -static struct built_in_command bltins[] = { - {"bg", "Resume a job in the background", builtin_fg_bg}, - {"break", "Exit for, while or until loop", builtin_not_written}, - {"cd", "Change working directory", builtin_cd}, - {"continue", "Continue for, while or until loop", builtin_not_written}, - {"env", "Print all environment variables", builtin_env}, - {"eval", "Construct and run shell command", builtin_not_written}, - {"exec", "Exec command, replacing this shell with the exec'd process", - builtin_exec}, - {"exit", "Exit from shell()", builtin_exit}, - {"export", "Set environment variable", builtin_export}, - {"fg", "Bring job into the foreground", builtin_fg_bg}, - {"jobs", "Lists the active jobs", builtin_jobs}, - {"pwd", "Print current directory", builtin_pwd}, - {"read", "Input environment variable", builtin_read}, - {"return", "Return from a function", builtin_not_written}, - {"set", "Set/unset shell local variables", builtin_set}, - {"shift", "Shift positional parameters", builtin_shift}, - {"trap", "Trap signals", builtin_not_written}, - {"ulimit","Controls resource limits", builtin_not_written}, - {"umask","Sets file creation mask", builtin_umask}, - {"unset", "Unset environment variable", builtin_unset}, - {".", "Source-in and run commands in a file", builtin_source}, - {"help", "List shell built-in commands", builtin_help}, - {NULL, NULL, NULL} -}; - -static const char *set_cwd(void) -{ - if(cwd==unknown) - cwd = NULL; /* xgetcwd(arg) called free(arg) */ - cwd = xgetcwd((char *)cwd); - if (!cwd) - cwd = unknown; - return cwd; -} - - -/* built-in 'cd ' handler */ -static int builtin_cd(struct child_prog *child) -{ - char *newdir; - if (child->argv[1] == NULL) - newdir = getenv("HOME"); - else - newdir = child->argv[1]; - if (chdir(newdir)) { - printf("cd: %s: %s\n", newdir, strerror(errno)); - return EXIT_FAILURE; - } - set_cwd(); - return EXIT_SUCCESS; -} - -/* built-in 'env' handler */ -static int builtin_env(struct child_prog *dummy) -{ - char **e = environ; - if (e == NULL) return EXIT_FAILURE; - for (; *e; e++) { - puts(*e); - } - return EXIT_SUCCESS; -} - -/* built-in 'exec' handler */ -static int builtin_exec(struct child_prog *child) -{ - if (child->argv[1] == NULL) - return EXIT_SUCCESS; /* Really? */ - child->argv++; - pseudo_exec(child); - /* never returns */ -} - -/* built-in 'exit' handler */ -static int builtin_exit(struct child_prog *child) -{ - if (child->argv[1] == NULL) - exit(last_return_code); - exit (atoi(child->argv[1])); -} - -/* built-in 'export VAR=value' handler */ -static int builtin_export(struct child_prog *child) -{ - int res = 0; - char *name = child->argv[1]; - - if (name == NULL) { - return (builtin_env(child)); - } - - name = strdup(name); - - if(name) { - char *value = strchr(name, '='); - - if (!value) { - char *tmp; - /* They are exporting something without an =VALUE */ - - value = get_local_var(name); - if (value) { - size_t ln = strlen(name); - - tmp = realloc(name, ln+strlen(value)+2); - if(tmp==NULL) - res = -1; - else { - sprintf(tmp+ln, "=%s", value); - name = tmp; - } - } else { - /* bash does not return an error when trying to export - * an undefined variable. Do likewise. */ - res = 1; - } - } - } - if (res<0) - perror_msg("export"); - else if(res==0) - res = set_local_var(name, 1); - else - res = 0; - free(name); - return res; -} - -/* built-in 'fg' and 'bg' handler */ -static int builtin_fg_bg(struct child_prog *child) -{ - int i, jobnum; - struct pipe *pi=NULL; - - if (!interactive) - return EXIT_FAILURE; - /* If they gave us no args, assume they want the last backgrounded task */ - if (!child->argv[1]) { - for (pi = job_list; pi; pi = pi->next) { - if (pi->jobid == last_jobid) { - break; - } - } - if (!pi) { - error_msg("%s: no current job", child->argv[0]); - return EXIT_FAILURE; - } - } else { - if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { - error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]); - return EXIT_FAILURE; - } - for (pi = job_list; pi; pi = pi->next) { - if (pi->jobid == jobnum) { - break; - } - } - if (!pi) { - error_msg("%s: %d: no such job", child->argv[0], jobnum); - return EXIT_FAILURE; - } - } - - if (*child->argv[0] == 'f') { - /* Put the job into the foreground. */ - tcsetpgrp(shell_terminal, pi->pgrp); - } - - /* Restart the processes in the job */ - for (i = 0; i < pi->num_progs; i++) - pi->progs[i].is_stopped = 0; - - if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) { - if (i == ESRCH) { - remove_bg_job(pi); - } else { - perror_msg("kill (SIGCONT)"); - } - } - - pi->stopped_progs = 0; - return EXIT_SUCCESS; -} - -/* built-in 'help' handler */ -static int builtin_help(struct child_prog *dummy) -{ - struct built_in_command *x; - - printf("\nBuilt-in commands:\n"); - printf("-------------------\n"); - for (x = bltins; x->cmd; x++) { - if (x->descr==NULL) - continue; - printf("%s\t%s\n", x->cmd, x->descr); - } - printf("\n\n"); - return EXIT_SUCCESS; -} - -/* built-in 'jobs' handler */ -static int builtin_jobs(struct child_prog *child) -{ - struct pipe *job; - char *status_string; - - for (job = job_list; job; job = job->next) { - if (job->running_progs == job->stopped_progs) - status_string = "Stopped"; - else - status_string = "Running"; - - printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text); - } - return EXIT_SUCCESS; -} - - -/* built-in 'pwd' handler */ -static int builtin_pwd(struct child_prog *dummy) -{ - puts(set_cwd()); - return EXIT_SUCCESS; -} - -/* built-in 'read VAR' handler */ -static int builtin_read(struct child_prog *child) -{ - int res; - - if (child->argv[1]) { - char string[BUFSIZ]; - char *var = 0; - - string[0] = 0; /* In case stdin has only EOF */ - /* read string */ - fgets(string, sizeof(string), stdin); - chomp(string); - var = malloc(strlen(child->argv[1])+strlen(string)+2); - if(var) { - sprintf(var, "%s=%s", child->argv[1], string); - res = set_local_var(var, 0); - } else - res = -1; - if (res) - fprintf(stderr, "read: %m\n"); - free(var); /* So not move up to avoid breaking errno */ - return res; - } else { - do res=getchar(); while(res!='\n' && res!=EOF); - return 0; - } -} - -/* built-in 'set VAR=value' handler */ -static int builtin_set(struct child_prog *child) -{ - char *temp = child->argv[1]; - struct variables *e; - - if (temp == NULL) - for(e = top_vars; e; e=e->next) - printf("%s=%s\n", e->name, e->value); - else - set_local_var(temp, 0); - - return EXIT_SUCCESS; -} - - -/* Built-in 'shift' handler */ -static int builtin_shift(struct child_prog *child) -{ - int n=1; - if (child->argv[1]) { - n=atoi(child->argv[1]); - } - if (n>=0 && nargv[1] == NULL) - return EXIT_FAILURE; - - /* XXX search through $PATH is missing */ - input = fopen(child->argv[1], "r"); - if (!input) { - error_msg("Couldn't open file '%s'", child->argv[1]); - return EXIT_FAILURE; - } - - /* Now run the file */ - /* XXX argv and argc are broken; need to save old global_argv - * (pointer only is OK!) on this stack frame, - * set global_argv=child->argv+1, recurse, and restore. */ - mark_open(fileno(input)); - status = parse_file_outer(input); - mark_closed(fileno(input)); - fclose(input); - return (status); -} - -static int builtin_umask(struct child_prog *child) -{ - mode_t new_umask; - const char *arg = child->argv[1]; - char *end; - if (arg) { - new_umask=strtoul(arg, &end, 8); - if (*end!='\0' || end == arg) { - return EXIT_FAILURE; - } - } else { - printf("%.3o\n", (unsigned int) (new_umask=umask(0))); - } - umask(new_umask); - return EXIT_SUCCESS; -} - -/* built-in 'unset VAR' handler */ -static int builtin_unset(struct child_prog *child) -{ - /* bash returned already true */ - unset_local_var(child->argv[1]); - return EXIT_SUCCESS; -} - -static int builtin_not_written(struct child_prog *child) -{ - printf("builtin_%s not written\n",child->argv[0]); - return EXIT_FAILURE; -} - -static int b_check_space(o_string *o, int len) -{ - /* It would be easy to drop a more restrictive policy - * in here, such as setting a maximum string length */ - if (o->length + len > o->maxlen) { - char *old_data = o->data; - /* assert (data == NULL || o->maxlen != 0); */ - o->maxlen += max(2*len, B_CHUNK); - o->data = realloc(o->data, 1 + o->maxlen); - if (o->data == NULL) { - free(old_data); - } - } - return o->data == NULL; -} - -static int b_addchr(o_string *o, int ch) -{ - debug_printf("b_addchr: %c %d %p\n", ch, o->length, o); - if (b_check_space(o, 1)) return B_NOSPAC; - o->data[o->length] = ch; - o->length++; - o->data[o->length] = '\0'; - return 0; -} - -static void b_reset(o_string *o) -{ - o->length = 0; - o->nonnull = 0; - if (o->data != NULL) *o->data = '\0'; -} - -static void b_free(o_string *o) -{ - b_reset(o); - if (o->data != NULL) free(o->data); - o->data = NULL; - o->maxlen = 0; -} - -/* My analysis of quoting semantics tells me that state information - * is associated with a destination, not a source. - */ -static int b_addqchr(o_string *o, int ch, int quote) -{ - if (quote && strchr("*?[\\",ch)) { - int rc; - rc = b_addchr(o, '\\'); - if (rc) return rc; - } - return b_addchr(o, ch); -} - -/* belongs in utility.c */ -char *simple_itoa(unsigned int i) -{ - /* 21 digits plus null terminator, good for 64-bit or smaller ints */ - static char local[22]; - char *p = &local[21]; - *p-- = '\0'; - do { - *p-- = '0' + i % 10; - i /= 10; - } while (i > 0); - return p + 1; -} - -static int b_adduint(o_string *o, unsigned int i) -{ - int r; - char *p = simple_itoa(i); - /* no escape checking necessary */ - do r=b_addchr(o, *p++); while (r==0 && *p); - return r; -} - -static int static_get(struct in_str *i) -{ - int ch=*i->p++; - if (ch=='\0') return EOF; - return ch; -} - -static int static_peek(struct in_str *i) -{ - return *i->p; -} - -static inline void cmdedit_set_initial_prompt(void) -{ -#ifndef BB_FEATURE_SH_FANCY_PROMPT - PS1 = NULL; -#else - PS1 = getenv("PS1"); - if(PS1==0) - PS1 = "\\w \\$ "; -#endif -} - -static inline void setup_prompt_string(int promptmode, char **prompt_str) -{ - debug_printf("setup_prompt_string %d ",promptmode); -#ifndef BB_FEATURE_SH_FANCY_PROMPT - /* Set up the prompt */ - if (promptmode == 1) { - if (PS1) - free(PS1); - PS1=xmalloc(strlen(cwd)+4); - sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); - *prompt_str = PS1; - } else { - *prompt_str = PS2; - } -#else - *prompt_str = (promptmode==1)? PS1 : PS2; -#endif - debug_printf("result %s\n",*prompt_str); -} - -static void get_user_input(struct in_str *i) -{ - char *prompt_str; - static char the_command[BUFSIZ]; - - setup_prompt_string(i->promptmode, &prompt_str); -#ifdef BB_FEATURE_COMMAND_EDITING - /* - ** enable command line editing only while a command line - ** is actually being read; otherwise, we'll end up bequeathing - ** atexit() handlers and other unwanted stuff to our - ** child processes (rob@sysgo.de) - */ - cmdedit_read_input(prompt_str, the_command); -#else - fputs(prompt_str, stdout); - fflush(stdout); - the_command[0]=fgetc(i->file); - the_command[1]='\0'; -#endif - fflush(stdout); - i->p = the_command; -} - -/* This is the magic location that prints prompts - * and gets data back from the user */ -static int file_get(struct in_str *i) -{ - int ch; - - ch = 0; - /* If there is data waiting, eat it up */ - if (i->p && *i->p) { - ch=*i->p++; - } else { - /* need to double check i->file because we might be doing something - * more complicated by now, like sourcing or substituting. */ - if (i->__promptme && interactive && i->file == stdin) { - while(! i->p || (interactive && strlen(i->p)==0) ) { - get_user_input(i); - } - i->promptmode=2; - i->__promptme = 0; - if (i->p && *i->p) { - ch=*i->p++; - } - } else { - ch = fgetc(i->file); - } - - debug_printf("b_getch: got a %d\n", ch); - } - if (ch == '\n') i->__promptme=1; - return ch; -} - -/* All the callers guarantee this routine will never be - * used right after a newline, so prompting is not needed. - */ -static int file_peek(struct in_str *i) -{ - if (i->p && *i->p) { - return *i->p; - } else { - i->peek_buf[0] = fgetc(i->file); - i->peek_buf[1] = '\0'; - i->p = i->peek_buf; - debug_printf("b_peek: got a %d\n", *i->p); - return *i->p; - } -} - -static void setup_file_in_str(struct in_str *i, FILE *f) -{ - i->peek = file_peek; - i->get = file_get; - i->__promptme=1; - i->promptmode=1; - i->file = f; - i->p = NULL; -} - -static void setup_string_in_str(struct in_str *i, const char *s) -{ - i->peek = static_peek; - i->get = static_get; - i->__promptme=1; - i->promptmode=1; - i->p = s; -} - -static void mark_open(int fd) -{ - struct close_me *new = xmalloc(sizeof(struct close_me)); - new->fd = fd; - new->next = close_me_head; - close_me_head = new; -} - -static void mark_closed(int fd) -{ - struct close_me *tmp; - if (close_me_head == NULL || close_me_head->fd != fd) - error_msg_and_die("corrupt close_me"); - tmp = close_me_head; - close_me_head = close_me_head->next; - free(tmp); -} - -static void close_all() -{ - struct close_me *c; - for (c=close_me_head; c; c=c->next) { - close(c->fd); - } - close_me_head = NULL; -} - -/* squirrel != NULL means we squirrel away copies of stdin, stdout, - * and stderr if they are redirected. */ -static int setup_redirects(struct child_prog *prog, int squirrel[]) -{ - int openfd, mode; - struct redir_struct *redir; - - for (redir=prog->redirects; redir; redir=redir->next) { - if (redir->dup == -1 && redir->word.gl_pathv == NULL) { - /* something went wrong in the parse. Pretend it didn't happen */ - continue; - } - if (redir->dup == -1) { - mode=redir_table[redir->type].mode; - openfd = open(redir->word.gl_pathv[0], mode, 0666); - if (openfd < 0) { - /* this could get lost if stderr has been redirected, but - bash and ash both lose it as well (though zsh doesn't!) */ - perror_msg("error opening %s", redir->word.gl_pathv[0]); - return 1; - } - } else { - openfd = redir->dup; - } - - if (openfd != redir->fd) { - if (squirrel && redir->fd < 3) { - squirrel[redir->fd] = dup(redir->fd); - } - if (openfd == -3) { - close(openfd); - } else { - dup2(openfd, redir->fd); - if (redir->dup == -1) - close (openfd); - } - } - } - return 0; -} - -static void restore_redirects(int squirrel[]) -{ - int i, fd; - for (i=0; i<3; i++) { - fd = squirrel[i]; - if (fd != -1) { - /* No error checking. I sure wouldn't know what - * to do with an error if I found one! */ - dup2(fd, i); - close(fd); - } - } -} - -/* never returns */ -/* XXX no exit() here. If you don't exec, use _exit instead. - * The at_exit handlers apparently confuse the calling process, - * in particular stdin handling. Not sure why? */ -static void pseudo_exec(struct child_prog *child) -{ - int i, rcode; - struct built_in_command *x; - if (child->argv) { - for (i=0; is_assignment(child->argv[i]); i++) { - debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]); - putenv(strdup(child->argv[i])); - } - child->argv+=i; /* XXX this hack isn't so horrible, since we are about - to exit, and therefore don't need to keep data - structures consistent for free() use. */ - /* If a variable is assigned in a forest, and nobody listens, - * was it ever really set? - */ - if (child->argv[0] == NULL) { - _exit(EXIT_SUCCESS); - } - - /* - * Check if the command matches any of the builtins. - * Depending on context, this might be redundant. But it's - * easier to waste a few CPU cycles than it is to figure out - * if this is one of those cases. - */ - for (x = bltins; x->cmd; x++) { - if (strcmp(child->argv[0], x->cmd) == 0 ) { - debug_printf("builtin exec %s\n", child->argv[0]); - rcode = x->function(child); - fflush(stdout); - _exit(rcode); - } - } - - /* Check if the command matches any busybox internal commands - * ("applets") here. - * FIXME: This feature is not 100% safe, since - * BusyBox is not fully reentrant, so we have no guarantee the things - * from the .bss are still zeroed, or that things from .data are still - * at their defaults. We could exec ourself from /proc/self/exe, but I - * really dislike relying on /proc for things. We could exec ourself - * from global_argv[0], but if we are in a chroot, we may not be able - * to find ourself... */ -#ifdef BB_FEATURE_SH_STANDALONE_SHELL - { - int argc_l; - char** argv_l=child->argv; - char *name = child->argv[0]; - -#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN - /* Following discussions from November 2000 on the busybox mailing - * list, the default configuration, (without - * get_last_path_component()) lets the user force use of an - * external command by specifying the full (with slashes) filename. - * If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then applets - * _aways_ override external commands, so if you want to run - * /bin/cat, it will use BusyBox cat even if /bin/cat exists on the - * filesystem and is _not_ busybox. Some systems may want this, - * most do not. */ - name = get_last_path_component(name); -#endif - /* Count argc for use in a second... */ - for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++); - optind = 1; - debug_printf("running applet %s\n", name); - run_applet_by_name(name, argc_l, child->argv); - } -#endif - debug_printf("exec of %s\n",child->argv[0]); - execvp(child->argv[0],child->argv); - perror_msg("couldn't exec: %s",child->argv[0]); - _exit(1); - } else if (child->group) { - debug_printf("runtime nesting to group\n"); - interactive=0; /* crucial!!!! */ - rcode = run_list_real(child->group); - /* OK to leak memory by not calling free_pipe_list, - * since this process is about to exit */ - _exit(rcode); - } else { - /* Can happen. See what bash does with ">foo" by itself. */ - debug_printf("trying to pseudo_exec null command\n"); - _exit(EXIT_SUCCESS); - } -} - -static void insert_bg_job(struct pipe *pi) -{ - struct pipe *thejob; - - /* Linear search for the ID of the job to use */ - pi->jobid = 1; - for (thejob = job_list; thejob; thejob = thejob->next) - if (thejob->jobid >= pi->jobid) - pi->jobid = thejob->jobid + 1; - - /* add thejob to the list of running jobs */ - if (!job_list) { - thejob = job_list = xmalloc(sizeof(*thejob)); - } else { - for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */; - thejob->next = xmalloc(sizeof(*thejob)); - thejob = thejob->next; - } - - /* physically copy the struct job */ - memcpy(thejob, pi, sizeof(struct pipe)); - thejob->next = NULL; - thejob->running_progs = thejob->num_progs; - thejob->stopped_progs = 0; - thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */ - - //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0]) - { - char *bar=thejob->text; - char **foo=pi->progs[0].argv; - while(foo && *foo) { - bar += sprintf(bar, "%s ", *foo++); - } - } - - /* we don't wait for background thejobs to return -- append it - to the list of backgrounded thejobs and leave it alone */ - printf("[%d] %d\n", thejob->jobid, thejob->progs[0].pid); - last_bg_pid = thejob->progs[0].pid; - last_jobid = thejob->jobid; -} - -/* remove a backgrounded job */ -static void remove_bg_job(struct pipe *pi) -{ - struct pipe *prev_pipe; - - if (pi == job_list) { - job_list = pi->next; - } else { - prev_pipe = job_list; - while (prev_pipe->next != pi) - prev_pipe = prev_pipe->next; - prev_pipe->next = pi->next; - } - if (job_list) - last_jobid = job_list->jobid; - else - last_jobid = 0; - - pi->stopped_progs = 0; - free_pipe(pi, 0); - free(pi); -} - -/* Checks to see if any processes have exited -- if they - have, figure out why and see if a job has completed */ -static int checkjobs(struct pipe* fg_pipe) -{ - int attributes; - int status; - int prognum = 0; - struct pipe *pi; - pid_t childpid; - - attributes = WUNTRACED; - if (fg_pipe==NULL) { - attributes |= WNOHANG; - } - - while ((childpid = waitpid(-1, &status, attributes)) > 0) { - if (fg_pipe) { - int i, rcode = 0; - for (i=0; i < fg_pipe->num_progs; i++) { - if (fg_pipe->progs[i].pid == childpid) { - if (i==fg_pipe->num_progs-1) - rcode=WEXITSTATUS(status); - (fg_pipe->num_progs)--; - return(rcode); - } - } - } - - for (pi = job_list; pi; pi = pi->next) { - prognum = 0; - while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) { - prognum++; - } - if (prognum < pi->num_progs) - break; - } - - if(pi==NULL) { - debug_printf("checkjobs: pid %d was not in our list!\n", childpid); - continue; - } - - if (WIFEXITED(status) || WIFSIGNALED(status)) { - /* child exited */ - pi->running_progs--; - pi->progs[prognum].pid = 0; - - if (!pi->running_progs) { - printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text); - remove_bg_job(pi); - } - } else { - /* child stopped */ - pi->stopped_progs++; - pi->progs[prognum].is_stopped = 1; - -#if 0 - /* Printing this stuff is a pain, since it tends to - * overwrite the prompt an inconveinient moments. So - * don't do that. */ - if (pi->stopped_progs == pi->num_progs) { - printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text); - } -#endif - } - } - - if (childpid == -1 && errno != ECHILD) - perror_msg("waitpid"); - - /* move the shell to the foreground */ - //if (interactive && tcsetpgrp(shell_terminal, getpgid(0))) - // perror_msg("tcsetpgrp-2"); - return -1; -} - -/* Figure out our controlling tty, checking in order stderr, - * stdin, and stdout. If check_pgrp is set, also check that - * we belong to the foreground process group associated with - * that tty. The value of shell_terminal is needed in order to call - * tcsetpgrp(shell_terminal, ...); */ -void controlling_tty(int check_pgrp) -{ - pid_t curpgrp; - - if ((curpgrp = tcgetpgrp(shell_terminal = 2)) < 0 - && (curpgrp = tcgetpgrp(shell_terminal = 0)) < 0 - && (curpgrp = tcgetpgrp(shell_terminal = 1)) < 0) - goto shell_terminal_error; - - if (check_pgrp && curpgrp != getpgid(0)) - goto shell_terminal_error; - - return; - -shell_terminal_error: - shell_terminal = -1; - return; -} - -/* run_pipe_real() starts all the jobs, but doesn't wait for anything - * to finish. See checkjobs(). - * - * return code is normally -1, when the caller has to wait for children - * to finish to determine the exit status of the pipe. If the pipe - * is a simple builtin command, however, the action is done by the - * time run_pipe_real returns, and the exit code is provided as the - * return value. - * - * The input of the pipe is always stdin, the output is always - * stdout. The outpipe[] mechanism in BusyBox-0.48 lash is bogus, - * because it tries to avoid running the command substitution in - * subshell, when that is in fact necessary. The subshell process - * now has its stdout directed to the input of the appropriate pipe, - * so this routine is noticeably simpler. - */ -static int run_pipe_real(struct pipe *pi) -{ - int i; - int nextin, nextout; - int pipefds[2]; /* pipefds[0] is for reading */ - struct child_prog *child; - struct built_in_command *x; - - nextin = 0; - pi->pgrp = -1; - - /* Check if this is a simple builtin (not part of a pipe). - * Builtins within pipes have to fork anyway, and are handled in - * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. - */ - if (pi->num_progs == 1) child = & (pi->progs[0]); - if (pi->num_progs == 1 && child->group && child->subshell == 0) { - int squirrel[] = {-1, -1, -1}; - int rcode; - debug_printf("non-subshell grouping\n"); - setup_redirects(child, squirrel); - /* XXX could we merge code with following builtin case, - * by creating a pseudo builtin that calls run_list_real? */ - rcode = run_list_real(child->group); - restore_redirects(squirrel); - return rcode; - } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) { - for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ } - if (i!=0 && child->argv[i]==NULL) { - /* assignments, but no command: set the local environment */ - for (i=0; child->argv[i]!=NULL; i++) { - - /* Ok, this case is tricky. We have to decide if this is a - * local variable, or an already exported variable. If it is - * already exported, we have to export the new value. If it is - * not exported, we need only set this as a local variable. - * This junk is all to decide whether or not to export this - * variable. */ - int export_me=0; - char *name, *value; - name = xstrdup(child->argv[i]); - debug_printf("Local environment set: %s\n", name); - value = strchr(name, '='); - if (value) - *value=0; - if ( get_local_var(name)) { - export_me=1; - } - free(name); - set_local_var(child->argv[i], export_me); - } - return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ - } - for (x = bltins; x->cmd; x++) { - if (strcmp(child->argv[i], x->cmd) == 0 ) { - int squirrel[] = {-1, -1, -1}; - int rcode; - if (x->function == builtin_exec && child->argv[i+1]==NULL) { - debug_printf("magic exec\n"); - setup_redirects(child,NULL); - return EXIT_SUCCESS; - } - debug_printf("builtin inline %s\n", child->argv[0]); - /* XXX setup_redirects acts on file descriptors, not FILEs. - * This is perfect for work that comes after exec(). - * Is it really safe for inline use? Experimentally, - * things seem to work with glibc. */ - setup_redirects(child, squirrel); - for (i=0; is_assignment(child->argv[i]); i++) { - putenv(strdup(child->argv[i])); - } - child->argv+=i; /* XXX horrible hack */ - rcode = x->function(child); - child->argv-=i; /* XXX restore hack so free() can work right */ - restore_redirects(squirrel); - return rcode; - } - } - } - - for (i = 0; i < pi->num_progs; i++) { - child = & (pi->progs[i]); - - /* pipes are inserted between pairs of commands */ - if ((i + 1) < pi->num_progs) { - if (pipe(pipefds)<0) perror_msg_and_die("pipe"); - nextout = pipefds[1]; - } else { - nextout=1; - pipefds[0] = -1; - } - - /* XXX test for failed fork()? */ - if (!(child->pid = fork())) { - /* Set the handling for job control signals back to the default. */ - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGTSTP, SIG_DFL); - signal(SIGTTIN, SIG_DFL); - signal(SIGTTOU, SIG_DFL); - signal(SIGCHLD, SIG_DFL); - - close_all(); - - if (nextin != 0) { - dup2(nextin, 0); - close(nextin); - } - if (nextout != 1) { - dup2(nextout, 1); - close(nextout); - } - if (pipefds[0]!=-1) { - close(pipefds[0]); /* opposite end of our output pipe */ - } - - /* Like bash, explicit redirects override pipes, - * and the pipe fd is available for dup'ing. */ - setup_redirects(child,NULL); - - if (interactive && pi->followup!=PIPE_BG) { - /* If we (the child) win the race, put ourselves in the process - * group whose leader is the first process in this pipe. */ - if (pi->pgrp < 0) { - pi->pgrp = getpid(); - } - if (setpgid(0, pi->pgrp) == 0) { - tcsetpgrp(2, pi->pgrp); - } - } - - pseudo_exec(child); - } - - - /* put our child in the process group whose leader is the - first process in this pipe */ - if (pi->pgrp < 0) { - pi->pgrp = child->pid; - } - /* Don't check for errors. The child may be dead already, - * in which case setpgid returns error code EACCES. */ - setpgid(child->pid, pi->pgrp); - - if (nextin != 0) - close(nextin); - if (nextout != 1) - close(nextout); - - /* If there isn't another process, nextin is garbage - but it doesn't matter */ - nextin = pipefds[0]; - } - return -1; -} - -static int run_list_real(struct pipe *pi) -{ - int rcode=0; - int if_code=0, next_if_code=0; /* need double-buffer to handle elif */ - reserved_style rmode, skip_more_in_this_rmode=RES_XXXX; - for (;pi;pi=pi->next) { - rmode = pi->r_mode; - debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode); - if (rmode == skip_more_in_this_rmode) continue; - skip_more_in_this_rmode = RES_XXXX; - if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code; - if (rmode == RES_THEN && if_code) continue; - if (rmode == RES_ELSE && !if_code) continue; - if (rmode == RES_ELIF && !if_code) continue; - if (pi->num_progs == 0) continue; - rcode = run_pipe_real(pi); - debug_printf("run_pipe_real returned %d\n",rcode); - if (rcode!=-1) { - /* We only ran a builtin: rcode was set by the return value - * of run_pipe_real(), and we don't need to wait for anything. */ - } else if (pi->followup==PIPE_BG) { - /* XXX check bash's behavior with nontrivial pipes */ - /* XXX compute jobid */ - /* XXX what does bash do with attempts to background builtins? */ - insert_bg_job(pi); - rcode = EXIT_SUCCESS; - } else { - if (interactive) { - /* move the new process group into the foreground */ - if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY) - perror_msg("tcsetpgrp-3"); - rcode = checkjobs(pi); - /* move the shell to the foreground */ - if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY) - perror_msg("tcsetpgrp-4"); - } else { - rcode = checkjobs(pi); - } - debug_printf("checkjobs returned %d\n",rcode); - } - last_return_code=rcode; - if ( rmode == RES_IF || rmode == RES_ELIF ) - next_if_code=rcode; /* can be overwritten a number of times */ - if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) || - (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) ) - skip_more_in_this_rmode=rmode; - checkjobs(NULL); - } - return rcode; -} - -/* broken, of course, but OK for testing */ -static char *indenter(int i) -{ - static char blanks[]=" "; - return &blanks[sizeof(blanks)-i-1]; -} - -/* return code is the exit status of the pipe */ -static int free_pipe(struct pipe *pi, int indent) -{ - char **p; - struct child_prog *child; - struct redir_struct *r, *rnext; - int a, i, ret_code=0; - char *ind = indenter(indent); - - if (pi->stopped_progs > 0) - return ret_code; - final_printf("%s run pipe: (pid %d)\n",ind,getpid()); - for (i=0; inum_progs; i++) { - child = &pi->progs[i]; - final_printf("%s command %d:\n",ind,i); - if (child->argv) { - for (a=0,p=child->argv; *p; a++,p++) { - final_printf("%s argv[%d] = %s\n",ind,a,*p); - } - globfree(&child->glob_result); - child->argv=NULL; - } else if (child->group) { - final_printf("%s begin group (subshell:%d)\n",ind, child->subshell); - ret_code = free_pipe_list(child->group,indent+3); - final_printf("%s end group\n",ind); - } else { - final_printf("%s (nil)\n",ind); - } - for (r=child->redirects; r; r=rnext) { - final_printf("%s redirect %d%s", ind, r->fd, redir_table[r->type].descrip); - if (r->dup == -1) { - /* guard against the case >$FOO, where foo is unset or blank */ - if (r->word.gl_pathv) { - final_printf(" %s\n", *r->word.gl_pathv); - globfree(&r->word); - } - } else { - final_printf("&%d\n", r->dup); - } - rnext=r->next; - free(r); - } - child->redirects=NULL; - } - free(pi->progs); /* children are an array, they get freed all at once */ - pi->progs=NULL; - return ret_code; -} - -static int free_pipe_list(struct pipe *head, int indent) -{ - int rcode=0; /* if list has no members */ - struct pipe *pi, *next; - char *ind = indenter(indent); - for (pi=head; pi; pi=next) { - final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode); - rcode = free_pipe(pi, indent); - final_printf("%s pipe followup code %d\n", ind, pi->followup); - next=pi->next; - pi->next=NULL; - free(pi); - } - return rcode; -} - -/* Select which version we will use */ -static int run_list(struct pipe *pi) -{ - int rcode=0; - if (fake_mode==0) { - rcode = run_list_real(pi); - } - /* free_pipe_list has the side effect of clearing memory - * In the long run that function can be merged with run_list_real, - * but doing that now would hobble the debugging effort. */ - free_pipe_list(pi,0); - return rcode; -} - -/* The API for glob is arguably broken. This routine pushes a non-matching - * string into the output structure, removing non-backslashed backslashes. - * If someone can prove me wrong, by performing this function within the - * original glob(3) api, feel free to rewrite this routine into oblivion. - * Return code (0 vs. GLOB_NOSPACE) matches glob(3). - * XXX broken if the last character is '\\', check that before calling. - */ -static int globhack(const char *src, int flags, glob_t *pglob) -{ - int cnt=0, pathc; - const char *s; - char *dest; - for (cnt=1, s=src; s && *s; s++) { - if (*s == '\\') s++; - cnt++; - } - dest = malloc(cnt); - if (!dest) return GLOB_NOSPACE; - if (!(flags & GLOB_APPEND)) { - pglob->gl_pathv=NULL; - pglob->gl_pathc=0; - pglob->gl_offs=0; - pglob->gl_offs=0; - } - pathc = ++pglob->gl_pathc; - pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv)); - if (pglob->gl_pathv == NULL) return GLOB_NOSPACE; - pglob->gl_pathv[pathc-1]=dest; - pglob->gl_pathv[pathc]=NULL; - for (s=src; s && *s; s++, dest++) { - if (*s == '\\') s++; - *dest = *s; - } - *dest='\0'; - return 0; -} - -/* XXX broken if the last character is '\\', check that before calling */ -static int glob_needed(const char *s) -{ - for (; *s; s++) { - if (*s == '\\') s++; - if (strchr("*[?",*s)) return 1; - } - return 0; -} - -#if 0 -static void globprint(glob_t *pglob) -{ - int i; - debug_printf("glob_t at %p:\n", pglob); - debug_printf(" gl_pathc=%d gl_pathv=%p gl_offs=%d gl_flags=%d\n", - pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags); - for (i=0; igl_pathc; i++) - debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i, - pglob->gl_pathv[i], pglob->gl_pathv[i]); -} -#endif - -static int xglob(o_string *dest, int flags, glob_t *pglob) -{ - int gr; - - /* short-circuit for null word */ - /* we can code this better when the debug_printf's are gone */ - if (dest->length == 0) { - if (dest->nonnull) { - /* bash man page calls this an "explicit" null */ - gr = globhack(dest->data, flags, pglob); - debug_printf("globhack returned %d\n",gr); - } else { - return 0; - } - } else if (glob_needed(dest->data)) { - gr = glob(dest->data, flags, NULL, pglob); - debug_printf("glob returned %d\n",gr); - if (gr == GLOB_NOMATCH) { - /* quote removal, or more accurately, backslash removal */ - gr = globhack(dest->data, flags, pglob); - debug_printf("globhack returned %d\n",gr); - } - } else { - gr = globhack(dest->data, flags, pglob); - debug_printf("globhack returned %d\n",gr); - } - if (gr == GLOB_NOSPACE) - error_msg_and_die("out of memory during glob"); - if (gr != 0) { /* GLOB_ABORTED ? */ - error_msg("glob(3) error %d",gr); - } - /* globprint(glob_target); */ - return gr; -} - -/* This is used to get/check local shell variables */ -static char *get_local_var(const char *s) -{ - struct variables *cur; - - if (!s) - return NULL; - for (cur = top_vars; cur; cur=cur->next) - if(strcmp(cur->name, s)==0) - return cur->value; - return NULL; -} - -/* This is used to set local shell variables - flg_export==0 if only local (not exporting) variable - flg_export==1 if "new" exporting environ - flg_export>1 if current startup environ (not call putenv()) */ -static int set_local_var(const char *s, int flg_export) -{ - char *name, *value; - int result=0; - struct variables *cur; - - name=strdup(s); - - /* Assume when we enter this function that we are already in - * NAME=VALUE format. So the first order of business is to - * split 's' on the '=' into 'name' and 'value' */ - value = strchr(name, '='); - if (value==0 && ++value==0) { - free(name); - return -1; - } - *value++ = 0; - - for(cur = top_vars; cur; cur = cur->next) { - if(strcmp(cur->name, name)==0) - break; - } - - if(cur) { - if(strcmp(cur->value, value)==0) { - if(flg_export>0 && cur->flg_export==0) - cur->flg_export=flg_export; - else - result++; - } else { - if(cur->flg_read_only) { - error_msg("%s: readonly variable", name); - result = -1; - } else { - if(flg_export>0 || cur->flg_export>1) - cur->flg_export=1; - free(cur->value); - - cur->value = strdup(value); - } - } - } else { - cur = malloc(sizeof(struct variables)); - if(!cur) { - result = -1; - } else { - cur->name = strdup(name); - if(cur->name == 0) { - free(cur); - result = -1; - } else { - struct variables *bottom = top_vars; - cur->value = strdup(value); - cur->next = 0; - cur->flg_export = flg_export; - cur->flg_read_only = 0; - while(bottom->next) bottom=bottom->next; - bottom->next = cur; - } - } - } - - if(result==0 && cur->flg_export==1) { - *(value-1) = '='; - result = putenv(name); - } else { - free(name); - if(result>0) /* equivalent to previous set */ - result = 0; - } - return result; -} - -static void unset_local_var(const char *name) -{ - struct variables *cur; - - if (name) { - for (cur = top_vars; cur; cur=cur->next) { - if(strcmp(cur->name, name)==0) - break; - } - if(cur!=0) { - struct variables *next = top_vars; - if(cur->flg_read_only) { - error_msg("%s: readonly variable", name); - return; - } else { - if(cur->flg_export) - unsetenv(cur->name); - free(cur->name); - free(cur->value); - while (next->next != cur) - next = next->next; - next->next = cur->next; - } - free(cur); - } - } -} - -static int is_assignment(const char *s) -{ - if (s==NULL || !isalpha(*s)) return 0; - ++s; - while(isalnum(*s) || *s=='_') ++s; - return *s=='='; -} - -/* the src parameter allows us to peek forward to a possible &n syntax - * for file descriptor duplication, e.g., "2>&1". - * Return code is 0 normally, 1 if a syntax error is detected in src. - * Resource errors (in xmalloc) cause the process to exit */ -static int setup_redirect(struct p_context *ctx, int fd, redir_type style, - struct in_str *input) -{ - struct child_prog *child=ctx->child; - struct redir_struct *redir = child->redirects; - struct redir_struct *last_redir=NULL; - - /* Create a new redir_struct and drop it onto the end of the linked list */ - while(redir) { - last_redir=redir; - redir=redir->next; - } - redir = xmalloc(sizeof(struct redir_struct)); - redir->next=NULL; - redir->word.gl_pathv=NULL; - if (last_redir) { - last_redir->next=redir; - } else { - child->redirects=redir; - } - - redir->type=style; - redir->fd= (fd==-1) ? redir_table[style].default_fd : fd ; - - debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip); - - /* Check for a '2>&1' type redirect */ - redir->dup = redirect_dup_num(input); - if (redir->dup == -2) return 1; /* syntax error */ - if (redir->dup != -1) { - /* Erik had a check here that the file descriptor in question - * is legit; I postpone that to "run time" - * A "-" representation of "close me" shows up as a -3 here */ - debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup); - } else { - /* We do _not_ try to open the file that src points to, - * since we need to return and let src be expanded first. - * Set ctx->pending_redirect, so we know what to do at the - * end of the next parsed word. - */ - ctx->pending_redirect = redir; - } - return 0; -} - -struct pipe *new_pipe(void) { - struct pipe *pi; - pi = xmalloc(sizeof(struct pipe)); - pi->num_progs = 0; - pi->progs = NULL; - pi->next = NULL; - pi->followup = 0; /* invalid */ - return pi; -} - -static void initialize_context(struct p_context *ctx) -{ - ctx->pipe=NULL; - ctx->pending_redirect=NULL; - ctx->child=NULL; - ctx->list_head=new_pipe(); - ctx->pipe=ctx->list_head; - ctx->w=RES_NONE; - ctx->stack=NULL; - done_command(ctx); /* creates the memory for working child */ -} - -/* normal return is 0 - * if a reserved word is found, and processed, return 1 - * should handle if, then, elif, else, fi, for, while, until, do, done. - * case, function, and select are obnoxious, save those for later. - */ -int reserved_word(o_string *dest, struct p_context *ctx) -{ - struct reserved_combo { - char *literal; - int code; - long flag; - }; - /* Mostly a list of accepted follow-up reserved words. - * FLAG_END means we are done with the sequence, and are ready - * to turn the compound list into a command. - * FLAG_START means the word must start a new compound list. - */ - static struct reserved_combo reserved_list[] = { - { "if", RES_IF, FLAG_THEN | FLAG_START }, - { "then", RES_THEN, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, - { "elif", RES_ELIF, FLAG_THEN }, - { "else", RES_ELSE, FLAG_FI }, - { "fi", RES_FI, FLAG_END }, - { "for", RES_FOR, FLAG_DO | FLAG_START }, - { "while", RES_WHILE, FLAG_DO | FLAG_START }, - { "until", RES_UNTIL, FLAG_DO | FLAG_START }, - { "do", RES_DO, FLAG_DONE }, - { "done", RES_DONE, FLAG_END } - }; - struct reserved_combo *r; - for (r=reserved_list; -#define NRES sizeof(reserved_list)/sizeof(struct reserved_combo) - rdata, r->literal) == 0) { - debug_printf("found reserved word %s, code %d\n",r->literal,r->code); - if (r->flag & FLAG_START) { - struct p_context *new = xmalloc(sizeof(struct p_context)); - debug_printf("push stack\n"); - *new = *ctx; /* physical copy */ - initialize_context(ctx); - ctx->stack=new; - } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<code))) { - syntax(); - ctx->w = RES_SNTX; - b_reset (dest); - return 1; - } - ctx->w=r->code; - ctx->old_flag = r->flag; - if (ctx->old_flag & FLAG_END) { - struct p_context *old; - debug_printf("pop stack\n"); - old = ctx->stack; - old->child->group = ctx->list_head; - old->child->subshell = 0; - *ctx = *old; /* physical copy */ - free(old); - } - b_reset (dest); - return 1; - } - } - return 0; -} - -/* normal return is 0. - * Syntax or xglob errors return 1. */ -static int done_word(o_string *dest, struct p_context *ctx) -{ - struct child_prog *child=ctx->child; - glob_t *glob_target; - int gr, flags = 0; - - debug_printf("done_word: %s %p\n", dest->data, child); - if (dest->length == 0 && !dest->nonnull) { - debug_printf(" true null, ignored\n"); - return 0; - } - if (ctx->pending_redirect) { - glob_target = &ctx->pending_redirect->word; - } else { - if (child->group) { - syntax(); - return 1; /* syntax error, groups and arglists don't mix */ - } - if (!child->argv) { - debug_printf("checking %s for reserved-ness\n",dest->data); - if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX; - } - glob_target = &child->glob_result; - if (child->argv) flags |= GLOB_APPEND; - } - gr = xglob(dest, flags, glob_target); - if (gr != 0) return 1; - - b_reset(dest); - if (ctx->pending_redirect) { - ctx->pending_redirect=NULL; - if (glob_target->gl_pathc != 1) { - error_msg("ambiguous redirect"); - return 1; - } - } else { - child->argv = glob_target->gl_pathv; - } - return 0; -} - -/* The only possible error here is out of memory, in which case - * xmalloc exits. */ -static int done_command(struct p_context *ctx) -{ - /* The child is really already in the pipe structure, so - * advance the pipe counter and make a new, null child. - * Only real trickiness here is that the uncommitted - * child structure, to which ctx->child points, is not - * counted in pi->num_progs. */ - struct pipe *pi=ctx->pipe; - struct child_prog *prog=ctx->child; - - if (prog && prog->group == NULL - && prog->argv == NULL - && prog->redirects == NULL) { - debug_printf("done_command: skipping null command\n"); - return 0; - } else if (prog) { - pi->num_progs++; - debug_printf("done_command: num_progs incremented to %d\n",pi->num_progs); - } else { - debug_printf("done_command: initializing\n"); - } - pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1)); - - prog = pi->progs + pi->num_progs; - prog->redirects = NULL; - prog->argv = NULL; - prog->is_stopped = 0; - prog->group = NULL; - prog->glob_result.gl_pathv = NULL; - prog->family = pi; - - ctx->child=prog; - /* but ctx->pipe and ctx->list_head remain unchanged */ - return 0; -} - -static int done_pipe(struct p_context *ctx, pipe_style type) -{ - struct pipe *new_p; - done_command(ctx); /* implicit closure of previous command */ - debug_printf("done_pipe, type %d\n", type); - ctx->pipe->followup = type; - ctx->pipe->r_mode = ctx->w; - new_p=new_pipe(); - ctx->pipe->next = new_p; - ctx->pipe = new_p; - ctx->child = NULL; - done_command(ctx); /* set up new pipe to accept commands */ - return 0; -} - -/* peek ahead in the in_str to find out if we have a "&n" construct, - * as in "2>&1", that represents duplicating a file descriptor. - * returns either -2 (syntax error), -1 (no &), or the number found. - */ -static int redirect_dup_num(struct in_str *input) -{ - int ch, d=0, ok=0; - ch = b_peek(input); - if (ch != '&') return -1; - - b_getch(input); /* get the & */ - ch=b_peek(input); - if (ch == '-') { - b_getch(input); - return -3; /* "-" represents "close me" */ - } - while (isdigit(ch)) { - d = d*10+(ch-'0'); - ok=1; - b_getch(input); - ch = b_peek(input); - } - if (ok) return d; - - error_msg("ambiguous redirect"); - return -2; -} - -/* If a redirect is immediately preceded by a number, that number is - * supposed to tell which file descriptor to redirect. This routine - * looks for such preceding numbers. In an ideal world this routine - * needs to handle all the following classes of redirects... - * echo 2>foo # redirects fd 2 to file "foo", nothing passed to echo - * echo 49>foo # redirects fd 49 to file "foo", nothing passed to echo - * echo -2>foo # redirects fd 1 to file "foo", "-2" passed to echo - * echo 49x>foo # redirects fd 1 to file "foo", "49x" passed to echo - * A -1 output from this program means no valid number was found, so the - * caller should use the appropriate default for this redirection. - */ -static int redirect_opt_num(o_string *o) -{ - int num; - - if (o->length==0) return -1; - for(num=0; numlength; num++) { - if (!isdigit(*(o->data+num))) { - return -1; - } - } - /* reuse num (and save an int) */ - num=atoi(o->data); - b_reset(o); - return num; -} - -FILE *generate_stream_from_list(struct pipe *head) -{ - FILE *pf; -#if 1 - int pid, channel[2]; - if (pipe(channel)<0) perror_msg_and_die("pipe"); - pid=fork(); - if (pid<0) { - perror_msg_and_die("fork"); - } else if (pid==0) { - close(channel[0]); - if (channel[1] != 1) { - dup2(channel[1],1); - close(channel[1]); - } -#if 0 -#define SURROGATE "surrogate response" - write(1,SURROGATE,sizeof(SURROGATE)); - _exit(run_list(head)); -#else - _exit(run_list_real(head)); /* leaks memory */ -#endif - } - debug_printf("forked child %d\n",pid); - close(channel[1]); - pf = fdopen(channel[0],"r"); - debug_printf("pipe on FILE *%p\n",pf); -#else - free_pipe_list(head,0); - pf=popen("echo surrogate response","r"); - debug_printf("started fake pipe on FILE *%p\n",pf); -#endif - return pf; -} - -/* this version hacked for testing purposes */ -/* return code is exit status of the process that is run. */ -static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end) -{ - int retcode; - o_string result=NULL_O_STRING; - struct p_context inner; - FILE *p; - struct in_str pipe_str; - initialize_context(&inner); - - /* recursion to generate command */ - retcode = parse_stream(&result, &inner, input, subst_end); - if (retcode != 0) return retcode; /* syntax error or EOF */ - done_word(&result, &inner); - done_pipe(&inner, PIPE_SEQ); - b_free(&result); - - p=generate_stream_from_list(inner.list_head); - if (p==NULL) return 1; - mark_open(fileno(p)); - setup_file_in_str(&pipe_str, p); - - /* now send results of command back into original context */ - retcode = parse_stream(dest, ctx, &pipe_str, '\0'); - /* XXX In case of a syntax error, should we try to kill the child? - * That would be tough to do right, so just read until EOF. */ - if (retcode == 1) { - while (b_getch(&pipe_str)!=EOF) { /* discard */ }; - } - - debug_printf("done reading from pipe, pclose()ing\n"); - /* This is the step that wait()s for the child. Should be pretty - * safe, since we just read an EOF from its stdout. We could try - * to better, by using wait(), and keeping track of background jobs - * at the same time. That would be a lot of work, and contrary - * to the KISS philosophy of this program. */ - mark_closed(fileno(p)); - retcode=pclose(p); - free_pipe_list(inner.list_head,0); - debug_printf("pclosed, retcode=%d\n",retcode); - /* XXX this process fails to trim a single trailing newline */ - return retcode; -} - -static int parse_group(o_string *dest, struct p_context *ctx, - struct in_str *input, int ch) -{ - int rcode, endch=0; - struct p_context sub; - struct child_prog *child = ctx->child; - if (child->argv) { - syntax(); - return 1; /* syntax error, groups and arglists don't mix */ - } - initialize_context(&sub); - switch(ch) { - case '(': endch=')'; child->subshell=1; break; - case '{': endch='}'; break; - default: syntax(); /* really logic error */ - } - rcode=parse_stream(dest,&sub,input,endch); - done_word(dest,&sub); /* finish off the final word in the subcontext */ - done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */ - child->group = sub.list_head; - return rcode; - /* child remains "open", available for possible redirects */ -} - -/* basically useful version until someone wants to get fancier, - * see the bash man page under "Parameter Expansion" */ -static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src) -{ - const char *p=NULL; - if (src->data) { - p = getenv(src->data); - if (!p) - p = get_local_var(src->data); - } - if (p) parse_string(dest, ctx, p); /* recursion */ - b_free(src); -} - -/* return code: 0 for OK, 1 for syntax error */ -static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input) -{ - int i, advance=0; - o_string alt=NULL_O_STRING; - char sep[]=" "; - int ch = input->peek(input); /* first character after the $ */ - debug_printf("handle_dollar: ch=%c\n",ch); - if (isalpha(ch)) { - while(ch=b_peek(input),isalnum(ch) || ch=='_') { - b_getch(input); - b_addchr(&alt,ch); - } - lookup_param(dest, ctx, &alt); - } else if (isdigit(ch)) { - i = ch-'0'; /* XXX is $0 special? */ - if (i 0) b_adduint(dest, last_bg_pid); - advance = 1; - break; - case '?': - b_adduint(dest,last_return_code); - advance = 1; - break; - case '#': - b_adduint(dest,global_argc ? global_argc-1 : 0); - advance = 1; - break; - case '{': - b_getch(input); - /* XXX maybe someone will try to escape the '}' */ - while(ch=b_getch(input),ch!=EOF && ch!='}') { - b_addchr(&alt,ch); - } - if (ch != '}') { - syntax(); - return 1; - } - lookup_param(dest, ctx, &alt); - break; - case '(': - b_getch(input); - process_command_subs(dest, ctx, input, ')'); - break; - case '*': - sep[0]=ifs[0]; - for (i=1; iquote); - } - /* Eat the character if the flag was set. If the compiler - * is smart enough, we could substitute "b_getch(input);" - * for all the "advance = 1;" above, and also end up with - * a nice size-optimized program. Hah! That'll be the day. - */ - if (advance) b_getch(input); - return 0; -} - -int parse_string(o_string *dest, struct p_context *ctx, const char *src) -{ - struct in_str foo; - setup_string_in_str(&foo, src); - return parse_stream(dest, ctx, &foo, '\0'); -} - -/* return code is 0 for normal exit, 1 for syntax error */ -int parse_stream(o_string *dest, struct p_context *ctx, - struct in_str *input, int end_trigger) -{ - unsigned int ch, m; - int redir_fd; - redir_type redir_style; - int next; - - /* Only double-quote state is handled in the state variable dest->quote. - * A single-quote triggers a bypass of the main loop until its mate is - * found. When recursing, quote state is passed in via dest->quote. */ - - debug_printf("parse_stream, end_trigger=%d\n",end_trigger); - while ((ch=b_getch(input))!=EOF) { - m = map[ch]; - next = (ch == '\n') ? 0 : b_peek(input); - debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d\n", - ch,ch,m,dest->quote); - if (m==0 || ((m==1 || m==2) && dest->quote)) { - b_addqchr(dest, ch, dest->quote); - } else { - if (m==2) { /* unquoted IFS */ - done_word(dest, ctx); - /* If we aren't performing a substitution, treat a newline as a - * command separator. */ - if (end_trigger != '\0' && ch=='\n') - done_pipe(ctx,PIPE_SEQ); - } - if (ch == end_trigger && !dest->quote && ctx->w==RES_NONE) { - debug_printf("leaving parse_stream (triggered)\n"); - return 0; - } -#if 0 - if (ch=='\n') { - /* Yahoo! Time to run with it! */ - done_pipe(ctx,PIPE_SEQ); - run_list(ctx->list_head); - initialize_context(ctx); - } -#endif - if (m!=2) switch (ch) { - case '#': - if (dest->length == 0 && !dest->quote) { - while(ch=b_peek(input),ch!=EOF && ch!='\n') { b_getch(input); } - } else { - b_addqchr(dest, ch, dest->quote); - } - break; - case '\\': - if (next == EOF) { - syntax(); - return 1; - } - b_addqchr(dest, '\\', dest->quote); - b_addqchr(dest, b_getch(input), dest->quote); - break; - case '$': - if (handle_dollar(dest, ctx, input)!=0) return 1; - break; - case '\'': - dest->nonnull = 1; - while(ch=b_getch(input),ch!=EOF && ch!='\'') { - b_addchr(dest,ch); - } - if (ch==EOF) { - syntax(); - return 1; - } - break; - case '"': - dest->nonnull = 1; - dest->quote = !dest->quote; - break; - case '`': - process_command_subs(dest, ctx, input, '`'); - break; - case '>': - redir_fd = redirect_opt_num(dest); - done_word(dest, ctx); - redir_style=REDIRECT_OVERWRITE; - if (next == '>') { - redir_style=REDIRECT_APPEND; - b_getch(input); - } else if (next == '(') { - syntax(); /* until we support >(list) Process Substitution */ - return 1; - } - setup_redirect(ctx, redir_fd, redir_style, input); - break; - case '<': - redir_fd = redirect_opt_num(dest); - done_word(dest, ctx); - redir_style=REDIRECT_INPUT; - if (next == '<') { - redir_style=REDIRECT_HEREIS; - b_getch(input); - } else if (next == '>') { - redir_style=REDIRECT_IO; - b_getch(input); - } else if (next == '(') { - syntax(); /* until we support <(list) Process Substitution */ - return 1; - } - setup_redirect(ctx, redir_fd, redir_style, input); - break; - case ';': - done_word(dest, ctx); - done_pipe(ctx,PIPE_SEQ); - break; - case '&': - done_word(dest, ctx); - if (next=='&') { - b_getch(input); - done_pipe(ctx,PIPE_AND); - } else { - done_pipe(ctx,PIPE_BG); - } - break; - case '|': - done_word(dest, ctx); - if (next=='|') { - b_getch(input); - done_pipe(ctx,PIPE_OR); - } else { - /* we could pick up a file descriptor choice here - * with redirect_opt_num(), but bash doesn't do it. - * "echo foo 2| cat" yields "foo 2". */ - done_command(ctx); - } - break; - case '(': - case '{': - if (parse_group(dest, ctx, input, ch)!=0) return 1; - break; - case ')': - case '}': - syntax(); /* Proper use of this character caught by end_trigger */ - return 1; - break; - default: - syntax(); /* this is really an internal logic error */ - return 1; - } - } - } - /* complain if quote? No, maybe we just finished a command substitution - * that was quoted. Example: - * $ echo "`cat foo` plus more" - * and we just got the EOF generated by the subshell that ran "cat foo" - * The only real complaint is if we got an EOF when end_trigger != '\0', - * that is, we were really supposed to get end_trigger, and never got - * one before the EOF. Can't use the standard "syntax error" return code, - * so that parse_stream_outer can distinguish the EOF and exit smoothly. */ - debug_printf("leaving parse_stream (EOF)\n"); - if (end_trigger != '\0') return -1; - return 0; -} - -void mapset(const unsigned char *set, int code) -{ - const unsigned char *s; - for (s=set; *s; s++) map[*s] = code; -} - -void update_ifs_map(void) -{ - /* char *ifs and char map[256] are both globals. */ - ifs = getenv("IFS"); - if (ifs == NULL) ifs=" \t\n"; - /* Precompute a list of 'flow through' behavior so it can be treated - * quickly up front. Computation is necessary because of IFS. - * Special case handling of IFS == " \t\n" is not implemented. - * The map[] array only really needs two bits each, and on most machines - * that would be faster because of the reduced L1 cache footprint. - */ - memset(map,0,sizeof(map)); /* most characters flow through always */ - mapset("\\$'\"`", 3); /* never flow through */ - mapset("<>;&|(){}#", 1); /* flow through if quoted */ - mapset(ifs, 2); /* also flow through if quoted */ -} - -/* most recursion does not come through here, the exeception is - * from builtin_source() */ -int parse_stream_outer(struct in_str *inp) -{ - - struct p_context ctx; - o_string temp=NULL_O_STRING; - int rcode; - do { - initialize_context(&ctx); - update_ifs_map(); - inp->promptmode=1; - rcode = parse_stream(&temp, &ctx, inp, '\n'); - done_word(&temp, &ctx); - done_pipe(&ctx,PIPE_SEQ); - run_list(ctx.list_head); - b_free(&temp); - } while (rcode != -1); /* loop on syntax errors, return on EOF */ - return 0; -} - -static int parse_string_outer(const char *s) -{ - struct in_str input; - setup_string_in_str(&input, s); - return parse_stream_outer(&input); -} - -static int parse_file_outer(FILE *f) -{ - int rcode; - struct in_str input; - setup_file_in_str(&input, f); - rcode = parse_stream_outer(&input); - return rcode; -} - -/* Make sure we have a controlling tty. If we get started under a job - * aware app (like bash for example), make sure we are now in charge so - * we don't fight over who gets the foreground */ -static void setup_job_control() -{ - static pid_t shell_pgrp; - /* Loop until we are in the foreground. */ - while (tcgetpgrp (shell_terminal) != (shell_pgrp = getpgrp ())) - kill (- shell_pgrp, SIGTTIN); - - /* Ignore interactive and job-control signals. */ - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - signal(SIGTERM, SIG_IGN); - signal(SIGTSTP, SIG_IGN); - signal(SIGTTIN, SIG_IGN); - signal(SIGTTOU, SIG_IGN); - signal(SIGCHLD, SIG_IGN); - - /* Put ourselves in our own process group. */ - setsid(); - shell_pgrp = getpid (); - setpgid (shell_pgrp, shell_pgrp); - - /* Grab control of the terminal. */ - tcsetpgrp(shell_terminal, shell_pgrp); -} - -int hush_main(int argc, char **argv) -{ - int opt; - FILE *input; - char **e = environ; - - /* XXX what should these be while sourcing /etc/profile? */ - global_argc = argc; - global_argv = argv; - - /* (re?) initialize globals. Sometimes hush_main() ends up calling - * hush_main(), therefore we cannot rely on the BSS to zero out this - * stuff. Reset these to 0 every time. */ - ifs = NULL; - /* map[] is taken care of with call to update_ifs_map() */ - fake_mode = 0; - interactive = 0; - close_me_head = NULL; - last_bg_pid = 0; - job_list = NULL; - last_jobid = 0; - - /* Initialize some more globals to non-zero values */ - set_cwd(); -#ifdef BB_FEATURE_COMMAND_EDITING - cmdedit_set_initial_prompt(); -#else - PS1 = NULL; -#endif - PS2 = "> "; - - /* initialize our shell local variables with the values - * currently living in the environment */ - if (e) { - for (; *e; e++) - set_local_var(*e, 2); /* without call putenv() */ - } - - last_return_code=EXIT_SUCCESS; - - - if (argv[0] && argv[0][0] == '-') { - debug_printf("\nsourcing /etc/profile\n"); - if ((input = fopen("/etc/profile", "r")) != NULL) { - mark_open(fileno(input)); - parse_file_outer(input); - mark_closed(fileno(input)); - fclose(input); - } - } - input=stdin; - - while ((opt = getopt(argc, argv, "c:xif")) > 0) { - switch (opt) { - case 'c': - { - global_argv = argv+optind; - global_argc = argc-optind; - opt = parse_string_outer(optarg); - goto final_return; - } - break; - case 'i': - interactive++; - break; - case 'f': - fake_mode++; - break; - default: -#ifndef BB_VER - fprintf(stderr, "Usage: sh [FILE]...\n" - " or: sh -c command [args]...\n\n"); - exit(EXIT_FAILURE); -#else - show_usage(); -#endif - } - } - /* A shell is interactive if the `-i' flag was given, or if all of - * the following conditions are met: - * no -c command - * no arguments remaining or the -s flag given - * standard input is a terminal - * standard output is a terminal - * Refer to Posix.2, the description of the `sh' utility. */ - if (argv[optind]==NULL && input==stdin && - isatty(fileno(stdin)) && isatty(fileno(stdout))) { - interactive++; - } - - debug_printf("\ninteractive=%d\n", interactive); - if (interactive) { - /* Looks like they want an interactive shell */ - fprintf(stdout, "\nhush -- the humble shell v0.01 (testing)\n\n"); - setup_job_control(); - } - - if (argv[optind]==NULL) { - opt=parse_file_outer(stdin); - goto final_return; - } - - debug_printf("\nrunning script '%s'\n", argv[optind]); - global_argv = argv+optind; - global_argc = argc-optind; - input = xfopen(argv[optind], "r"); - opt = parse_file_outer(input); - -#ifdef BB_FEATURE_CLEAN_UP - fclose(input); - if (cwd && cwd != unknown) - free((char*)cwd); - { - struct variables *cur, *tmp; - for(cur = top_vars; cur; cur = tmp) { - tmp = cur->next; - if (!cur->flg_read_only) { - free(cur->name); - free(cur->value); - free(cur); - } - } - } -#endif - -final_return: - return(opt?opt:last_return_code); -} diff --git a/busybox/id.c b/busybox/id.c deleted file mode 100644 index 85b288c0c..000000000 --- a/busybox/id.c +++ /dev/null @@ -1,97 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini id implementation for busybox - * - * Copyright (C) 2000 by Randolph Chung - * - * 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 "busybox.h" -#include -#include -#include -#include -#include - -extern int id_main(int argc, char **argv) -{ - int no_user = 0, no_group = 0, print_real = 0; - int name_not_number = 0; - char user[9], group[9]; - long gid; - long pwnam, grnam; - int opt; - - gid = 0; - - while ((opt = getopt(argc, argv, "ugrn")) > 0) { - switch (opt) { - case 'u': - no_group++; - break; - case 'g': - no_user++; - break; - case 'r': - print_real++; - break; - case 'n': - name_not_number++; - break; - default: - show_usage(); - } - } - - if (no_user && no_group) show_usage(); - - if (argv[optind] == NULL) { - if (print_real) { - my_getpwuid(user, getuid()); - my_getgrgid(group, getgid()); - } else { - my_getpwuid(user, geteuid()); - my_getgrgid(group, getegid()); - } - } else { - strncpy(user, argv[optind], 8); - user[8] = '\0'; - gid = my_getpwnamegid(user); - my_getgrgid(group, gid); - } - - pwnam=my_getpwnam(user); - grnam=my_getgrnam(group); - - if (no_group) { - if(name_not_number && user) - puts(user); - else - printf("%ld\n", pwnam); - } else if (no_user) { - if(name_not_number && group) - puts(group); - else - printf("%ld\n", grnam); - } else { - printf("uid=%ld(%s) gid=%ld(%s)\n", pwnam, user, grnam, group); - } - return(0); -} - - -/* END CODE */ diff --git a/busybox/ifconfig.c b/busybox/ifconfig.c deleted file mode 100644 index 5f8b0eed6..000000000 --- a/busybox/ifconfig.c +++ /dev/null @@ -1,492 +0,0 @@ -/* ifconfig - * - * Similar to the standard Unix ifconfig, but with only the necessary - * parts for AF_INET, and without any printing of if info (for now). - * - * Bjorn Wesen, Axis Communications AB - * - * - * Authors of the original ifconfig was: - * Fred N. van Kempen, - * - * 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. - * - * $Id: ifconfig.c,v 1.11.2.1 2001/08/10 18:22:15 andersen Exp $ - * - */ - -/* - * Heavily modified by Manuel Novoa III Mar 6, 2001 - * - * From initial port to busybox, removed most of the redundancy by - * converting to a table-driven approach. Added several (optional) - * args missing from initial port. - * - * Still missing: media, tunnel. - */ - -#include -#include -#include // strcmp and friends -#include // isdigit and friends -#include /* offsetof */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#ifdef BB_FEATURE_IFCONFIG_SLIP -#include -#endif - -/* I don't know if this is needed for busybox or not. Anyone? */ -#define QUESTIONABLE_ALIAS_CASE - - -/* Defines for glibc2.0 users. */ -#ifndef SIOCSIFTXQLEN -#define SIOCSIFTXQLEN 0x8943 -#define SIOCGIFTXQLEN 0x8942 -#endif - -/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */ -#ifndef ifr_qlen -#define ifr_qlen ifr_ifru.ifru_mtu -#endif - -#ifndef IFF_DYNAMIC -#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */ -#endif - -/* - * Here are the bit masks for the "flags" member of struct options below. - * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'. - * CLR clears the flag; SET sets the flag; ARG signifies (optional) arg. - */ -#define N_CLR 0x01 -#define M_CLR 0x02 -#define N_SET 0x04 -#define M_SET 0x08 -#define N_ARG 0x10 -#define M_ARG 0x20 - -#define M_MASK (M_CLR | M_SET | M_ARG) -#define N_MASK (N_CLR | N_SET | N_ARG) -#define SET_MASK (N_SET | M_SET) -#define CLR_MASK (N_CLR | M_CLR) -#define SET_CLR_MASK (SET_MASK | CLR_MASK) -#define ARG_MASK (M_ARG | N_ARG) - -/* - * Here are the bit masks for the "arg_flags" member of struct options below. - */ - -/* - * cast type: - * 00 int - * 01 char * - * 02 HOST_COPY in_ether - * 03 HOST_COPY INET_resolve - */ -#define A_CAST_TYPE 0x03 -/* - * map type: - * 00 not a map type (mem_start, io_addr, irq) - * 04 memstart (unsigned long) - * 08 io_addr (unsigned short) - * 0C irq (unsigned char) - */ -#define A_MAP_TYPE 0x0C -#define A_ARG_REQ 0x10 /* Set if an arg is required. */ -#define A_NETMASK 0x20 /* Set if netmask (check for multiple sets). */ -#define A_SET_AFTER 0x40 /* Set a flag at the end. */ -#define A_COLON_CHK 0x80 /* Is this needed? See below. */ - -/* - * These defines are for dealing with the A_CAST_TYPE field. - */ -#define A_CAST_CHAR_PTR 0x01 -#define A_CAST_RESOLVE 0x01 -#define A_CAST_HOST_COPY 0x02 -#define A_CAST_HOST_COPY_IN_ETHER A_CAST_HOST_COPY -#define A_CAST_HOST_COPY_RESOLVE (A_CAST_HOST_COPY | A_CAST_RESOLVE) - -/* - * These defines are for dealing with the A_MAP_TYPE field. - */ -#define A_MAP_ULONG 0x04 /* memstart */ -#define A_MAP_USHORT 0x08 /* io_addr */ -#define A_MAP_UCHAR 0x0C /* irq */ - -/* - * Define the bit masks signifying which operations to perform for each arg. - */ - -#define ARG_METRIC (A_ARG_REQ /*| A_CAST_INT*/) -#define ARG_MTU (A_ARG_REQ /*| A_CAST_INT*/) -#define ARG_TXQUEUELEN (A_ARG_REQ /*| A_CAST_INT*/) -#define ARG_MEM_START (A_ARG_REQ | A_MAP_ULONG) -#define ARG_IO_ADDR (A_ARG_REQ | A_MAP_USHORT) -#define ARG_IRQ (A_ARG_REQ | A_MAP_UCHAR) -#define ARG_DSTADDR (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE) -#define ARG_NETMASK (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_NETMASK) -#define ARG_BROADCAST (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER) -#define ARG_HW (A_ARG_REQ | A_CAST_HOST_COPY_IN_ETHER) -#define ARG_POINTOPOINT (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER) -#define ARG_KEEPALIVE (A_ARG_REQ | A_CAST_CHAR_PTR) -#define ARG_OUTFILL (A_ARG_REQ | A_CAST_CHAR_PTR) -#define ARG_HOSTNAME (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK) - - -/* - * Set up the tables. Warning! They must have corresponding order! - */ - -struct arg1opt { - const char *name; - unsigned short selector; - unsigned short ifr_offset; -}; - -struct options { - const char *name; - const unsigned char flags; - const unsigned char arg_flags; - const unsigned short selector; -}; - -#define ifreq_offsetof(x) offsetof(struct ifreq, x) - -static const struct arg1opt Arg1Opt[] = { - {"SIOCSIFMETRIC", SIOCSIFMETRIC, ifreq_offsetof(ifr_metric)}, - {"SIOCSIFMTU", SIOCSIFMTU, ifreq_offsetof(ifr_mtu)}, - {"SIOCSIFTXQLEN", SIOCSIFTXQLEN, ifreq_offsetof(ifr_qlen)}, - {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)}, - {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)}, - {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)}, -#ifdef BB_FEATURE_IFCONFIG_HW - {"SIOCSIFHWADDR", SIOCSIFHWADDR, ifreq_offsetof(ifr_hwaddr)}, -#endif - {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)}, -#ifdef SIOCSKEEPALIVE - {"SIOCSKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data)}, -#endif -#ifdef SIOCSOUTFILL - {"SIOCSOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data)}, -#endif -#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ - {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.mem_start)}, - {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.base_addr)}, - {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq)}, -#endif - /* Last entry if for unmatched (possibly hostname) arg. */ - {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)}, -}; - -static const struct options OptArray[] = { - {"metric", N_ARG, ARG_METRIC, 0}, - {"mtu", N_ARG, ARG_MTU, 0}, - {"txqueuelen", N_ARG, ARG_TXQUEUELEN, 0}, - {"dstaddr", N_ARG, ARG_DSTADDR, 0}, - {"netmask", N_ARG, ARG_NETMASK, 0}, - {"broadcast", N_ARG | M_CLR, ARG_BROADCAST, IFF_BROADCAST}, -#ifdef BB_FEATURE_IFCONFIG_HW - {"hw", N_ARG, ARG_HW, 0}, -#endif - {"pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT}, -#ifdef SIOCSKEEPALIVE - {"keepalive", N_ARG, ARG_KEEPALIVE, 0}, -#endif -#ifdef SIOCSOUTFILL - {"outfill", N_ARG, ARG_OUTFILL, 0}, -#endif -#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ - {"mem_start", N_ARG, ARG_MEM_START, 0}, - {"io_addr", N_ARG, ARG_IO_ADDR, 0}, - {"irq", N_ARG, ARG_IRQ, 0}, -#endif - {"arp", N_CLR | M_SET, 0, IFF_NOARP}, - {"trailers", N_CLR | M_SET, 0, IFF_NOTRAILERS}, - {"promisc", N_SET | M_CLR, 0, IFF_PROMISC}, - {"multicast", N_SET | M_CLR, 0, IFF_MULTICAST}, - {"allmulti", N_SET | M_CLR, 0, IFF_ALLMULTI}, - {"dynamic", N_SET | M_CLR, 0, IFF_DYNAMIC}, - {"up", N_SET , 0, (IFF_UP | IFF_RUNNING)}, - {"down", N_CLR , 0, IFF_UP}, - { NULL, 0, ARG_HOSTNAME, (IFF_UP | IFF_RUNNING)} -}; - -/* - * A couple of prototypes. - */ - -#ifdef BB_FEATURE_IFCONFIG_HW -static int in_ether(char *bufp, struct sockaddr *sap); -#endif - -#ifdef BB_FEATURE_IFCONFIG_STATUS -extern int interface_opt_a; -extern int display_interfaces(char *ifname); -#endif - -/* - * Our main function. - */ - -int ifconfig_main(int argc, char **argv) -{ - struct ifreq ifr; - struct sockaddr_in sai; -#ifdef BB_FEATURE_IFCONFIG_HW - struct sockaddr sa; -#endif - const struct arg1opt *a1op; - const struct options *op; - int sockfd; /* socket fd we use to manipulate stuff with */ - int goterr; - int selector; - char *p; - char host[128]; - unsigned char mask; - unsigned char did_flags; - - goterr = 0; - did_flags = 0; - - /* skip argv[0] */ - ++argv; - --argc; - -#ifdef BB_FEATURE_IFCONFIG_STATUS - if ((argc > 0) && (strcmp(*argv,"-a") == 0)) { - interface_opt_a = 1; - --argc; - ++argv; - } -#endif - - if(argc <= 1) { -#ifdef BB_FEATURE_IFCONFIG_STATUS - return display_interfaces(argc ? *argv : NULL); -#else - error_msg_and_die( "ifconfig was not compiled with interface status display support."); -#endif - } - - /* Create a channel to the NET kernel. */ - if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - perror_msg_and_die("socket"); - } - - /* get interface name */ - safe_strncpy(ifr.ifr_name, *argv, IFNAMSIZ); - - /* Process the remaining arguments. */ - while (*++argv != (char *) NULL) { - p = *argv; - mask = N_MASK; - if (*p == '-') { /* If the arg starts with '-'... */ - ++p; /* advance past it and */ - mask = M_MASK; /* set the appropriate mask. */ - } - for (op = OptArray ; op->name ; op++) { /* Find table entry. */ - if (strcmp(p,op->name) == 0) { /* If name matches... */ - if ((mask &= op->flags)) { /* set the mask and go. */ - goto FOUND_ARG;; - } - /* If we get here, there was a valid arg with an */ - /* invalid '-' prefix. */ - ++goterr; - goto LOOP; - } - } - - /* We fell through, so treat as possible hostname. */ - a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1; - mask = op->arg_flags; - goto HOSTNAME; - - FOUND_ARG: - if (mask & ARG_MASK) { - mask = op->arg_flags; - a1op = Arg1Opt + (op - OptArray); - if (mask & A_NETMASK & did_flags) { - show_usage(); - } - if (*++argv == NULL) { - if (mask & A_ARG_REQ) { - show_usage(); - } else { - --argv; - mask &= A_SET_AFTER; /* just for broadcast */ - } - } else { /* got an arg so process it */ - HOSTNAME: - did_flags |= (mask & A_NETMASK); - if (mask & A_CAST_HOST_COPY) { -#ifdef BB_FEATURE_IFCONFIG_HW - if (mask & A_CAST_RESOLVE) { -#endif - safe_strncpy(host, *argv, (sizeof host)); - sai.sin_family = AF_INET; - sai.sin_port = 0; - if (!strcmp(host, "default")) { - /* Default is special, meaning 0.0.0.0. */ - sai.sin_addr.s_addr = INADDR_ANY; - } else if (inet_aton(host, &sai.sin_addr) == 0) { - /* It's not a dotted quad. */ - ++goterr; - continue; - } - p = (char *) &sai; -#ifdef BB_FEATURE_IFCONFIG_HW - } else { /* A_CAST_HOST_COPY_IN_ETHER */ - /* This is the "hw" arg case. */ - if (strcmp("ether", *argv) || (*++argv == NULL)) { - show_usage(); - } - safe_strncpy(host, *argv, (sizeof host)); - if (in_ether(host, &sa)) { - fprintf(stderr, "invalid hw-addr %s\n", host); - ++goterr; - continue; - } - p = (char *) &sa; - } -#endif - memcpy((((char *)(&ifr)) + a1op->ifr_offset), - p, sizeof(struct sockaddr)); - } else { - unsigned int i = strtoul(*argv,NULL,0); - p = ((char *)(&ifr)) + a1op->ifr_offset; -#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ - if (mask & A_MAP_TYPE) { - if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) { - ++goterr; - continue; - } - if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) { - *((unsigned char *) p) = i; - } else if (mask & A_MAP_USHORT) { - *((unsigned short *) p) = i; - } else { - *((unsigned long *) p) = i; - } - } else -#endif - if (mask & A_CAST_CHAR_PTR) { - *((caddr_t *) p) = (caddr_t) i; - } else { /* A_CAST_INT */ - *((int *) p) = i; - } - } - - if (ioctl(sockfd, a1op->selector, &ifr) < 0) { - perror(a1op->name); - ++goterr; - continue; - } - -#ifdef QUESTIONABLE_ALIAS_CASE - if (mask & A_COLON_CHK) { - /* - * Don't do the set_flag() if the address is an alias with - * a - at the end, since it's deleted already! - Roman - * - * Should really use regex.h here, not sure though how well - * it'll go with the cross-platform support etc. - */ - char *ptr; - short int found_colon = 0; - for (ptr = ifr.ifr_name; *ptr; ptr++ ) { - if (*ptr == ':') { - found_colon++; - } - } - - if (found_colon && *(ptr - 1) == '-') { - continue; - } - } -#endif - } - if (!(mask & A_SET_AFTER)) { - continue; - } - mask = N_SET; - } - - if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { - perror("SIOCGIFFLAGS"); - ++goterr; - } else { - selector = op->selector; - if (mask & SET_MASK) { - ifr.ifr_flags |= selector; - } else { - ifr.ifr_flags &= ~selector; - } - if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { - perror("SIOCSIFFLAGS"); - ++goterr; - } - } - LOOP: - } /* end of while-loop */ - - return goterr; -} - -#ifdef BB_FEATURE_IFCONFIG_HW -/* Input an Ethernet address and convert to binary. */ -static int -in_ether(char *bufp, struct sockaddr *sap) -{ - unsigned char *ptr; - int i, j; - unsigned char val; - unsigned char c; - - sap->sa_family = ARPHRD_ETHER; - ptr = sap->sa_data; - - for (i = 0 ; i < ETH_ALEN ; i++) { - val = 0; - - /* We might get a semicolon here - not required. */ - if (i && (*bufp == ':')) { - bufp++; - } - - for (j=0 ; j<2 ; j++) { - c = *bufp; - if (c >= '0' && c <= '9') { - c -= '0'; - } else if (c >= 'a' && c <= 'f') { - c -= ('a' - 10); - } else if (c >= 'A' && c <= 'F') { - c -= ('A' - 10); - } else if (j && (c == ':' || c == 0)) { - break; - } else { - return -1; - } - ++bufp; - val <<= 4; - val += c; - } - *ptr++ = val; - } - - return (int) (*bufp); /* Error if we don't end at end of string. */ -} -#endif diff --git a/busybox/include/applets.h b/busybox/include/applets.h deleted file mode 100644 index 7d7517385..000000000 --- a/busybox/include/applets.h +++ /dev/null @@ -1,478 +0,0 @@ -/* - * applets.h - a listing of all busybox applets. - * - * If you write a new applet, you need to add an entry to this list to make - * busybox aware of it. - * - * It is CRUCIAL that this listing be kept in ascii order, otherwise the binary - * search lookup contributed by Gaute B Strokkenes stops working. If you value - * your kneecaps, you'll be sure to *make sure* that any changes made to this - * file result in the listing remaining in ascii order. You have been warned. - */ - -#undef APPLET -#undef APPLET_ODDNAME -#undef APPLET_NOUSAGE - - -#if defined(PROTOTYPES) - #define APPLET(a,b,c) extern int b(int argc, char **argv); - #define APPLET_NOUSAGE(a,b,c) extern int b(int argc, char **argv); - #define APPLET_ODDNAME(a,b,c,d) extern int b(int argc, char **argv); - extern const char usage_messages[]; -#elif defined(MAKE_USAGE) - #ifdef BB_FEATURE_VERBOSE_USAGE - #define APPLET(a,b,c) a##_trivial_usage "\n\n" a##_full_usage "\0" - #define APPLET_NOUSAGE(a,b,c) "\0" - #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\n\n" d##_full_usage "\0" - #else - #define APPLET(a,b,c) a##_trivial_usage "\0" - #define APPLET_NOUSAGE(a,b,c) "\0" - #define APPLET_ODDNAME(a,b,c,d) d##_trivial_usage "\0" - #endif -#elif defined(MAKE_LINKS) -# define APPLET(a,b,c) LINK c a -# define APPLET_NOUSAGE(a,b,c) LINK c a -# define APPLET_ODDNAME(a,b,c,d) LINK c a -#else - const struct BB_applet applets[] = { - #define APPLET(a,b,c) {#a,b,c}, - #define APPLET_NOUSAGE(a,b,c) {a,b,c}, - #define APPLET_ODDNAME(a,b,c,d) {a,b,c}, -#endif - - - -#ifdef BB_TEST - APPLET_NOUSAGE("[", test_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_ADJTIMEX - APPLET(adjtimex, adjtimex_main, _BB_DIR_SBIN) -#endif -#ifdef BB_AR - APPLET(ar, ar_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_ASH - APPLET_NOUSAGE("ash", ash_main, _BB_DIR_BIN) -#endif -#ifdef BB_BASENAME - APPLET(basename, basename_main, _BB_DIR_USR_BIN) -#endif - APPLET_NOUSAGE("busybox", busybox_main, _BB_DIR_BIN) -#ifdef BB_CAT - APPLET(cat, cat_main, _BB_DIR_BIN) -#endif -#ifdef BB_CHGRP - APPLET(chgrp, chgrp_main, _BB_DIR_BIN) -#endif -#ifdef BB_CHMOD - APPLET(chmod, chmod_main, _BB_DIR_BIN) -#endif -#ifdef BB_CHOWN - APPLET(chown, chown_main, _BB_DIR_BIN) -#endif -#ifdef BB_CHROOT - APPLET(chroot, chroot_main, _BB_DIR_USR_SBIN) -#endif -#ifdef BB_CHVT - APPLET(chvt, chvt_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_CLEAR - APPLET(clear, clear_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_CMP - APPLET(cmp, cmp_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_CP - APPLET(cp, cp_main, _BB_DIR_BIN) -#endif -#ifdef BB_CPIO - APPLET(cpio, cpio_main, _BB_DIR_BIN) -#endif -#ifdef BB_CUT - APPLET(cut, cut_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_DATE - APPLET(date, date_main, _BB_DIR_BIN) -#endif -#ifdef BB_DC - APPLET(dc, dc_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_DD - APPLET(dd, dd_main, _BB_DIR_BIN) -#endif -#ifdef BB_DEALLOCVT - APPLET(deallocvt, deallocvt_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_DF - APPLET(df, df_main, _BB_DIR_BIN) -#endif -#ifdef BB_DIRNAME - APPLET(dirname, dirname_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_DMESG - APPLET(dmesg, dmesg_main, _BB_DIR_BIN) -#endif -#ifdef BB_DOS2UNIX - APPLET(dos2unix, dos2unix_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_DPKG - APPLET(dpkg, dpkg_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_DPKG_DEB - APPLET_ODDNAME("dpkg-deb", dpkg_deb_main, _BB_DIR_USR_BIN, dpkg_deb) -#endif -#ifdef BB_DU - APPLET(du, du_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_DUMPKMAP - APPLET(dumpkmap, dumpkmap_main, _BB_DIR_BIN) -#endif -#ifdef BB_DUTMP - APPLET(dutmp, dutmp_main, _BB_DIR_USR_SBIN) -#endif -#ifdef BB_ECHO - APPLET(echo, echo_main, _BB_DIR_BIN) -#endif -#if defined(BB_FEATURE_GREP_EGREP_ALIAS) && defined(BB_GREP) - APPLET_NOUSAGE("egrep", grep_main, _BB_DIR_BIN) -#endif -#ifdef BB_ENV - APPLET(env, env_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_EXPR - APPLET(expr, expr_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TRUE_FALSE - APPLET(false, false_main, _BB_DIR_BIN) -#endif -#ifdef BB_FBSET - APPLET(fbset, fbset_main, _BB_DIR_USR_SBIN) -#endif -#ifdef BB_FDFLUSH - APPLET(fdflush, fdflush_main, _BB_DIR_BIN) -#endif -#ifdef BB_FIND - APPLET(find, find_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_FREE - APPLET(free, free_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_FREERAMDISK - APPLET(freeramdisk, freeramdisk_main, _BB_DIR_SBIN) -#endif -#ifdef BB_FSCK_MINIX - APPLET_ODDNAME("fsck.minix", fsck_minix_main, _BB_DIR_SBIN, fsck_minix) -#endif -#ifdef BB_GETOPT - APPLET(getopt, getopt_main, _BB_DIR_BIN) -#endif -#ifdef BB_GREP - APPLET(grep, grep_main, _BB_DIR_BIN) -#endif -#ifdef BB_GUNZIP - APPLET(gunzip, gunzip_main, _BB_DIR_BIN) -#endif -#ifdef BB_GZIP - APPLET(gzip, gzip_main, _BB_DIR_BIN) -#endif -#ifdef BB_HALT - APPLET(halt, halt_main, _BB_DIR_SBIN) -#endif -#ifdef BB_HEAD - APPLET(head, head_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_HOSTID - APPLET(hostid, hostid_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_HOSTNAME - APPLET(hostname, hostname_main, _BB_DIR_BIN) -#endif -#ifdef BB_HUSH - APPLET_NOUSAGE("hush", hush_main, _BB_DIR_BIN) -#endif -#ifdef BB_ID - APPLET(id, id_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_IFCONFIG - APPLET(ifconfig, ifconfig_main, _BB_DIR_SBIN) -#endif -#ifdef BB_INIT - APPLET(init, init_main, _BB_DIR_SBIN) -#endif -#ifdef BB_INSMOD - APPLET(insmod, insmod_main, _BB_DIR_SBIN) -#endif -#ifdef BB_KILL - APPLET(kill, kill_main, _BB_DIR_BIN) -#endif -#ifdef BB_KILLALL - APPLET(killall, kill_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_KLOGD - APPLET(klogd, klogd_main, _BB_DIR_SBIN) -#endif -#ifdef BB_LASH - APPLET(lash, lash_main, _BB_DIR_BIN) -#endif -#ifdef BB_LENGTH - APPLET(length, length_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_FEATURE_LINUXRC - APPLET_NOUSAGE("linuxrc", init_main, _BB_DIR_ROOT) -#endif -#ifdef BB_LN - APPLET(ln, ln_main, _BB_DIR_BIN) -#endif -#ifdef BB_LOADACM - APPLET(loadacm, loadacm_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_LOADFONT - APPLET(loadfont, loadfont_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_LOADKMAP - APPLET(loadkmap, loadkmap_main, _BB_DIR_SBIN) -#endif -#ifdef BB_LOGGER - APPLET(logger, logger_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_LOGNAME - APPLET(logname, logname_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_LOGREAD - APPLET(logread, logread_main, _BB_DIR_SBIN) -#endif -#ifdef BB_LS - APPLET(ls, ls_main, _BB_DIR_BIN) -#endif -#ifdef BB_LSMOD - APPLET(lsmod, lsmod_main, _BB_DIR_SBIN) -#endif -#ifdef BB_MAKEDEVS - APPLET(makedevs, makedevs_main, _BB_DIR_SBIN) -#endif -#ifdef BB_MD5SUM - APPLET(md5sum, md5sum_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_MKDIR - APPLET(mkdir, mkdir_main, _BB_DIR_BIN) -#endif -#ifdef BB_MKFIFO - APPLET(mkfifo, mkfifo_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_MKFS_MINIX - APPLET_ODDNAME("mkfs.minix", mkfs_minix_main, _BB_DIR_SBIN, mkfs_minix) -#endif -#ifdef BB_MKNOD - APPLET(mknod, mknod_main, _BB_DIR_BIN) -#endif -#ifdef BB_MKSWAP - APPLET(mkswap, mkswap_main, _BB_DIR_SBIN) -#endif -#ifdef BB_MKTEMP - APPLET(mktemp, mktemp_main, _BB_DIR_BIN) -#endif -#ifdef BB_MODPROBE - APPLET(modprobe, modprobe_main, _BB_DIR_SBIN) -#endif -#ifdef BB_MORE - APPLET(more, more_main, _BB_DIR_BIN) -#endif -#ifdef BB_MOUNT - APPLET(mount, mount_main, _BB_DIR_BIN) -#endif -#ifdef BB_MSH - APPLET_NOUSAGE("msh", msh_main, _BB_DIR_BIN) -#endif -#ifdef BB_MT - APPLET(mt, mt_main, _BB_DIR_BIN) -#endif -#ifdef BB_MV - APPLET(mv, mv_main, _BB_DIR_BIN) -#endif -#ifdef BB_NC - APPLET(nc, nc_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_NSLOOKUP - APPLET(nslookup, nslookup_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_PIDOF - APPLET(pidof, pidof_main, _BB_DIR_BIN) -#endif -#ifdef BB_PING - APPLET(ping, ping_main, _BB_DIR_BIN) -#endif -#ifdef BB_PIVOT_ROOT - APPLET(pivot_root, pivot_root_main, _BB_DIR_SBIN) -#endif -#ifdef BB_POWEROFF - APPLET(poweroff, poweroff_main, _BB_DIR_SBIN) -#endif -#ifdef BB_PRINTF - APPLET(printf, printf_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_PS - APPLET(ps, ps_main, _BB_DIR_BIN) -#endif -#ifdef BB_PWD - APPLET(pwd, pwd_main, _BB_DIR_BIN) -#endif -#ifdef BB_RDATE - APPLET(rdate, rdate_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_READLINK - APPLET(readlink, readlink_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_REBOOT - APPLET(reboot, reboot_main, _BB_DIR_SBIN) -#endif -#ifdef BB_RENICE - APPLET(renice, renice_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_RESET - APPLET(reset, reset_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_RM - APPLET(rm, rm_main, _BB_DIR_BIN) -#endif -#ifdef BB_RMDIR - APPLET(rmdir, rmdir_main, _BB_DIR_BIN) -#endif -#ifdef BB_RMMOD - APPLET(rmmod, rmmod_main, _BB_DIR_SBIN) -#endif -#ifdef BB_ROUTE - APPLET(route, route_main, _BB_DIR_SBIN) -#endif -#ifdef BB_RPM2CPIO - APPLET(rpm2cpio, rpm2cpio_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_SED - APPLET(sed, sed_main, _BB_DIR_BIN) -#endif -#ifdef BB_SETKEYCODES - APPLET(setkeycodes, setkeycodes_main, _BB_DIR_USR_BIN) -#endif -#if defined(BB_FEATURE_SH_IS_ASH) && defined(BB_ASH) - APPLET_NOUSAGE("sh", ash_main, _BB_DIR_BIN) -#elif defined(BB_FEATURE_SH_IS_HUSH) && defined(BB_HUSH) - APPLET_NOUSAGE("sh", hush_main, _BB_DIR_BIN) -#elif defined(BB_FEATURE_SH_IS_LASH) && defined(BB_LASH) - APPLET_NOUSAGE("sh", lash_main, _BB_DIR_BIN) -#elif defined(BB_FEATURE_SH_IS_MSH) && defined(BB_MSH) - APPLET_NOUSAGE("sh", msh_main, _BB_DIR_BIN) -#endif -#ifdef BB_SLEEP - APPLET(sleep, sleep_main, _BB_DIR_BIN) -#endif -#ifdef BB_SORT - APPLET(sort, sort_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_STTY - APPLET(stty, stty_main, _BB_DIR_BIN) -#endif -#ifdef BB_SWAPONOFF - APPLET(swapoff, swap_on_off_main, _BB_DIR_SBIN) -#endif -#ifdef BB_SWAPONOFF - APPLET(swapon, swap_on_off_main, _BB_DIR_SBIN) -#endif -#ifdef BB_SYNC - APPLET(sync, sync_main, _BB_DIR_BIN) -#endif -#ifdef BB_SYSLOGD - APPLET(syslogd, syslogd_main, _BB_DIR_SBIN) -#endif -#ifdef BB_TAIL - APPLET(tail, tail_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TAR - APPLET(tar, tar_main, _BB_DIR_BIN) -#endif -#ifdef BB_TEE - APPLET(tee, tee_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TELNET - APPLET(telnet, telnet_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TEST - APPLET(test, test_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TFTP - APPLET(tftp, tftp_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TOUCH - APPLET(touch, touch_main, _BB_DIR_BIN) -#endif -#ifdef BB_TR - APPLET(tr, tr_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TRACEROUTE - APPLET(traceroute, traceroute_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_TRUE_FALSE - APPLET(true, true_main, _BB_DIR_BIN) -#endif -#ifdef BB_TTY - APPLET(tty, tty_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_UMOUNT - APPLET(umount, umount_main, _BB_DIR_BIN) -#endif -#ifdef BB_UNAME - APPLET(uname, uname_main, _BB_DIR_BIN) -#endif -#ifdef BB_UNIQ - APPLET(uniq, uniq_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_UNIX2DOS - APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_UPDATE - APPLET(update, update_main, _BB_DIR_SBIN) -#endif -#ifdef BB_UPTIME - APPLET(uptime, uptime_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_USLEEP - APPLET(usleep, usleep_main, _BB_DIR_BIN) -#endif -#ifdef BB_UUDECODE - APPLET(uudecode, uudecode_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_UUENCODE - APPLET(uuencode, uuencode_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_VI - APPLET(vi, vi_main, _BB_DIR_BIN) -#endif -#ifdef BB_WATCHDOG - APPLET(watchdog, watchdog_main, _BB_DIR_SBIN) -#endif -#ifdef BB_WC - APPLET(wc, wc_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_WGET - APPLET(wget, wget_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_WHICH - APPLET(which, which_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_WHOAMI - APPLET(whoami, whoami_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_XARGS - APPLET(xargs, xargs_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_YES - APPLET(yes, yes_main, _BB_DIR_USR_BIN) -#endif -#ifdef BB_GUNZIP - APPLET(zcat, gunzip_main, _BB_DIR_BIN) -#endif - -#if !defined(PROTOTYPES) && !defined(MAKE_USAGE) - { 0,NULL,0 } -}; - -#endif diff --git a/busybox/include/busybox.h b/busybox/include/busybox.h deleted file mode 100644 index f79dac8c8..000000000 --- a/busybox/include/busybox.h +++ /dev/null @@ -1,106 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Busybox main internal header 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ -#ifndef _BB_INTERNAL_H_ -#define _BB_INTERNAL_H_ 1 - -#include "Config.h" - -#include -#include -#include -#include - -#define BB_BANNER "BusyBox v" BB_VER " (" BB_BT ")" - -#ifdef DMALLOC -#include "dmalloc.h" -#endif - -#include - - -enum Location { - _BB_DIR_ROOT = 0, - _BB_DIR_BIN, - _BB_DIR_SBIN, - _BB_DIR_USR_BIN, - _BB_DIR_USR_SBIN -}; - -struct BB_applet { - const char* name; - int (*main)(int argc, char** argv); - enum Location location; -}; -/* From busybox.c */ -extern const struct BB_applet applets[]; - -/* Automagically pull in all the applet function prototypes and - * applet usage strings. These are all of the form: - * extern int foo_main(int argc, char **argv); - * extern const char foo_usage[]; - * These are all autogenerated from the set of currently defined applets. - */ -#define PROTOTYPES -#include "applets.h" -#undef PROTOTYPES - -#ifdef BB_FEATURE_BUFFERS_GO_ON_STACK -#define RESERVE_BB_BUFFER(buffer,len) char buffer[len] -#define RESERVE_BB_UBUFFER(buffer,len) unsigned char buffer[len] -#define RELEASE_BB_BUFFER(buffer) ((void)0) -#else -#ifdef BB_FEATURE_BUFFERS_GO_IN_BSS -#define RESERVE_BB_BUFFER(buffer,len) static char buffer[len] -#define RESERVE_BB_UBUFFER(buffer,len) static unsigned char buffer[len] -#define RELEASE_BB_BUFFER(buffer) ((void)0) -#else -#define RESERVE_BB_BUFFER(buffer,len) char *buffer=xmalloc(len) -#define RESERVE_BB_UBUFFER(buffer,len) unsigned char *buffer=xmalloc(len) -#define RELEASE_BB_BUFFER(buffer) free (buffer) -#endif -#endif - - -/* Bit map related macros -- libc5 doens't provide these... sigh. */ -#ifndef setbit -#define NBBY CHAR_BIT -#define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY)) -#define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY))) -#define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY))) -#define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0) -#endif - -#ifndef RB_POWER_OFF -/* Stop system and switch power off if possible. */ -#define RB_POWER_OFF 0x4321fedc -#endif - - -/* Pull in the utility routines from libbb */ -#include "libbb/libbb.h" - - - -#endif /* _BB_INTERNAL_H_ */ diff --git a/busybox/include/grp.h b/busybox/include/grp.h deleted file mode 100644 index 87d4115ce..000000000 --- a/busybox/include/grp.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __BB_GRP_H -#define __BB_GRP_H - -#if defined USE_SYSTEM_PWD_GRP -#include -#else - -#include -#include -#include - -/* The group structure */ -struct group -{ - char *gr_name; /* Group name. */ - char *gr_passwd; /* Password. */ - gid_t gr_gid; /* Group ID. */ - char **gr_mem; /* Member list. */ -}; - -extern void setgrent __P ((void)); -extern void endgrent __P ((void)); -extern struct group * getgrent __P ((void)); - -extern struct group * getgrgid __P ((__const gid_t gid)); -extern struct group * getgrnam __P ((__const char * name)); - -extern struct group * fgetgrent __P ((FILE * file)); - -extern int setgroups __P ((size_t n, __const gid_t * groups)); -extern int initgroups __P ((__const char * user, gid_t gid)); - -extern struct group * __getgrent __P ((int grp_fd)); - -#endif /* USE_SYSTEM_PWD_GRP */ -#endif /* __BB_GRP_H */ - diff --git a/busybox/include/libbb.h b/busybox/include/libbb.h deleted file mode 100644 index 30f0bb9a7..000000000 --- a/busybox/include/libbb.h +++ /dev/null @@ -1,326 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Busybox main internal header 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ -#ifndef __LIBBB_H__ -#define __LIBBB_H__ 1 - -#include -#include -#include -#include - -#include - -#ifdef DMALLOC -#include "dmalloc.h" -#endif - -#include - -#ifndef _BB_INTERNAL_H_ -#include "../busybox.h" -#endif - -#if (__GNU_LIBRARY__ < 5) && (!defined __dietlibc__) -/* libc5 doesn't define socklen_t */ -typedef unsigned int socklen_t; -/* libc5 doesn't implement BSD 4.4 daemon() */ -extern int daemon (int nochdir, int noclose); -/* libc5 doesn't implement strtok_r */ -char *strtok_r(char *s, const char *delim, char **ptrptr); -#endif - -/* Some useful definitions */ -#define FALSE ((int) 0) -#define TRUE ((int) 1) -#define SKIP ((int) 2) - -/* for mtab.c */ -#define MTAB_GETMOUNTPT '1' -#define MTAB_GETDEVICE '2' - -#define BUF_SIZE 8192 -#define EXPAND_ALLOC 1024 - -static inline int is_decimal(int ch) { return ((ch >= '0') && (ch <= '9')); } -static inline int is_octal(int ch) { return ((ch >= '0') && (ch <= '7')); } - -/* Macros for min/max. */ -#ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) -#endif - -#ifndef MAX -#define MAX(a,b) (((a)>(b))?(a):(b)) -#endif - - - -extern void show_usage(void) __attribute__ ((noreturn)); -extern void error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))); -extern void error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))); -extern void perror_msg(const char *s, ...); -extern void perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn)); -extern void vherror_msg(const char *s, va_list p); -extern void herror_msg(const char *s, ...); -extern void herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn)); - -/* These two are used internally -- you shouldn't need to use them */ -extern void verror_msg(const char *s, va_list p); -extern void vperror_msg(const char *s, va_list p); - -const char *mode_string(int mode); -const char *time_string(time_t timeVal); -int is_directory(const char *name, int followLinks, struct stat *statBuf); -int isDevice(const char *name); - -int remove_file(const char *path, int flags); -int copy_file(const char *source, const char *dest, int flags); -int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize); -char *buildName(const char *dirName, const char *fileName); -int makeString(int argc, const char **argv, char *buf, int bufLen); -char *getChunk(int size); -char *chunkstrdup(const char *str); -void freeChunks(void); -ssize_t safe_read(int fd, void *buf, size_t count); -int full_write(int fd, const char *buf, int len); -int full_read(int fd, char *buf, int len); -int recursive_action(const char *fileName, int recurse, int followLinks, int depthFirst, - int (*fileAction) (const char *fileName, struct stat* statbuf, void* userData), - int (*dirAction) (const char *fileName, struct stat* statbuf, void* userData), - void* userData); - -extern int parse_mode( const char* s, mode_t* theMode); - -extern int get_kernel_revision(void); - -extern int get_console_fd(char* tty_name); -extern struct mntent *find_mount_point(const char *name, const char *table); -extern void write_mtab(char* blockDevice, char* directory, - char* filesystemType, long flags, char* string_flags); -extern void erase_mtab(const char * name); -extern long atoi_w_units (const char *cp); -extern pid_t* find_pid_by_name( char* pidName); -extern char *find_real_root_device_name(const char* name); -extern char *get_line_from_file(FILE *file); -extern void print_file(FILE *file); -extern int copyfd(int fd1, int fd2); -extern int print_file_by_name(char *filename); -extern char process_escape_sequence(const char **ptr); -extern char *get_last_path_component(char *path); -extern FILE *wfopen(const char *path, const char *mode); -extern FILE *xfopen(const char *path, const char *mode); -extern void chomp(char *s); -extern void trim(char *s); -extern struct BB_applet *find_applet_by_name(const char *name); -void run_applet_by_name(const char *name, int argc, char **argv); - -#ifndef DMALLOC -extern void *xmalloc (size_t size); -extern void *xrealloc(void *old, size_t size); -extern void *xcalloc(size_t nmemb, size_t size); -extern char *xstrdup (const char *s); -#endif -extern char *xstrndup (const char *s, int n); -extern char * safe_strncpy(char *dst, const char *src, size_t size); - -struct suffix_mult { - const char *suffix; - int mult; -}; - -extern unsigned long parse_number(const char *numstr, - const struct suffix_mult *suffixes); - - -/* These parse entries in /etc/passwd and /etc/group. This is desirable - * for BusyBox since we want to avoid using the glibc NSS stuff, which - * increases target size and is often not needed embedded systems. */ -extern long my_getpwnam(const char *name); -extern long my_getgrnam(const char *name); -extern void my_getpwuid(char *name, long uid); -extern void my_getgrgid(char *group, long gid); -extern long my_getpwnamegid(const char *name); - -extern int device_open(char *device, int mode); - -extern int del_loop(const char *device); -extern int set_loop(const char *device, const char *file, int offset, int *loopro); -extern char *find_unused_loop_device (void); - - -#if (__GLIBC__ < 2) -extern int vdprintf(int d, const char *format, va_list ap); -#endif - -int nfsmount(const char *spec, const char *node, int *flags, - char **extra_opts, char **mount_opts, int running_bg); - -void syslog_msg_with_name(const char *name, int facility, int pri, const char *msg); -void syslog_msg(int facility, int pri, const char *msg); - -/* Include our own copy of struct sysinfo to avoid binary compatability - * problems with Linux 2.4, which changed things. Grumble, grumble. */ -struct sysinfo { - long uptime; /* Seconds since boot */ - unsigned long loads[3]; /* 1, 5, and 15 minute load averages */ - unsigned long totalram; /* Total usable main memory size */ - unsigned long freeram; /* Available memory size */ - unsigned long sharedram; /* Amount of shared memory */ - unsigned long bufferram; /* Memory used by buffers */ - unsigned long totalswap; /* Total swap space size */ - unsigned long freeswap; /* swap space still available */ - unsigned short procs; /* Number of current processes */ - unsigned short pad; /* Padding needed for m68k */ - unsigned long totalhigh; /* Total high memory size */ - unsigned long freehigh; /* Available high memory size */ - unsigned int mem_unit; /* Memory unit size in bytes */ - char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */ -}; -extern int sysinfo (struct sysinfo* info); - -enum { - KILOBYTE = 1024, - MEGABYTE = (KILOBYTE*1024), - GIGABYTE = (MEGABYTE*1024) -}; -const char *make_human_readable_str(unsigned long size, unsigned long block_size, unsigned long display_unit); - -int ask_confirmation(void); -int klogctl(int type, char * b, int len); - -char *xgetcwd(char *cwd); -char *xreadlink(const char *path); -char *concat_path_file(const char *path, const char *filename); -char *last_char_is(const char *s, int c); - -extern long arith (const char *startbuf, int *errcode); - -typedef struct file_headers_s { - char *name; - char *link_name; - off_t size; - uid_t uid; - gid_t gid; - mode_t mode; - time_t mtime; - dev_t device; -} file_header_t; -file_header_t *get_header_ar(FILE *in_file); -file_header_t *get_header_cpio(FILE *src_stream); -file_header_t *get_header_tar(FILE *tar_stream); - -enum extract_functions_e { - extract_verbose_list = 1, - extract_list = 2, - extract_one_to_buffer = 4, - extract_to_stdout = 8, - extract_all_to_fs = 16, - extract_preserve_date = 32, - extract_data_tar_gz = 64, - extract_control_tar_gz = 128, - extract_unzip_only = 256, - extract_unconditional = 512, - extract_create_leading_dirs = 1024, - extract_quiet = 2048, - extract_exclude_list = 4096 -}; -char *unarchive(FILE *src_stream, FILE *out_stream, file_header_t *(*get_header)(FILE *), - const int extract_function, const char *prefix, char **extract_names); -char *deb_extract(const char *package_filename, FILE *out_stream, const int extract_function, - const char *prefix, const char *filename); -int read_package_field(const char *package_buffer, char **field_name, char **field_value); -char *fgets_str(FILE *file, const char *terminating_string); - -extern int unzip(FILE *l_in_file, FILE *l_out_file); -extern void gz_close(int gunzip_pid); -extern FILE *gz_open(FILE *compressed_file, int *pid); - -extern struct hostent *xgethostbyname(const char *name); -extern int create_icmp_socket(void); - -char *dirname (char *path); - -int make_directory (char *path, long mode, int flags); - -const char *u_signal_names(const char *str_sig, int *signo, int startnum); -char *simplify_path(const char *path); - -#define CT_AUTO 0 -#define CT_UNIX2DOS 1 -#define CT_DOS2UNIX 2 -/* extern int convert(char *fn, int ConvType); */ - -enum { - FILEUTILS_PRESERVE_STATUS = 1, - FILEUTILS_PRESERVE_SYMLINKS = 2, - FILEUTILS_RECUR = 4, - FILEUTILS_FORCE = 8, - FILEUTILS_INTERACTIVE = 16 -}; - -extern const char *applet_name; -extern const char * const full_version; -extern const char * const name_too_long; -extern const char * const omitting_directory; -extern const char * const not_a_directory; -extern const char * const memory_exhausted; -extern const char * const invalid_date; -extern const char * const invalid_option; -extern const char * const io_error; -extern const char * const dash_dash_help; -extern const char * const write_error; -extern const char * const too_few_args; -extern const char * const name_longer_than_foo; -extern const char * const unknown; -extern const char * const can_not_create_raw_socket; - -#ifdef BB_FEATURE_DEVFS -# define CURRENT_VC "/dev/vc/0" -# define VC_1 "/dev/vc/1" -# define VC_2 "/dev/vc/2" -# define VC_3 "/dev/vc/3" -# define VC_4 "/dev/vc/4" -# define VC_5 "/dev/vc/5" -# define SC_0 "/dev/tts/0" -# define SC_1 "/dev/tts/1" -# define VC_FORMAT "/dev/vc/%d" -# define SC_FORMAT "/dev/tts/%d" -#else -# define CURRENT_VC "/dev/tty0" -# define VC_1 "/dev/tty1" -# define VC_2 "/dev/tty2" -# define VC_3 "/dev/tty3" -# define VC_4 "/dev/tty4" -# define VC_5 "/dev/tty5" -# define SC_0 "/dev/ttyS0" -# define SC_1 "/dev/ttyS1" -# define VC_FORMAT "/dev/tty%d" -# define SC_FORMAT "/dev/ttyS%d" -#endif - -/* The following devices are the same on devfs and non-devfs systems. */ -#define CURRENT_TTY "/dev/tty" -#define CONSOLE_DEV "/dev/console" - -#endif /* __LIBBB_H__ */ diff --git a/busybox/include/pwd.h b/busybox/include/pwd.h deleted file mode 100644 index e603a96e3..000000000 --- a/busybox/include/pwd.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef __BB_PWD_H -#define __BB_PWD_H - -#if defined USE_SYSTEM_PWD_GRP -#include -#else - -#include -#include -#include - -/* The passwd structure. */ -struct passwd -{ - char *pw_name; /* Username. */ - char *pw_passwd; /* Password. */ - uid_t pw_uid; /* User ID. */ - gid_t pw_gid; /* Group ID. */ - char *pw_gecos; /* Real name. */ - char *pw_dir; /* Home directory. */ - char *pw_shell; /* Shell program. */ -}; - -extern void setpwent __P ((void)); -extern void endpwent __P ((void)); -extern struct passwd * getpwent __P ((void)); - -extern int putpwent __P ((__const struct passwd * __p, FILE * __f)); -extern int getpw __P ((uid_t uid, char *buf)); - -extern struct passwd * fgetpwent __P ((FILE * file)); - -extern struct passwd * getpwuid __P ((__const uid_t)); -extern struct passwd * getpwnam __P ((__const char *)); - -extern struct passwd * __getpwent __P ((__const int passwd_fd)); - -#endif /* USE_SYSTEM_PWD_GRP */ -#endif /* __BB_PWD_H */ - diff --git a/busybox/include/usage.h b/busybox/include/usage.h deleted file mode 100644 index 4d38c43bb..000000000 --- a/busybox/include/usage.h +++ /dev/null @@ -1,1826 +0,0 @@ -#define adjtimex_trivial_usage \ - "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]" -#define adjtimex_full_usage \ - "Reads and optionally sets system timebase parameters.\n" \ - "See adjtimex(2).\n\n" \ - "Options:\n" \ - "\t-q\t\tquiet mode - do not print\n" \ - "\t-o offset\ttime offset, microseconds\n" \ - "\t-f frequency\tfrequency adjust, integer kernel units (65536 is 1ppm)\n" \ - "\t\t\t(positive values make the system clock run fast)\n" \ - "\t-t tick\t\tmicroseconds per tick, usually 10000\n" \ - "\t-p timeconstant\n" - -#define ar_trivial_usage \ - "-[ov][ptx] ARCHIVE FILES" -#define ar_full_usage \ - "Extract or list FILES from an ar archive.\n\n" \ - "Options:\n" \ - "\t-o\t\tpreserve original dates\n" \ - "\t-p\t\textract to stdout\n" \ - "\t-t\t\tlist\n" \ - "\t-x\t\textract\n" \ - "\t-v\t\tverbosely list files processed\n" - -#define basename_trivial_usage \ - "FILE [SUFFIX]" -#define basename_full_usage \ - "Strips directory path and suffixes from FILE.\n" \ - "If specified, also removes any trailing SUFFIX." -#define basename_example_usage \ - "$ basename /usr/local/bin/foo\n" \ - "foo\n" \ - "$ basename /usr/local/bin/\n" \ - "bin\n" \ - "$ basename /foo/bar.txt .txt\n" \ - "bar" - -#define cat_trivial_usage \ - "[FILE]..." -#define cat_full_usage \ - "Concatenates FILE(s) and prints them to stdout." -#define cat_example_usage \ - "$ cat /proc/uptime\n" \ - "110716.72 17.67" - -#define chgrp_trivial_usage \ - "[OPTION]... GROUP FILE..." -#define chgrp_full_usage \ - "Change the group membership of each FILE to GROUP.\n" \ - "\nOptions:\n" \ - "\t-R\tChanges files and directories recursively." -#define chgrp_example_usage \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chgrp root /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 andersen root 0 Apr 12 18:25 /tmp/foo\n" - -#define chmod_trivial_usage \ - "[-R] MODE[,MODE]... FILE..." -#define chmod_full_usage \ - "Each MODE is one or more of the letters ugoa, one of the\n" \ - "symbols +-= and one or more of the letters rwxst.\n\n" \ - "Options:\n" \ - "\t-R\tChanges files and directories recursively." -#define chmod_example_usage \ - "$ ls -l /tmp/foo\n" \ - "-rw-rw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chmod u+x /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-rwxrw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo*\n" \ - "$ chmod 444 /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" - -#define chown_trivial_usage \ - "[ -Rh ]... OWNER[<.|:>[GROUP]] FILE..." -#define chown_full_usage \ - "Change the owner and/or group of each FILE to OWNER and/or GROUP.\n" \ - "\nOptions:\n" \ - "\t-R\tChanges files and directories recursively.\n" \ - "\t-h\tDo not dereference symbolic links." -#define chown_example_usage \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chown root /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 root andersen 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chown root.root /tmp/foo\n" \ - "ls -l /tmp/foo\n" \ - "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" - -#define chroot_trivial_usage \ - "NEWROOT [COMMAND...]" -#define chroot_full_usage \ - "Run COMMAND with root directory set to NEWROOT." -#define chroot_example_usage \ - "$ ls -l /bin/ls\n" \ - "lrwxrwxrwx 1 root root 12 Apr 13 00:46 /bin/ls -> /BusyBox\n" \ - "$ mount /dev/hdc1 /mnt -t minix\n" \ - "$ chroot /mnt\n" \ - "$ ls -l /bin/ls\n" \ - "-rwxr-xr-x 1 root root 40816 Feb 5 07:45 /bin/ls*\n" - -#define chvt_trivial_usage \ - "N" -#define chvt_full_usage \ - "Changes the foreground virtual terminal to /dev/ttyN" - -#define clear_trivial_usage \ - "" -#define clear_full_usage \ - "Clear screen." - -#define cmp_trivial_usage \ - "FILE1 [FILE2]" -#define cmp_full_usage \ - "\t-s\tquiet mode - do not print\n" \ - "Compare files." - -#define cp_trivial_usage \ - "[OPTION]... SOURCE DEST" -#define cp_full_usage \ - "Copies SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n" \ - "\n" \ - "\t-a\tSame as -dpR\n" \ - "\t-d\tPreserves links\n" \ - "\t-p\tPreserves file attributes if possible\n" \ - "\t-f\tforce (implied; ignored) - always set\n" \ - "\t-R\tCopies directories recursively" - -#define cpio_trivial_usage \ - "-[dimtuv][F cpiofile]" -#define cpio_full_usage \ - "Extract or list files from a cpio archive\n" \ - "Main operation mode:\n" \ - "\td\t\tmake leading directories\n" \ - "\ti\t\textract\n" \ - "\tm\t\tpreserve mtime\n" \ - "\tt\t\tlist\n" \ - "\tu\t\tunconditional overwrite\t" \ - "\tF\t\tinput from file\t" - -#define cut_trivial_usage \ - "[OPTION]... [FILE]..." -#define cut_full_usage \ - "Prints selected fields from each input FILE to standard output.\n\n" \ - "Options:\n" \ - "\t-b LIST\t\tOutput only bytes from LIST\n" \ - "\t-c LIST\t\tOutput only characters from LIST\n" \ - "\t-d CHAR\t\tUse CHAR instead of tab as the field delimiter\n" \ - "\t-s\t\tOutput only the lines containing delimiter\n" \ - "\t-f N\t\tPrint only these fields\n" \ - "\t-n\t\tIgnored" -#define cut_example_usage \ - "$ echo "Hello world" | cut -f 1 -d ' '\n" \ - "Hello\n" \ - "$ echo "Hello world" | cut -f 2 -d ' '\n" \ - "world\n" - -#define date_trivial_usage \ - "[OPTION]... [+FORMAT]" -#define date_full_usage \ - "Displays the current time in the given FORMAT, or sets the system date.\n" \ - "\nOptions:\n" \ - "\t-R\t\tOutputs RFC-822 compliant date string\n" \ - "\t-d STRING\tdisplay time described by STRING, not `now'\n" \ - "\t-s\t\tSets time described by STRING\n" \ - "\t-u\t\tPrints or sets Coordinated Universal Time" -#define date_example_usage \ - "$ date\n" \ - "Wed Apr 12 18:52:41 MDT 2000\n" - -#define dc_trivial_usage \ - "expression ..." -#define dc_full_usage \ - "This is a Tiny RPN calculator that understands the\n" \ - "following operations: +, -, /, *, and, or, not, eor.\n" \ - "i.e., 'dc 2 2 add' -> 4, and 'dc 8 8 \\* 2 2 + /' -> 16" -#define dc_example_usage \ - "$ dc 2 2 +\n" \ - "4\n" \ - "$ dc 8 8 \* 2 2 + /\n" \ - "16\n" \ - "$ dc 0 1 and\n" \ - "0\n" \ - "$ dc 0 1 or\n" \ - "1\n" \ - "$ echo 72 9 div 8 mul | dc\n" \ - "64\n" - -#define dd_trivial_usage \ - "[if=FILE] [of=FILE] [bs=N] [count=N] [skip=N]\n" \ - "\t [seek=N] [conv=notrunc|sync]" -#define dd_full_usage \ - "Copy a file, converting and formatting according to options\n\n" \ - "\tif=FILE\t\tread from FILE instead of stdin\n" \ - "\tof=FILE\t\twrite to FILE instead of stdout\n" \ - "\tbs=N\t\tread and write N bytes at a time\n" \ - "\tcount=N\t\tcopy only N input blocks\n" \ - "\tskip=N\t\tskip N input blocks\n" \ - "\tseek=N\t\tskip N output blocks\n" \ - "\tconv=notrunc\tdon't truncate output file\n" \ - "\tconv=sync\tpad blocks with zeros\n" \ - "\n" \ - "Numbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),\n" \ - "MD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)." -#define dd_example_usage \ - "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" \ - "4+0 records in\n" \ - "4+0 records out\n" - -#define deallocvt_trivial_usage \ - "N" -#define deallocvt_full_usage \ - "Deallocate unused virtual terminal /dev/ttyN" - - -#ifdef BB_FEATURE_HUMAN_READABLE - #define USAGE_HUMAN_READABLE(a) a - #define USAGE_NOT_HUMAN_READABLE(a) -#else - #define USAGE_HUMAN_READABLE(a) - #define USAGE_NOT_HUMAN_READABLE(a) a -#endif -#define df_trivial_usage \ - "[-" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILESYSTEM ...]" -#define df_full_usage \ - "Print the filesystem space used and space available.\n\n" \ - "Options:\n" \ - USAGE_HUMAN_READABLE( \ - "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \ - "\t-m\tprint sizes in megabytes\n" \ - "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \ - "\n\t-k\tprint sizes in kilobytes(compatibility)") -#define df_example_usage \ - "$ df\n" \ - "Filesystem 1k-blocks Used Available Use% Mounted on\n" \ - "/dev/sda3 8690864 8553540 137324 98% /\n" \ - "/dev/sda1 64216 36364 27852 57% /boot\n" \ - "$ df /dev/sda3\n" \ - "Filesystem 1k-blocks Used Available Use% Mounted on\n" \ - "/dev/sda3 8690864 8553540 137324 98% /\n" - -#define dirname_trivial_usage \ - "[FILENAME ...]" -#define dirname_full_usage \ - "Strips non-directory suffix from FILENAME" -#define dirname_example_usage \ - "$ dirname /tmp/foo\n" \ - "/tmp\n" \ - "$ dirname /tmp/foo/\n" \ - "/tmp\n" - -#define dmesg_trivial_usage \ - "[-c] [-n LEVEL] [-s SIZE]" -#define dmesg_full_usage \ - "Prints or controls the kernel ring buffer\n\n" \ - "Options:\n" \ - "\t-c\t\tClears the ring buffer's contents after printing\n" \ - "\t-n LEVEL\tSets console logging level\n" \ - "\t-s SIZE\t\tUse a buffer of size SIZE" - -#define dos2unix_trivial_usage \ - "[option] [FILE]" -#define dos2unix_full_usage \ - "Converts FILE from dos format to unix format. When no option\n" \ - "is given, the input is converted to the opposite output format.\n" \ - "When no file is given, uses stdin for input and stdout for output.\n\n" \ - "Options:\n" \ - "\t-u\toutput will be in UNIX format\n" \ - "\t-d\toutput will be in DOS format" - -#define dpkg_trivial_usage \ - "-i package_file\n" - "[-CPru] package_name" -#define dpkg_full_usage \ - "\t-i\tInstall the package\n" \ - "\t-C\tConfigure an unpackaged package\n" \ - "\t-P\tPurge all files of a package\n" \ - "\t-r\tRemove all but the configuration files for a package\n" \ - "\t-u\tUnpack a package, but dont configure it\n" - -#define dpkg_deb_trivial_usage \ - "[-cefItxX] FILE [argument]" -#define dpkg_deb_full_usage \ - "Perform actions on debian packages (.debs)\n\n" \ - "Options:\n" \ - "\t-c\tList contents of filesystem tree\n" \ - "\t-e\tExtract control files to [argument] directory\n" \ - "\t-f\tDisplay control field name starting with [argument]\n" \ - "\t-I\tDisplay the control filenamed [argument]\n" \ - "\t-t\tExtract filesystem tree to stdout in tar format\n" \ - "\t-x\tExtract packages filesystem tree to directory\n" \ - "\t-X\tVerbose extract" -#define dpkg_deb_example_usage \ - "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n" - -#define du_trivial_usage \ - "[-ls" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILE]..." -#define du_full_usage \ - "Summarizes disk space used for each FILE and/or directory.\n" \ - "Disk space is printed in units of 1024 bytes.\n\n" \ - "Options:\n" \ - "\t-l\tcount sizes many times if hard linked\n" \ - "\t-s\tdisplay only a total for each argument" \ - USAGE_HUMAN_READABLE( \ - "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \ - "\t-m\tprint sizes in megabytes\n" \ - "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \ - "\n\t-k\tprint sizes in kilobytes(compatibility)") -#define du_example_usage \ - "$ du\n" \ - "16 ./CVS\n" \ - "12 ./kernel-patches/CVS\n" \ - "80 ./kernel-patches\n" \ - "12 ./tests/CVS\n" \ - "36 ./tests\n" \ - "12 ./scripts/CVS\n" \ - "16 ./scripts\n" \ - "12 ./docs/CVS\n" \ - "104 ./docs\n" \ - "2417 .\n" - -#define dumpkmap_trivial_usage \ - "> keymap" -#define dumpkmap_full_usage \ - "Prints out a binary keyboard translation table to standard output." -#define dumpkmap_example_usage \ - "$ dumpkmap > keymap\n" - -#define dutmp_trivial_usage \ - "[FILE]" -#define dutmp_full_usage \ - "Dump utmp file format (pipe delimited) from FILE\n" \ - "or stdin to stdout. (i.e., 'dutmp /var/run/utmp')" -#define dutmp_example_usage \ - "$ dutmp /var/run/utmp\n" \ - "8|7||si|||0|0|0|955637625|760097|0\n" \ - "2|0|~|~~|reboot||0|0|0|955637625|782235|0\n" \ - "1|20020|~|~~|runlevel||0|0|0|955637625|800089|0\n" \ - "8|125||l4|||0|0|0|955637629|998367|0\n" \ - "6|245|tty1|1|LOGIN||0|0|0|955637630|998974|0\n" \ - "6|246|tty2|2|LOGIN||0|0|0|955637630|999498|0\n" \ - "7|336|pts/0|vt00andersen|andersen|:0.0|0|0|0|955637763|0|0\n" - -#define echo_trivial_usage \ - "[-neE] [ARG ...]" -#define echo_full_usage \ - "Prints the specified ARGs to stdout\n\n" \ - "Options:\n" \ - "\t-n\tsuppress trailing newline\n" \ - "\t-e\tinterpret backslash-escaped characters (i.e., \\t=tab)\n" \ - "\t-E\tdisable interpretation of backslash-escaped characters" -#define echo_example_usage \ - "$ echo "Erik is cool"\n" \ - "Erik is cool\n" \ - "$ echo -e "Erik\\nis\\ncool"\n" \ - "Erik\n" \ - "is\n" \ - "cool\n" \ - "$ echo "Erik\\nis\\ncool"\n" \ - "Erik\\nis\\ncool\n" - -#define env_trivial_usage \ - "[-iu] [-] [name=value]... [command]" -#define env_full_usage \ - "Prints the current environment or runs a program after setting\n" \ - "up the specified environment.\n\n" \ - "Options:\n" \ - "\t-, -i\tstart with an empty environment\n" \ - "\t-u\tremove variable from the environment\n" - -#define expr_trivial_usage \ - "EXPRESSION" -#define expr_full_usage \ - "Prints the value of EXPRESSION to standard output.\n\n" \ - "EXPRESSION may be:\n" \ - "\tARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n" \ - "\tARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n" \ - "\tARG1 < ARG2 ARG1 is less than ARG2\n" \ - "\tARG1 <= ARG2 ARG1 is less than or equal to ARG2\n" \ - "\tARG1 = ARG2 ARG1 is equal to ARG2\n" \ - "\tARG1 != ARG2 ARG1 is unequal to ARG2\n" \ - "\tARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n" \ - "\tARG1 > ARG2 ARG1 is greater than ARG2\n" \ - "\tARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n" \ - "\tARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n" \ - "\tARG1 * ARG2 arithmetic product of ARG1 and ARG2\n" \ - "\tARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n" \ - "\tARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n" \ - "\tSTRING : REGEXP anchored pattern match of REGEXP in STRING\n" \ - "\tmatch STRING REGEXP same as STRING : REGEXP\n" \ - "\tsubstr STRING POS LENGTH substring of STRING, POS counted from 1\n" \ - "\tindex STRING CHARS index in STRING where any CHARS is found,\n" \ - "\t or 0\n" \ - "\tlength STRING length of STRING\n" \ - "\tquote TOKEN interpret TOKEN as a string, even if\n" \ - "\t it is a keyword like `match' or an\n" \ - "\t operator like `/'\n" \ - "\t( EXPRESSION ) value of EXPRESSION\n\n" \ - "Beware that many operators need to be escaped or quoted for shells.\n" \ - "Comparisons are arithmetic if both ARGs are numbers, else\n" \ - "lexicographical. Pattern matches return the string matched between \n" \ - "\\( and \\) or null; if \\( and \\) are not used, they return the number \n" \ - "of characters matched or 0." - -#define false_trivial_usage \ - "" -#define false_full_usage \ - "Return an exit code of FALSE (1)." -#define false_example_usage \ - "$ false\n" \ - "$ echo $?\n" \ - "1\n" - -#define fbset_trivial_usage \ - "[options] [mode]" -#define fbset_full_usage \ - "Show and modify frame buffer settings" -#define fbset_example_usage \ - "$ fbset\n" \ - "mode "1024x768-76"\n" \ - "\t# D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz\n" \ - "\tgeometry 1024 768 1024 768 16\n" \ - "\ttimings 12714 128 32 16 4 128 4\n" \ - "\taccel false\n" \ - "\trgba 5/11,6/5,5/0,0/0\n" \ - "endmode\n" - -#define fdflush_trivial_usage \ - "DEVICE" -#define fdflush_full_usage \ - "Forces floppy disk drive to detect disk change" - -#ifdef BB_FEATURE_FIND_TYPE - #define USAGE_FIND_TYPE(a) a -#else - #define USAGE_FIND_TYPE(a) -#endif -#ifdef BB_FEATURE_FIND_PERM - #define USAGE_FIND_PERM(a) a -#else - #define USAGE_FIND_PERM(a) -#endif -#ifdef BB_FEATURE_FIND_MTIME - #define USAGE_FIND_MTIME(a) a -#else - #define USAGE_FIND_MTIME(a) -#endif - -#define find_trivial_usage \ - "[PATH...] [EXPRESSION]" -#define find_full_usage \ - "Search for files in a directory hierarchy. The default PATH is\n" \ - "the current directory; default EXPRESSION is '-print'\n" \ - "\nEXPRESSION may consist of:\n" \ - "\t-follow\t\tDereference symbolic links.\n" \ - "\t-name PATTERN\tFile name (leading directories removed) matches PATTERN.\n" \ - "\t-print\t\tPrint (default and assumed).\n" \ - USAGE_FIND_TYPE( \ - "\n\t-type X\t\tFiletype matches X (where X is one of: f,d,l,b,c,...)" \ -) USAGE_FIND_PERM( \ - "\n\t-perm PERMS\tPermissions match any of (+NNN); all of (-NNN);\n\t\t\tor exactly (NNN)" \ -) USAGE_FIND_MTIME( \ - "\n\t-mtime TIME\tModified time is greater than (+N); less than (-N);\n\t\t\tor exactly (N) days") -#define find_example_usage \ - "$ find / -name /etc/passwd\n" \ - "/etc/passwd\n" - -#define free_trivial_usage \ - "" -#define free_full_usage \ - "Displays the amount of free and used system memory" -#define free_example_usage \ - "$ free\n" \ - " total used free shared buffers\n" \ - " Mem: 257628 248724 8904 59644 93124\n" \ - " Swap: 128516 8404 120112\n" \ - "Total: 386144 257128 129016\n" \ - -#define freeramdisk_trivial_usage \ - "DEVICE" -#define freeramdisk_full_usage \ - "Frees all memory used by the specified ramdisk." -#define freeramdisk_example_usage \ - "$ freeramdisk /dev/ram2\n" - -#define fsck_minix_trivial_usage \ - "[-larvsmf] /dev/name" -#define fsck_minix_full_usage \ - "Performs a consistency check for MINIX filesystems.\n\n" \ - "Options:\n" \ - "\t-l\tLists all filenames\n" \ - "\t-r\tPerform interactive repairs\n" \ - "\t-a\tPerform automatic repairs\n" \ - "\t-v\tverbose\n" \ - "\t-s\tOutputs super-block information\n" \ - "\t-m\tActivates MINIX-like \"mode not cleared\" warnings\n" \ - "\t-f\tForce file system check." - -#define getopt_trivial_usage \ - "[OPTIONS]..." -#define getopt_full_usage \ - "Parse command options\n" \ - "\t-a, --alternative Allow long options starting with single -\n" \ - "\t-l, --longoptions=longopts Long options to be recognized\n" \ - "\t-n, --name=progname The name under which errors are reported\n" \ - "\t-o, --options=optstring Short options to be recognized\n" \ - "\t-q, --quiet Disable error reporting by getopt(3)\n" \ - "\t-Q, --quiet-output No normal output\n" \ - "\t-s, --shell=shell Set shell quoting conventions\n" \ - "\t-T, --test Test for getopt(1) version\n" \ - "\t-u, --unqote Do not quote the output" -#define getopt_example_usage \ - "$ cat getopt.test\n" \ - "#!/bin/sh\n" \ - "GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \\\n" \ - " -n 'example.busybox' -- "$@"`\n" \ - "if [ $? != 0 ] ; then exit 1 ; fi\n" \ - "eval set -- "$GETOPT"\n" \ - "while true ; do\n" \ - " case $1 in\n" \ - " -a|--a-long) echo \"Option a\" ; shift ;;\n" \ - " -b|--b-long) echo \"Option b, argument \`$2'\" ; shift 2 ;;\n" \ - " -c|--c-long)\n" \ - " case "$2" in\n" \ - " \"\") echo \"Option c, no argument\"; shift 2 ;;\n" \ - " *) echo \"Option c, argument \`$2'\" ; shift 2 ;;\n" \ - " esac ;;\n" \ - " --) shift ; break ;;\n" \ - " *) echo \"Internal error!\" ; exit 1 ;;\n" \ - " esac\n" \ - "done\n" - -#define grep_trivial_usage \ - "[-ihHnqvs] PATTERN [FILEs...]" -#define grep_full_usage \ - "Search for PATTERN in each FILE or standard input.\n\n" \ - "Options:\n" \ - "\t-H\tprefix output lines with filename where match was found\n" \ - "\t-h\tsuppress the prefixing filename on output\n" \ - "\t-i\tignore case distinctions\n" \ - "\t-l\tlist names of files that match\n" \ - "\t-n\tprint line number with output lines\n" \ - "\t-q\tbe quiet. Returns 0 if result was found, 1 otherwise\n" \ - "\t-v\tselect non-matching lines\n" \ - "\t-s\tsuppress file open/read error messages" -#define grep_example_usage \ - "$ grep root /etc/passwd\n" \ - "root:x:0:0:root:/root:/bin/bash\n" \ - "$ grep ^[rR]oo. /etc/passwd\n" \ - "root:x:0:0:root:/root:/bin/bash\n" - -#define gunzip_trivial_usage \ - "[OPTION]... FILE" -#define gunzip_full_usage \ - "Uncompress FILE (or standard input if FILE is '-').\n\n" \ - "Options:\n" \ - "\t-c\tWrite output to standard output\n" \ - "\t-t\tTest compressed file integrity" -#define gunzip_example_usage \ - "$ ls -la /tmp/BusyBox*\n" \ - "-rw-rw-r-- 1 andersen andersen 557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n" \ - "$ gunzip /tmp/BusyBox-0.43.tar.gz\n" \ - "$ ls -la /tmp/BusyBox*\n" \ - "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n" - -#define gzip_trivial_usage \ - "[OPTION]... FILE" -#define gzip_full_usage \ - "Compress FILE with maximum compression.\n" \ - "When FILE is '-', reads standard input. Implies -c.\n\n" \ - "Options:\n" \ - "\t-c\tWrite output to standard output instead of FILE.gz\n" \ - "\t-d\tdecompress" -#define gzip_example_usage \ - "$ ls -la /tmp/busybox*\n" \ - "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/busybox.tar\n" \ - "$ gzip /tmp/busybox.tar\n" \ - "$ ls -la /tmp/busybox*\n" \ - "-rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/busybox.tar.gz\n" - -#define halt_trivial_usage \ - "" -#define halt_full_usage \ - "Halt the system." - -#define head_trivial_usage \ - "[OPTION] [FILE]..." -#define head_full_usage \ - "Print first 10 lines of each FILE to standard output.\n" \ - "With more than one FILE, precede each with a header giving the\n" \ - "file name. With no FILE, or when FILE is -, read standard input.\n\n" \ - "Options:\n" \ - "\t-n NUM\t\tPrint first NUM lines instead of first 10" -#define head_example_usage \ - "$ head -n 2 /etc/passwd\n" \ - "root:x:0:0:root:/root:/bin/bash\n" \ - "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n" - -#define hostid_trivial_usage \ - "" -#define hostid_full_usage \ - "Print out a unique 32-bit identifier for the machine." - -#define hostname_trivial_usage \ - "[OPTION] {hostname | -F FILE}" -#define hostname_full_usage \ - "Get or set the hostname or DNS domain name. If a hostname is given\n" \ - "(or FILE with the -F parameter), the host name will be set.\n\n" \ - "Options:\n" \ - "\t-s\t\tShort\n" \ - "\t-i\t\tAddresses for the hostname\n" \ - "\t-d\t\tDNS domain name\n" \ - "\t-F, --file FILE\tUse the contents of FILE to specify the hostname" -#define hostname_example_usage \ - "$ hostname\n" \ - "sage \n" - -#define id_trivial_usage \ - "[OPTIONS]... [USERNAME]" -#define id_full_usage \ - "Print information for USERNAME or the current user\n\n" \ - "Options:\n" \ - "\t-g\tprints only the group ID\n" \ - "\t-u\tprints only the user ID\n" \ - "\t-n\tprint a name instead of a number (with for -ug)\n" \ - "\t-r\tprints the real user ID instead of the effective ID (with -ug)" -#define id_example_usage \ - "$ id\n" \ - "uid=1000(andersen) gid=1000(andersen)\n" - -#ifdef BB_FEATURE_IFCONFIG_SLIP - #define USAGE_SIOCSKEEPALIVE(a) a -#else - #define USAGE_SIOCSKEEPALIVE(a) -#endif -#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ - #define USAGE_IFCONFIG_MII(a) a -#else - #define USAGE_IFCONFIG_MII(a) -#endif -#ifdef BB_FEATURE_IFCONFIG_HW - #define USAGE_IFCONFIG_HW(a) a -#else - #define USAGE_IFCONFIG_HW(a) -#endif -#ifdef BB_FEATURE_IFCONFIG_STATUS - #define USAGE_IFCONFIG_OPT_A(a) a -#else - #define USAGE_IFCONFIG_OPT_A(a) -#endif - -#define ifconfig_trivial_usage \ - USAGE_IFCONFIG_OPT_A("[-a]") " [
]" -#define ifconfig_full_usage \ - "configure a network interface\n\n" \ - "Options:\n" \ - "\t[[-]broadcast [
]] [[-]pointopoint [
]]\n" \ - "\t[netmask
] [dstaddr
]\n" \ - USAGE_SIOCSKEEPALIVE("\t[outfill ] [keepalive ]\n") \ - "\t" USAGE_IFCONFIG_HW("[hw ether
] ") \ - "[metric ] [mtu ]\n" \ - "\t[[-]trailers] [[-]arp] [[-]allmulti]\n" \ - "\t[multicast] [[-]promisc] [txqueuelen ] [[-]dynamic]\n" \ - USAGE_IFCONFIG_MII("\t[mem_start ] [io_addr ] [irq ]\n") \ - "\t[up|down] ..." - -#define init_trivial_usage \ - "" -#define init_full_usage \ - "Init is the parent of all processes." -#define init_notes_usage \ -"This version of init is designed to be run only by the kernel.\n" \ -"\n" \ -"BusyBox init doesn't support multiple runlevels. The runlevels field of\n" \ -"the /etc/inittab file is completely ignored by BusyBox init. If you want \n" \ -"runlevels, use sysvinit.\n" \ -"\n" \ -"BusyBox init works just fine without an inittab. If no inittab is found, \n" \ -"it has the following default behavior:\n" \ -"\n" \ -" ::sysinit:/etc/init.d/rcS\n" \ -" ::askfirst:/bin/sh\n" \ -" ::ctrlaltdel:/sbin/reboot\n" \ -" ::shutdown:/sbin/swapoff -a\n" \ -" ::shutdown:/bin/umount -a -r\n" \ -"\n" \ -"if it detects that /dev/console is _not_ a serial console, it will also run:\n" \ -"\n" \ -" tty2::askfirst:/bin/sh\n" \ -" tty3::askfirst:/bin/sh\n" \ -" tty4::askfirst:/bin/sh\n" \ -"\n" \ -"If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" \ -"\n" \ -" :::\n" \ -"\n" \ -" : \n" \ -"\n" \ -" WARNING: This field has a non-traditional meaning for BusyBox init!\n" \ -" The id field is used by BusyBox init to specify the controlling tty for\n" \ -" the specified process to run on. The contents of this field are\n" \ -" appended to "/dev/" and used as-is. There is no need for this field to\n" \ -" be unique, although if it isn't you may have strange results. If this\n" \ -" field is left blank, the controlling tty is set to the console. Also\n" \ -" note that if BusyBox detects that a serial console is in use, then only\n" \ -" entries whose controlling tty is either the serial console or /dev/null\n" \ -" will be run. BusyBox init does nothing with utmp. We don't need no\n" \ -" stinkin' utmp.\n" \ -"\n" \ -" : \n" \ -"\n" \ -" The runlevels field is completely ignored.\n" \ -"\n" \ -" : \n" \ -"\n" \ -" Valid actions include: sysinit, respawn, askfirst, wait, \n" \ -" once, ctrlaltdel, and shutdown.\n" \ -"\n" \ -" The available actions can be classified into two groups: actions\n" \ -" that are run only once, and actions that are re-run when the specified\n" \ -" process exits.\n" \ -"\n" \ -" Run only-once actions:\n" \ -"\n" \ -" 'sysinit' is the first item run on boot. init waits until all\n" \ -" sysinit actions are completed before continuing. Following the\n" \ -" completion of all sysinit actions, all 'wait' actions are run.\n" \ -" 'wait' actions, like 'sysinit' actions, cause init to wait until\n" \ -" the specified task completes. 'once' actions are asynchronous,\n" \ -" therefore, init does not wait for them to complete. 'ctrlaltdel'\n" \ -" actions are run when the system detects that someone on the system\n" \ -" console has pressed the CTRL-ALT-DEL key combination. Typically one\n" \ -" wants to run 'reboot' at this point to cause the system to reboot.\n" \ -" Finally the 'shutdown' action specifies the actions to taken when\n" \ -" init is told to reboot. Unmounting filesystems and disabling swap\n" \ -" is a very good here\n" \ -"\n" \ -" Run repeatedly actions:\n" \ -"\n" \ -" 'respawn' actions are run after the 'once' actions. When a process\n" \ -" started with a 'respawn' action exits, init automatically restarts\n" \ -" it. Unlike sysvinit, BusyBox init does not stop processes from\n" \ -" respawning out of control. The 'askfirst' actions acts just like\n" \ -" respawn, except that before running the specified process it\n" \ -" displays the line "Please press Enter to activate this console."\n" \ -" and then waits for the user to press enter before starting the\n" \ -" specified process. \n" \ -"\n" \ -" Unrecognized actions (like initdefault) will cause init to emit an\n" \ -" error message, and then go along with its business. All actions are\n" \ -" run in the reverse order from how they appear in /etc/inittab.\n" \ -"\n" \ -" : \n" \ -"\n" \ -" Specifies the process to be executed and it's command line.\n" \ -"\n" \ -"Example /etc/inittab file:\n" \ -"\n" \ -" # This is run first except when booting in single-user mode.\n" \ -" #\n" \ -" ::sysinit:/etc/init.d/rcS\n" \ -" \n" \ -" # /bin/sh invocations on selected ttys\n" \ -" #\n" \ -" # Start an "askfirst" shell on the console (whatever that may be)\n" \ -" ::askfirst:-/bin/sh\n" \ -" # Start an "askfirst" shell on /dev/tty2-4\n" \ -" tty2::askfirst:-/bin/sh\n" \ -" tty3::askfirst:-/bin/sh\n" \ -" tty4::askfirst:-/bin/sh\n" \ -" \n" \ -" # /sbin/getty invocations for selected ttys\n" \ -" #\n" \ -" tty4::respawn:/sbin/getty 38400 tty5\n" \ -" tty5::respawn:/sbin/getty 38400 tty6\n" \ -" \n" \ -" \n" \ -" # Example of how to put a getty on a serial line (for a terminal)\n" \ -" #\n" \ -" #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" \ -" #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" \ -" #\n" \ -" # Example how to put a getty on a modem line.\n" \ -" #::respawn:/sbin/getty 57600 ttyS2\n" \ -" \n" \ -" # Stuff to do before rebooting\n" \ -" ::ctrlaltdel:/sbin/reboot\n" \ -" ::shutdown:/bin/umount -a -r\n" \ -" ::shutdown:/sbin/swapoff -a\n" - -#define insmod_trivial_usage \ - "[OPTION]... MODULE [symbol=value]..." -#define insmod_full_usage \ - "Loads the specified kernel modules into the kernel.\n\n" \ - "Options:\n" \ - "\t-f\tForce module to load into the wrong kernel version.\n" \ - "\t-k\tMake module autoclean-able.\n" \ - "\t-v\tverbose output\n" \ - "\t-L\tLock to prevent simultaneous loads of a module\n" \ - "\t-x\tdo not export externs" - -#define kill_trivial_usage \ - "[-signal] process-id [process-id ...]" -#define kill_full_usage \ - "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\ - "Options:\n" \ - "\t-l\tList all signal names and numbers." -#define kill_example_usage \ - "$ ps | grep apache\n" \ - "252 root root S [apache]\n" \ - "263 www-data www-data S [apache]\n" \ - "264 www-data www-data S [apache]\n" \ - "265 www-data www-data S [apache]\n" \ - "266 www-data www-data S [apache]\n" \ - "267 www-data www-data S [apache]\n" \ - "$ kill 252\n" - -#define killall_trivial_usage \ - "[-signal] process-name [process-name ...]" -#define killall_full_usage \ - "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\ - "Options:\n" \ - "\t-l\tList all signal names and numbers." -#define killall_example_usage \ - "$ killall apache\n" - -#define klogd_trivial_usage \ - "-n" -#define klogd_full_usage \ - "Kernel logger.\n"\ - "Options:\n"\ - "\t-n\tRun as a foreground process." - -#define length_trivial_usage \ - "STRING" -#define length_full_usage \ - "Prints out the length of the specified STRING." -#define length_example_usage \ - "$ length Hello\n" \ - "5\n" - -#define ln_trivial_usage \ - "[OPTION] TARGET... LINK_NAME|DIRECTORY" -#define ln_full_usage \ - "Create a link named LINK_NAME or DIRECTORY to the specified TARGET\n"\ - "\nYou may use '--' to indicate that all following arguments are non-options.\n\n" \ - "Options:\n" \ - "\t-s\tmake symbolic links instead of hard links\n" \ - "\t-f\tremove existing destination files\n" \ - "\t-n\tno dereference symlinks - treat like normal file" -#define ln_example_usage \ - "$ ln -s BusyBox /tmp/ls\n" \ - "$ ls -l /tmp/ls\n" \ - "lrwxrwxrwx 1 root root 7 Apr 12 18:39 ls -> BusyBox*\n" - -#define loadacm_trivial_usage \ - "< mapfile" -#define loadacm_full_usage \ - "Loads an acm from standard input." -#define loadacm_example_usage \ - "$ loadacm < /etc/i18n/acmname\n" - -#define loadfont_trivial_usage \ - "< font" -#define loadfont_full_usage \ - "Loads a console font from standard input." -#define loadfont_example_usage \ - "$ loadfont < /etc/i18n/fontname\n" - -#define loadkmap_trivial_usage \ - "< keymap" -#define loadkmap_full_usage \ - "Loads a binary keyboard translation table from standard input." -#define loadkmap_example_usage \ - "$ loadkmap < /etc/i18n/lang-keymap\n" - -#define logger_trivial_usage \ - "[OPTION]... [MESSAGE]" -#define logger_full_usage \ - "Write MESSAGE to the system log. If MESSAGE is omitted, log stdin.\n\n" \ - "Options:\n" \ - "\t-s\tLog to stderr as well as the system log.\n" \ - "\t-t\tLog using the specified tag (defaults to user name).\n" \ - "\t-p\tEnter the message with the specified priority.\n" \ - "\t\tThis may be numerical or a ``facility.level'' pair." -#define logger_example_usage \ - "$ logger "hello"\n" - -#define logname_trivial_usage \ - "" -#define logname_full_usage \ - "Print the name of the current user." -#define logname_example_usage \ - "$ logname\n" \ - "root\n" - -#define logread_trivial_usage \ - "" - -#define logread_full_usage \ - "Shows the messages from syslogd (using circular buffer)." - -#ifdef BB_FEATURE_LS_TIMESTAMPS - #define USAGE_LS_TIMESTAMPS(a) a -#else - #define USAGE_LS_TIMESTAMPS(a) -#endif -#ifdef BB_FEATURE_LS_FILETYPES - #define USAGE_LS_FILETYPES(a) a -#else - #define USAGE_LS_FILETYPES(a) -#endif -#ifdef BB_FEATURE_LS_FOLLOWLINKS - #define USAGE_LS_FOLLOWLINKS(a) a -#else - #define USAGE_LS_FOLLOWLINKS(a) -#endif -#ifdef BB_FEATURE_LS_RECURSIVE - #define USAGE_LS_RECURSIVE(a) a -#else - #define USAGE_LS_RECURSIVE(a) -#endif -#ifdef BB_FEATURE_LS_SORTFILES - #define USAGE_LS_SORTFILES(a) a -#else - #define USAGE_LS_SORTFILES(a) -#endif -#ifdef BB_FEATURE_AUTOWIDTH - #define USAGE_AUTOWIDTH(a) a -#else - #define USAGE_AUTOWIDTH(a) -#endif -#define ls_trivial_usage \ - "[-1Aa" USAGE_LS_TIMESTAMPS("c") "Cd" USAGE_LS_TIMESTAMPS("e") USAGE_LS_FILETYPES("F") "iln" USAGE_LS_FILETYPES("p") USAGE_LS_FOLLOWLINKS("L") USAGE_LS_RECURSIVE("R") USAGE_LS_SORTFILES("rS") "s" USAGE_AUTOWIDTH("T") USAGE_LS_TIMESTAMPS("tu") USAGE_LS_SORTFILES("v") USAGE_AUTOWIDTH("w") "x" USAGE_LS_SORTFILES("X") USAGE_HUMAN_READABLE("h") USAGE_NOT_HUMAN_READABLE("") "k] [filenames...]" -#define ls_full_usage \ - "List directory contents\n\n" \ - "Options:\n" \ - "\t-1\tlist files in a single column\n" \ - "\t-A\tdo not list implied . and ..\n" \ - "\t-a\tdo not hide entries starting with .\n" \ - "\t-C\tlist entries by columns\n" \ - USAGE_LS_TIMESTAMPS("\t-c\twith -l: show ctime\n") \ - "\t-d\tlist directory entries instead of contents\n" \ - USAGE_LS_TIMESTAMPS("\t-e\tlist both full date and full time\n") \ - USAGE_LS_FILETYPES("\t-F\tappend indicator (one of */=@|) to entries\n") \ - "\t-i\tlist the i-node for each file\n" \ - "\t-l\tuse a long listing format\n" \ - "\t-n\tlist numeric UIDs and GIDs instead of names\n" \ - USAGE_LS_FILETYPES("\t-p\tappend indicator (one of /=@|) to entries\n") \ - USAGE_LS_FOLLOWLINKS("\t-L\tlist entries pointed to by symbolic links\n") \ - USAGE_LS_RECURSIVE("\t-R\tlist subdirectories recursively\n") \ - USAGE_LS_SORTFILES("\t-r\tsort the listing in reverse order\n") \ - USAGE_LS_SORTFILES("\t-S\tsort the listing by file size\n") \ - "\t-s\tlist the size of each file, in blocks\n" \ - USAGE_AUTOWIDTH("\t-T NUM\tassume Tabstop every NUM columns\n") \ - USAGE_LS_TIMESTAMPS("\t-t\twith -l: show modification time\n") \ - USAGE_LS_TIMESTAMPS("\t-u\twith -l: show access time\n") \ - USAGE_LS_SORTFILES("\t-v\tsort the listing by version\n") \ - USAGE_AUTOWIDTH("\t-w NUM\tassume the terminal is NUM columns wide\n") \ - "\t-x\tlist entries by lines instead of by columns\n" \ - USAGE_LS_SORTFILES("\t-X\tsort the listing by extension\n") \ - USAGE_HUMAN_READABLE( \ - "\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \ - "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \ - "\t-k\tprint sizes in kilobytes(compatibility)") - -#define lsmod_trivial_usage \ - "" -#define lsmod_full_usage \ - "List the currently loaded kernel modules." - -#define makedevs_trivial_usage \ - "NAME TYPE MAJOR MINOR FIRST LAST [s]" -#define makedevs_full_usage \ - "Creates a range of block or character special files\n\n" \ - "TYPEs include:\n" \ - "\tb:\tMake a block (buffered) device.\n" \ - "\tc or u:\tMake a character (un-buffered) device.\n" \ - "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes.\n\n" \ - "FIRST specifies the number appended to NAME to create the first device.\n" \ - "LAST specifies the number of the last item that should be created.\n" \ - "If 's' is the last argument, the base device is created as well.\n\n" \ - "For example:\n" \ - "\tmakedevs /dev/ttyS c 4 66 2 63 -> ttyS2-ttyS63\n" \ - "\tmakedevs /dev/hda b 3 0 0 8 s -> hda,hda1-hda8" -#define makedevs_example_usage \ - "$ makedevs /dev/ttyS c 4 66 2 63\n" \ - "[creates ttyS2-ttyS63]\n" \ - "$ makedevs /dev/hda b 3 0 0 8 s\n" \ - "[creates hda,hda1-hda8]\n" - -#define md5sum_trivial_usage \ - "[OPTION] [FILE]...\n" \ - "or: md5sum [OPTION] -c [FILE]" -#define md5sum_full_usage \ - "Print or check MD5 checksums.\n\n" \ - "Options:\n" \ - "With no FILE, or when FILE is -, read standard input.\n\n" \ - "\t-b\tread files in binary mode\n" \ - "\t-c\tcheck MD5 sums against given list\n" \ - "\t-t\tread files in text mode (default)\n" \ - "\t-g\tread a string\n" \ - "\nThe following two options are useful only when verifying checksums:\n" \ - "\t-s\tdon't output anything, status code shows success\n" \ - "\t-w\twarn about improperly formated MD5 checksum lines" -#define md5sum_example_usage \ - "$ md5sum < busybox\n" \ - "6fd11e98b98a58f64ff3398d7b324003\n" \ - "$ md5sum busybox\n" \ - "6fd11e98b98a58f64ff3398d7b324003 busybox\n" \ - "$ md5sum -c -\n" \ - "6fd11e98b98a58f64ff3398d7b324003 busybox\n" \ - "busybox: OK\n" \ - "^D\n" - -#define mkdir_trivial_usage \ - "[OPTION] DIRECTORY..." -#define mkdir_full_usage \ - "Create the DIRECTORY(ies) if they do not already exist\n\n" \ - "Options:\n" \ - "\t-m\tset permission mode (as in chmod), not rwxrwxrwx - umask\n" \ - "\t-p\tno error if existing, make parent directories as needed" -#define mkdir_example_usage \ - "$ mkdir /tmp/foo\n" \ - "$ mkdir /tmp/foo\n" \ - "/tmp/foo: File exists\n" \ - "$ mkdir /tmp/foo/bar/baz\n" \ - "/tmp/foo/bar/baz: No such file or directory\n" \ - "$ mkdir -p /tmp/foo/bar/baz\n" - -#define mkfifo_trivial_usage \ - "[OPTIONS] name" -#define mkfifo_full_usage \ - "Creates a named pipe (identical to 'mknod name p')\n\n" \ - "Options:\n" \ - "\t-m\tcreate the pipe using the specified mode (default a=rw)" - -#define mkfs_minix_trivial_usage \ - "[-c | -l filename] [-nXX] [-iXX] /dev/name [blocks]" -#define mkfs_minix_full_usage \ - "Make a MINIX filesystem.\n\n" \ - "Options:\n" \ - "\t-c\t\tCheck the device for bad blocks\n" \ - "\t-n [14|30]\tSpecify the maximum length of filenames\n" \ - "\t-i INODES\tSpecify the number of inodes for the filesystem\n" \ - "\t-l FILENAME\tRead the bad blocks list from FILENAME\n" \ - "\t-v\t\tMake a Minix version 2 filesystem" - -#define mknod_trivial_usage \ - "[OPTIONS] NAME TYPE MAJOR MINOR" -#define mknod_full_usage \ - "Create a special file (block, character, or pipe).\n\n" \ - "Options:\n" \ - "\t-m\tcreate the special file using the specified mode (default a=rw)\n\n" \ - "TYPEs include:\n" \ - "\tb:\tMake a block (buffered) device.\n" \ - "\tc or u:\tMake a character (un-buffered) device.\n" \ - "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes." -#define mknod_example_usage \ - "$ mknod /dev/fd0 b 2 0 \n" \ - "$ mknod -m 644 /tmp/pipe p\n" - -#define mkswap_trivial_usage \ - "[-c] [-v0|-v1] device [block-count]" -#define mkswap_full_usage \ - "Prepare a disk partition to be used as a swap partition.\n\n" \ - "Options:\n" \ - "\t-c\t\tCheck for read-ability.\n" \ - "\t-v0\t\tMake version 0 swap [max 128 Megs].\n" \ - "\t-v1\t\tMake version 1 swap [big!] (default for kernels >\n\t\t\t2.1.117).\n" \ - "\tblock-count\tNumber of block to use (default is entire partition)." - -#define mktemp_trivial_usage \ - "[-q] TEMPLATE" -#define mktemp_full_usage \ - "Creates a temporary file with its name based on TEMPLATE.\n" \ - "TEMPLATE is any name with six `Xs' (i.e., /tmp/temp.XXXXXX)." -#define mktemp_example_usage \ - "$ mktemp /tmp/temp.XXXXXX\n" \ - "/tmp/temp.mWiLjM\n" \ - "$ ls -la /tmp/temp.mWiLjM\n" \ - "-rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM\n" - -#define modprobe_trivial_usage \ - "[FILE ...]" -#define modprobe_full_usage \ - "Used for hight level module loading and unloading." -#define modprobe_example_usage \ - "$ modprobe cdrom\n" - -#define more_trivial_usage \ - "[FILE ...]" -#define more_full_usage \ - "More is a filter for viewing FILE one screenful at a time." -#define more_example_usage \ - "$ dmesg | more\n" - -#ifdef BB_FEATURE_MOUNT_LOOP - #define USAGE_MOUNT_LOOP(a) a -#else - #define USAGE_MOUNT_LOOP(a) -#endif -#ifdef BB_FEATURE_MTAB_SUPPORT - #define USAGE_MTAB(a) a -#else - #define USAGE_MTAB(a) -#endif -#define mount_trivial_usage \ - "[flags] DEVICE NODE [-o options,more-options]" -#define mount_full_usage \ - "Mount a filesystem\n\n" \ - "Flags:\n" \ - "\t-a:\t\tMount all filesystems in fstab.\n" \ - USAGE_MTAB( \ - "\t-f:\t\t\"Fake\" Add entry to mount table but don't mount it.\n" \ - "\t-n:\t\tDon't write a mount table entry.\n" \ - ) \ - "\t-o option:\tOne of many filesystem options, listed below.\n" \ - "\t-r:\t\tMount the filesystem read-only.\n" \ - "\t-t fs-type:\tSpecify the filesystem type.\n" \ - "\t-w:\t\tMount for reading and writing (default).\n" \ - "\n" \ - "Options for use with the \"-o\" flag:\n" \ - "\tasync/sync:\tWrites are asynchronous / synchronous.\n" \ - "\tatime/noatime:\tEnable / disable updates to inode access times.\n" \ - "\tdev/nodev:\tAllow use of special device files / disallow them.\n" \ - "\texec/noexec:\tAllow use of executable files / disallow them.\n" \ - USAGE_MOUNT_LOOP( \ - "\tloop:\t\tMounts a file via loop device.\n" \ - ) \ - "\tsuid/nosuid:\tAllow set-user-id-root programs / disallow them.\n" \ - "\tremount:\tRe-mount a mounted filesystem, changing its flags.\n" \ - "\tro/rw:\t\tMount for read-only / read-write.\n" \ - "\tbind:\t\tUse the linux 2.4.x \"bind\" feature.\n" \ - "\nThere are EVEN MORE flags that are specific to each filesystem.\n" \ - "You'll have to see the written documentation for those filesystems." -#define mount_example_usage \ - "$ mount\n" \ - "/dev/hda3 on / type minix (rw)\n" \ - "proc on /proc type proc (rw)\n" \ - "devpts on /dev/pts type devpts (rw)\n" \ - "$ mount /dev/fd0 /mnt -t msdos -o ro\n" \ - "$ mount /tmp/diskimage /opt -t ext2 -o loop\n" - -#define mt_trivial_usage \ - "[-f device] opcode value" -#define mt_full_usage \ - "Control magnetic tape drive operation\n" \ - "\nAvailable Opcodes:\n\n" \ - "bsf bsfm bsr bss datacompression drvbuffer eof eom erase\n" \ - "fsf fsfm fsr fss load lock mkpart nop offline ras1 ras2\n" \ - "ras3 reset retension rew rewoffline seek setblk setdensity\n" \ - "setpart tell unload unlock weof wset" - -#define mv_trivial_usage \ - "SOURCE DEST\n" \ - "or: mv SOURCE... DIRECTORY" -#define mv_full_usage \ - "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY." -#define mv_example_usage \ - "$ mv /tmp/foo /bin/bar\n" - -#define nc_trivial_usage \ - "[IP] [port]" -#define nc_full_usage \ - "Netcat opens a pipe to IP:port" -#define nc_example_usage \ - "$ nc foobar.somedomain.com 25\n" \ - "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" \ - "help\n" \ - "214-Commands supported:\n" \ - "214- HELO EHLO MAIL RCPT DATA AUTH\n" \ - "214 NOOP QUIT RSET HELP\n" \ - "quit\n" \ - "221 foobar closing connection\n" - -#define nslookup_trivial_usage \ - "[HOST] [SERVER]" -#define nslookup_full_usage \ - "Queries the nameserver for the IP address of the given HOST\n" \ - "optionally using a specified DNS server" -#define nslookup_example_usage \ - "$ nslookup localhost\n" \ - "Server: default\n" \ - "Address: default\n" \ - "\n" \ - "Name: debian\n" \ - "Address: 127.0.0.1\n" - -#define pidof_trivial_usage \ - "process-name [process-name ...]" -#define pidof_full_usage \ - "Lists the PIDs of all processes with names that match the names on the command line" -#define pidof_example_usage \ - "$ pidof init\n" \ - "1\n" - -#ifndef BB_FEATURE_FANCY_PING -#define ping_trivial_usage "host" -#define ping_full_usage "Send ICMP ECHO_REQUEST packets to network hosts" -#else -#define ping_trivial_usage \ - "[OPTION]... host" -#define ping_full_usage \ - "Send ICMP ECHO_REQUEST packets to network hosts.\n\n" \ - "Options:\n" \ - "\t-c COUNT\tSend only COUNT pings.\n" \ - "\t-s SIZE\t\tSend SIZE data bytes in packets (default=56).\n" \ - "\t-q\t\tQuiet mode, only displays output at start\n" \ - "\t\t\tand when finished." -#endif -#define ping_example_usage \ - "$ ping localhost\n" \ - "PING slag (127.0.0.1): 56 data bytes\n" \ - "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" \ - "\n" \ - "--- debian ping statistics ---\n" \ - "1 packets transmitted, 1 packets received, 0% packet loss\n" \ - "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" - -#define pivot_root_trivial_usage \ - "NEW_ROOT PUT_OLD" -#define pivot_root_full_usage \ - "Move the current root file system to PUT_OLD and make NEW_ROOT\n" \ - "the new root file system." - -#define poweroff_trivial_usage \ - "" -#define poweroff_full_usage \ - "Halt the system and request that the kernel shut off the power." - -#define printf_trivial_usage \ - "FORMAT [ARGUMENT...]" -#define printf_full_usage \ - "Formats and prints ARGUMENT(s) according to FORMAT,\n" \ - "Where FORMAT controls the output exactly as in C printf." -#define printf_example_usage \ - "$ printf "Val=%d\\n" 5\n" \ - "Val=5\n" - -#define ps_trivial_usage \ - "" -#define ps_full_usage \ - "Report process status\n" \ - "\nThis version of ps accepts no options." -#define ps_example_usage \ - "$ ps\n" \ - " PID Uid Gid State Command\n" \ - " 1 root root S init\n" \ - " 2 root root S [kflushd]\n" \ - " 3 root root S [kupdate]\n" \ - " 4 root root S [kpiod]\n" \ - " 5 root root S [kswapd]\n" \ - " 742 andersen andersen S [bash]\n" \ - " 743 andersen andersen S -bash\n" \ - " 745 root root S [getty]\n" \ - " 2990 andersen andersen R ps\n" - -#define pwd_trivial_usage \ - "" -#define pwd_full_usage \ - "Print the full filename of the current working directory." -#define pwd_example_usage \ - "$ pwd\n" \ - "/root\n" - -#define rdate_trivial_usage \ - "[OPTION] HOST" -#define rdate_full_usage \ - "Get and possibly set the system date and time from a remote HOST.\n\n" \ - "Options:\n" \ - "\t-s\tSet the system date and time (default).\n" \ - "\t-p\tPrint the date and time." - -#define readlink_trivial_usage \ - "" -#define readlink_full_usage \ - "Read a symbolic link." - -#define reboot_trivial_usage \ - "" -#define reboot_full_usage \ - "Reboot the system." - -#define renice_trivial_usage \ - "priority pid [pid ...]" -#define renice_full_usage \ - "Changes priority of running processes. Allowed priorities range\n" \ - "from 20 (the process runs only when nothing else is running) to 0\n" \ - "(default priority) to -20 (almost nothing else ever gets to run)." - -#define reset_trivial_usage \ - "" -#define reset_full_usage \ - "Resets the screen." - -#define rm_trivial_usage \ - "[OPTION]... FILE..." -#define rm_full_usage \ - "Remove (unlink) the FILE(s). You may use '--' to\n" \ - "indicate that all following arguments are non-options.\n\n" \ - "Options:\n" \ - "\t-i\t\talways prompt before removing each destination" \ - "\t-f\t\tremove existing destinations, never prompt\n" \ - "\t-r or -R\tremove the contents of directories recursively" -#define rm_example_usage \ - "$ rm -rf /tmp/foo\n" - -#define rmdir_trivial_usage \ - "[OPTION]... DIRECTORY..." -#define rmdir_full_usage \ - "Remove the DIRECTORY(ies), if they are empty." -#define rmdir_example_usage \ - "# rmdir /tmp/foo\n" - -#define rmmod_trivial_usage \ - "[OPTION]... [MODULE]..." -#define rmmod_full_usage \ - "Unloads the specified kernel modules from the kernel.\n\n" \ - "Options:\n" \ - "\t-a\tTry to remove all unused kernel modules." -#define rmmod_example_usage \ - "$ rmmod tulip\n" - -#define route_trivial_usage \ - "[{add|del|flush}]" -#define route_full_usage \ - "Edit the kernel's routing tables" - -#define rpm2cpio_trivial_usage \ - "package.rpm" -#define rpm2cpio_full_usage \ - "Outputs a cpio archive of the rpm file." - -#define sed_trivial_usage \ - "[-nef] pattern [files...]" -#define sed_full_usage \ - "Options:\n" \ - "\t-n\t\tsuppress automatic printing of pattern space\n" \ - "\t-e script\tadd the script to the commands to be executed\n" \ - "\t-f scriptfile\tadd the contents of script-file to the commands to be executed\n" \ - "\n" \ - "If no -e or -f is given, the first non-option argument is taken as the\n" \ - "sed script to interpret. All remaining arguments are names of input\n" \ - "files; if no input files are specified, then the standard input is read." -#define sed_example_usage \ - "$ echo "foo" | sed -e 's/f[a-zA-Z]o/bar/g'\n" \ - "bar\n" - -#define setkeycodes_trivial_usage \ - "SCANCODE KEYCODE ..." -#define setkeycodes_full_usage \ - "Set entries into the kernel's scancode-to-keycode map,\n" \ - "allowing unusual keyboards to generate usable keycodes.\n\n" \ - "SCANCODE may be either xx or e0xx (hexadecimal),\n" \ - "and KEYCODE is given in decimal" -#define setkeycodes_example_usage \ - "$ setkeycodes e030 127\n" - -#define lash_trivial_usage \ - "[FILE]...\n" \ - "or: sh -c command [args]..." -#define lash_full_usage \ - "lash: The BusyBox LAme SHell (command interpreter)" -#define lash_notes_usage \ -"This command does not yet have proper documentation.\n" \ -"\n" \ -"Use lash just as you would use any other shell. It properly handles pipes,\n" \ -"redirects, job control, can be used as the shell for scripts, and has a\n" \ -"sufficient set of builtins to do what is needed. It does not (yet) support\n" \ -"Bourne Shell syntax. If you need things like "if-then-else", "while", and such\n" \ -"use ash or bash. If you just need a very simple and extremely small shell,\n" \ -"this will do the job." - -#define sleep_trivial_usage \ - "N" -#define sleep_full_usage \ - "Pause for N seconds." -#define sleep_example_usage \ - "$ sleep 2\n" \ - "[2 second delay results]\n" - - -#ifdef BB_FEATURE_SORT_UNIQUE - #define USAGE_SORT_UNIQUE(a) a -#else - #define USAGE_SORT_UNIQUE(a) -#endif -#ifdef BB_FEATURE_SORT_REVERSE - #define USAGE_SORT_REVERSE(a) a -#else - #define USAGE_SORT_REVERSE(a) -#endif -#define sort_trivial_usage \ - "[-n" USAGE_SORT_REVERSE("r") USAGE_SORT_UNIQUE("u") "] [FILE]..." -#define sort_full_usage \ - "Sorts lines of text in the specified files\n\n"\ - "Options:\n" \ - USAGE_SORT_UNIQUE("\t-u\tsuppress duplicate lines\n") \ - USAGE_SORT_REVERSE("\t-r\tsort in reverse order\n") \ - "\t-n\tsort numerics" -#define sort_example_usage \ - "$ echo -e \"e\\nf\\nb\\nd\\nc\\na\" | sort\n" \ - "a\n" \ - "b\n" \ - "c\n" \ - "d\n" \ - "e\n" \ - "f\n" - -#define stty_trivial_usage \ - "[-a|g] [-F DEVICE] [SETTING]..." -#define stty_full_usage \ - "Without arguments, prints baud rate, line discipline," \ - "\nand deviations from stty sane." \ - "\n\nOptions:" \ - "\n\t-F DEVICE\topen device instead of stdin" \ - "\n\t-a\t\tprint all current settings in human-readable form" \ - "\n\t-g\t\tprint in stty-readable form" \ - "\n\t[SETTING]\tsee manpage" - -#define swapoff_trivial_usage \ - "[OPTION] [DEVICE]" -#define swapoff_full_usage \ - "Stop swapping virtual memory pages on DEVICE.\n\n" \ - "Options:\n" \ - "\t-a\tStop swapping on all swap devices" - -#define swapon_trivial_usage \ - "[OPTION] [DEVICE]" -#define swapon_full_usage \ - "Start swapping virtual memory pages on DEVICE.\n\n" \ - "Options:\n" \ - "\t-a\tStart swapping on all swap devices" - -#define sync_trivial_usage \ - "" -#define sync_full_usage \ - "Write all buffered filesystem blocks to disk." - - -#ifdef BB_FEATURE_REMOTE_LOG - #define USAGE_REMOTE_LOG(a) a -#else - #define USAGE_REMOTE_LOG(a) -#endif -#define syslogd_trivial_usage \ - "[OPTION]..." -#define syslogd_full_usage \ - "Linux system and kernel logging utility.\n" \ - "Note that this version of syslogd ignores /etc/syslog.conf.\n\n" \ - "Options:\n" \ - "\t-m NUM\t\tInterval between MARK lines (default=20min, 0=off)\n" \ - "\t-n\t\tRun as a foreground process\n" \ - "\t-O FILE\t\tUse an alternate log file (default=/var/log/messages)" \ - USAGE_REMOTE_LOG( \ - "\n\t-R HOST[:PORT]\tLog to IP or hostname on PORT (default PORT=514/UDP)\n" \ - "\t-L\t\tLog locally and via network logging (default is network only)") -#define syslogd_example_usage \ - "$ syslogd -R masterlog:514\n" \ - "$ syslogd -R 192.168.1.1:601\n" - - -#ifndef BB_FEATURE_FANCY_TAIL - #define USAGE_UNSIMPLE_TAIL(a) -#else - #define USAGE_UNSIMPLE_TAIL(a) a -#endif -#define tail_trivial_usage \ - "[OPTION]... [FILE]..." -#define tail_full_usage \ - "Print last 10 lines of each FILE to standard output.\n" \ - "With more than one FILE, precede each with a header giving the\n" \ - "file name. With no FILE, or when FILE is -, read standard input.\n\n" \ - "Options:\n" \ - USAGE_UNSIMPLE_TAIL("\t-c N[kbm]\toutput the last N bytes\n") \ - "\t-n N[kbm]\tprint last N lines instead of last 10\n" \ - "\t-f\t\toutput data as the file grows" \ - USAGE_UNSIMPLE_TAIL( "\n\t-q\t\tnever output headers giving file names\n" \ - "\t-s SEC\t\twait SEC seconds between reads with -f\n" \ - "\t-v\t\talways output headers giving file names\n\n" \ - "If the first character of N (bytes or lines) is a '+', output begins with \n" \ - "the Nth item from the start of each file, otherwise, print the last N items\n" \ - "in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2)." ) -#define tail_example_usage \ - "$ tail -n 1 /etc/resolv.conf\n" \ - "nameserver 10.0.0.1\n" - -#ifdef BB_FEATURE_TAR_CREATE - #define USAGE_TAR_CREATE(a) a -#else - #define USAGE_TAR_CREATE(a) -#endif -#ifdef BB_FEATURE_TAR_EXCLUDE - #define USAGE_TAR_EXCLUDE(a) a -#else - #define USAGE_TAR_EXCLUDE(a) -#endif -#define tar_trivial_usage \ - "-[" USAGE_TAR_CREATE("c") "xtvO] " \ - USAGE_TAR_EXCLUDE("[--exclude FILE] [-X FILE]") \ - "[-f TARFILE] [-C DIR] [FILE(s)] ..." -#define tar_full_usage \ - "Create, extract, or list files from a tar file.\n\n" \ - "Options:\n" \ - USAGE_TAR_CREATE("\tc\t\tcreate\n") \ - "\tx\t\textract\n" \ - "\tt\t\tlist\n" \ - "\nFile selection:\n" \ - "\tf\t\tname of TARFILE or \"-\" for stdin\n" \ - "\tO\t\textract to stdout\n" \ - USAGE_TAR_EXCLUDE( \ - "\texclude\t\tfile to exclude\n" \ - "\tX\t\tfile with names to exclude\n" \ - ) \ - "\tC\t\tchange to directory DIR before operation\n" \ - "\tv\t\tverbosely list files processed" -#define tar_example_usage \ - "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" \ - "$ tar -cf /tmp/tarball.tar /usr/local\n" - -#define tee_trivial_usage \ - "[OPTION]... [FILE]..." -#define tee_full_usage \ - "Copy standard input to each FILE, and also to standard output.\n\n" \ - "Options:\n" \ - "\t-a\tappend to the given FILEs, do not overwrite" -#define tee_example_usage \ - "$ echo "Hello" | tee /tmp/foo\n" \ - "$ cat /tmp/foo\n" \ - "Hello\n" - -#define telnet_trivial_usage \ - "HOST [PORT]" -#define telnet_full_usage \ - "Telnet is used to establish interactive communication with another\n"\ - "computer over a network using the TELNET protocol." - -#define test_trivial_usage \ - "EXPRESSION\n or [ EXPRESSION ]" -#define test_full_usage \ - "Checks file types and compares values returning an exit\n" \ - "code determined by the value of EXPRESSION." -#define test_example_usage \ - "$ test 1 -eq 2\n" \ - "$ echo $?\n" \ - "1\n" \ - "$ test 1 -eq 1\n" \ - "$ echo $? \n" \ - "0\n" \ - "$ [ -d /etc ]\n" \ - "$ echo $?\n" \ - "0\n" \ - "$ [ -d /junk ]\n" \ - "$ echo $?\n" \ - "1\n" - -#ifdef BB_FEATURE_TFTP_GET - #define USAGE_TFTP_GET(a) a -#else - #define USAGE_TFTP_GET(a) -#endif -#ifdef BB_FEATURE_TFTP_PUT - #define USAGE_TFTP_PUT(a) a -#else - #define USAGE_TFTP_PUT(a) -#endif - -#define tftp_trivial_usage \ - "[OPTION]... HOST [PORT]" -#define tftp_full_usage \ - "Transfers a file from/to a tftp server using \"octet\" mode.\n\n" \ - "Options:\n" \ - "\t-b SIZE\tTransfer blocks of SIZE octets.\n" \ - USAGE_TFTP_GET( \ - "\t-g\tGet file.\n" \ - ) \ - "\t-l FILE\tTransfer local FILE.\n" \ - USAGE_TFTP_PUT( \ - "\t-p\tPut file.\n" \ - ) \ - "\t-r FILE\tTransfer remote FILE.\n" - -#define touch_trivial_usage \ - "[-c] FILE [FILE ...]" -#define touch_full_usage \ - "Update the last-modified date on the given FILE[s].\n\n" \ - "Options:\n" \ - "\t-c\tDo not create any files" -#define touch_example_usage \ - "$ ls -l /tmp/foo\n" \ - "/bin/ls: /tmp/foo: No such file or directory\n" \ - "$ touch /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo\n" - -#define tr_trivial_usage \ - "[-cds] STRING1 [STRING2]" -#define tr_full_usage \ - "Translate, squeeze, and/or delete characters from\n" \ - "standard input, writing to standard output.\n\n" \ - "Options:\n" \ - "\t-c\ttake complement of STRING1\n" \ - "\t-d\tdelete input characters coded STRING1\n" \ - "\t-s\tsqueeze multiple output characters of STRING2 into one character" -#define tr_example_usage \ - "$ echo "gdkkn vnqkc" | tr [a-y] [b-z]\n" \ - "hello world\n" - -#define traceroute_trivial_usage \ - "[-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\ - [-s src_addr] [-t tos] [-w wait] host [data size]" -#define traceroute_full_usage \ - "trace the route ip packets follow going to \"host\"\n" \ - "Options:\n" \ - "\t-d\tset SO_DEBUG options to socket\n" \ - "\t-n\tPrint hop addresses numerically rather than symbolically\n" \ - "\t-r\tBypass the normal routing tables and send directly to a host\n" \ - "\t-v\tVerbose output\n" \ - "\t-m max_ttl\tSet the max time-to-live (max number of hops)\n" \ - "\t-p port#\tSet the base UDP port number used in probes\n" \ - "\t\t(default is 33434)\n" \ - "\t-q nqueries\tSet the number of probes per ``ttl'' to nqueries\n" \ - "\t\t(default is 3)\n" \ - "\t-s src_addr\tUse the following IP address as the source address\n" \ - "\t-t tos\tSet the type-of-service in probe packets to the following value\n" \ - "\t\t(default 0)\n" \ - "\t-w wait\tSet the time (in seconds) to wait for a response to a probe\n" \ - "\t\t(default 3 sec.)." - - -#define true_trivial_usage \ - "" -#define true_full_usage \ - "Return an exit code of TRUE (0)." -#define true_example_usage \ - "$ true\n" \ - "$ echo $?\n" \ - "0\n" - -#define tty_trivial_usage \ - "" -#define tty_full_usage \ - "Print the file name of the terminal connected to standard input.\n\n"\ - "Options:\n" \ - "\t-s\tprint nothing, only return an exit status" -#define tty_example_usage \ - "$ tty\n" \ - "/dev/tty2\n" - -#ifdef BB_FEATURE_MOUNT_FORCE - #define USAGE_MOUNT_FORCE(a) a -#else - #define USAGE_MOUNT_FORCE(a) -#endif -#define umount_trivial_usage \ - "[flags] FILESYSTEM|DIRECTORY" -#define umount_full_usage \ - "Unmount file systems\n" \ - "\nFlags:\n" "\t-a\tUnmount all file systems" \ - USAGE_MTAB(" in /etc/mtab\n\t-n\tDon't erase /etc/mtab entries") \ - "\n\t-r\tTry to remount devices as read-only if mount is busy" \ - USAGE_MOUNT_FORCE("\n\t-f\tForce umount (i.e., unreachable NFS server)") \ - USAGE_MOUNT_LOOP("\n\t-l\tDo not free loop device (if a loop device has been used)") -#define umount_example_usage \ - "$ umount /dev/hdc1 \n" - -#define uname_trivial_usage \ - "[OPTION]..." -#define uname_full_usage \ - "Print certain system information. With no OPTION, same as -s.\n\n" \ - "Options:\n" \ - "\t-a\tprint all information\n" \ - "\t-m\tthe machine (hardware) type\n" \ - "\t-n\tprint the machine's network node hostname\n" \ - "\t-r\tprint the operating system release\n" \ - "\t-s\tprint the operating system name\n" \ - "\t-p\tprint the host processor type\n" \ - "\t-v\tprint the operating system version" -#define uname_example_usage \ - "$ uname -a\n" \ - "Linux debian 2.2.15pre13 #5 Tue Mar 14 16:03:50 MST 2000 i686 unknown\n" - -#define uniq_trivial_usage \ - "[OPTION]... [INPUT [OUTPUT]]" -#define uniq_full_usage \ - "Discard all but one of successive identical lines from INPUT\n" \ - "(or standard input), writing to OUTPUT (or standard output).\n\n" \ - "Options:\n" \ - "\t-c\tprefix lines by the number of occurrences\n" \ - "\t-d\tonly print duplicate lines\n" \ - "\t-u\tonly print unique lines" -#define uniq_example_usage \ - "$ echo -e \"a\\na\\nb\\nc\\nc\\na\" | sort | uniq\n" \ - "a\n" \ - "b\n" \ - "c\n" - -#define unix2dos_trivial_usage \ - "[option] [FILE]" -#define unix2dos_full_usage \ - "Converts FILE from unix format to dos format. When no option\n" \ - "is given, the input is converted to the opposite output format.\n" \ - "When no file is given, uses stdin for input and stdout for output.\n" \ - "Options:\n" \ - "\t-u\toutput will be in UNIX format\n" \ - "\t-d\toutput will be in DOS format" - -#define update_trivial_usage \ - "[options]" -#define update_full_usage \ - "Periodically flushes filesystem buffers.\n\n" \ - "Options:\n" \ - "\t-S\tforce use of sync(2) instead of flushing\n" \ - "\t-s SECS\tcall sync this often (default 30)\n" \ - "\t-f SECS\tflush some buffers this often (default 5)" - -#define uptime_trivial_usage \ - "" -#define uptime_full_usage \ - "Display the time since the last boot." -#define uptime_example_usage \ - "$ uptime\n" \ - " 1:55pm up 2:30, load average: 0.09, 0.04, 0.00\n" - -#define usleep_trivial_usage \ - "N" -#define usleep_full_usage \ - "Pause for N microseconds." -#define usleep_example_usage \ - "$ usleep 1000000\n" \ - "[pauses for 1 second]\n" - -#define uudecode_trivial_usage \ - "[FILE]..." -#define uudecode_full_usage \ - "Uudecode a file that is uuencoded.\n\n" \ - "Options:\n" \ - "\t-o FILE\tdirect output to FILE" -#define uudecode_example_usage \ - "$ uudecode -o busybox busybox.uu\n" \ - "$ ls -l busybox\n" \ - "-rwxr-xr-x 1 ams ams 245264 Jun 7 21:35 busybox\n" - -#define uuencode_trivial_usage \ - "[OPTION] [INFILE] REMOTEFILE" -#define uuencode_full_usage \ - "Uuencode a file.\n\n" \ - "Options:\n" \ - "\t-m\tuse base64 encoding per RFC1521" -#define uuencode_example_usage \ - "$ uuencode busybox busybox\n" \ - "begin 755 busybox\n" \ - "\n" \ - "$ uudecode busybox busybox > busybox.uu\n" \ - "$\n" - -#define vi_trivial_usage \ - "[OPTION] [FILE]..." -#define vi_full_usage \ - "edit FILE.\n\n" \ - "Options:\n" \ - "\t-R\tRead-only- do not write to the file." - -#define watchdog_trivial_usage \ - "DEV" -#define watchdog_full_usage \ - "Periodically write to watchdog device DEV" - -#define wc_trivial_usage \ - "[OPTION]... [FILE]..." -#define wc_full_usage \ - "Print line, word, and byte counts for each FILE, and a total line if\n" \ - "more than one FILE is specified. With no FILE, read standard input.\n\n" \ - "Options:\n" \ - "\t-c\tprint the byte counts\n" \ - "\t-l\tprint the newline counts\n" \ - "\t-L\tprint the length of the longest line\n" \ - "\t-w\tprint the word counts" -#define wc_example_usage \ - "$ wc /etc/passwd\n" \ - " 31 46 1365 /etc/passwd\n" - -#define wget_trivial_usage \ - "[-c|--continue] [-q|--quiet] [-O|--output-document file]\n\t[--header 'header: value'] [-P DIR] url" -#define wget_full_usage \ - "wget retrieves files via HTTP or FTP\n\n" \ - "Options:\n" \ - "\t-c\tcontinue retrieval of aborted transfers\n" \ - "\t-q\tquiet mode - do not print\n" \ - "\t-P\tSet directory prefix to DIR\n" \ - "\t-O\tsave to filename ('-' for stdout)" - -#define which_trivial_usage \ - "[COMMAND ...]" -#define which_full_usage \ - "Locates a COMMAND." -#define which_example_usage \ - "$ which login\n" \ - "/bin/login\n" - -#define whoami_trivial_usage \ - "" -#define whoami_full_usage \ - "Prints the user name associated with the current effective user id." - -#define xargs_trivial_usage \ - "[COMMAND] [ARGS...]" -#define xargs_full_usage \ - "Executes COMMAND on every item given by standard input." -#define xargs_example_usage \ - "$ ls | xargs gzip\n" \ - "$ find . -name '*.c' -print | xargs rm\n" - -#define yes_trivial_usage \ - "[OPTION]... [STRING]..." -#define yes_full_usage \ - "Repeatedly outputs a line with all specified STRING(s), or 'y'." - -#define zcat_trivial_usage \ - "FILE" -#define zcat_full_usage \ - "Uncompress to stdout." diff --git a/busybox/init.c b/busybox/init.c deleted file mode 100644 index 45b510fa1..000000000 --- a/busybox/init.c +++ /dev/null @@ -1,1031 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini init implementation for busybox - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * Adjusted by so many folks, it's impossible to keep track. - * - * 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 - * - */ - -/* Turn this on to disable all the dangerous - rebooting stuff when debugging. -#define DEBUG_INIT -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" -#ifdef BB_SYSLOGD -# include -#endif - - -/* From */ -struct vt_stat { - unsigned short v_active; /* active vt */ - unsigned short v_signal; /* signal to send */ - unsigned short v_state; /* vt bitmask */ -}; -static const int VT_GETSTATE = 0x5603; /* get global vt state info */ - -/* From */ -struct serial_struct { - int type; - int line; - int port; - int irq; - int flags; - int xmit_fifo_size; - int custom_divisor; - int baud_base; - unsigned short close_delay; - char reserved_char[2]; - int hub6; - unsigned short closing_wait; /* time to wait before closing */ - unsigned short closing_wait2; /* no longer used... */ - int reserved[4]; -}; - - - -#ifndef RB_HALT_SYSTEM -static const int RB_HALT_SYSTEM = 0xcdef0123; -static const int RB_ENABLE_CAD = 0x89abcdef; -static const int RB_DISABLE_CAD = 0; -#define RB_POWER_OFF 0x4321fedc -static const int RB_AUTOBOOT = 0x01234567; -#endif - -#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__) - #include - #define init_reboot(magic) reboot(magic) -#else - #define init_reboot(magic) reboot(0xfee1dead, 672274793, magic) -#endif - -#ifndef _PATH_STDPATH -#define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin" -#endif - - -#if defined BB_FEATURE_INIT_COREDUMPS -/* - * When a file named CORE_ENABLE_FLAG_FILE exists, setrlimit is called - * before processes are spawned to set core file size as unlimited. - * This is for debugging only. Don't use this is production, unless - * you want core dumps lying about.... - */ -#define CORE_ENABLE_FLAG_FILE "/.init_enable_core" -#include -#include -#endif - -#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) - -#if __GNU_LIBRARY__ > 5 - #include -#else - extern int bdflush (int func, long int data); -#endif - - -#define SHELL "/bin/sh" /* Default shell */ -#define LOGIN_SHELL "-" SHELL /* Default login shell */ -#define INITTAB "/etc/inittab" /* inittab file location */ -#ifndef INIT_SCRIPT -#define INIT_SCRIPT "/etc/init.d/rcS" /* Default sysinit script. */ -#endif - -#define MAXENV 16 /* Number of env. vars */ -//static const int MAXENV = 16; /* Number of env. vars */ -static const int LOG = 0x1; -static const int CONSOLE = 0x2; - -/* Allowed init action types */ -typedef enum { - SYSINIT = 1, - RESPAWN, - ASKFIRST, - WAIT, - ONCE, - CTRLALTDEL, - SHUTDOWN -} initActionEnum; - -/* A mapping between "inittab" action name strings and action type codes. */ -typedef struct initActionType { - const char *name; - initActionEnum action; -} initActionType; - -static const struct initActionType actions[] = { - {"sysinit", SYSINIT}, - {"respawn", RESPAWN}, - {"askfirst", ASKFIRST}, - {"wait", WAIT}, - {"once", ONCE}, - {"ctrlaltdel", CTRLALTDEL}, - {"shutdown", SHUTDOWN}, - {0, 0} -}; - -/* Set up a linked list of initActions, to be read from inittab */ -typedef struct initActionTag initAction; -struct initActionTag { - pid_t pid; - char process[256]; - char console[256]; - initAction *nextPtr; - initActionEnum action; -}; -static initAction *initActionList = NULL; - - -static char *secondConsole = VC_2; -static char *thirdConsole = VC_3; -static char *fourthConsole = VC_4; -static char *log = VC_5; -static int kernelVersion = 0; -static char termType[32] = "TERM=linux"; -static char console[32] = _PATH_CONSOLE; - -static void delete_initAction(initAction * action); - -static void loop_forever() -{ - while (1) - sleep (1); -} - -/* Print a message to the specified device. - * Device may be bitwise-or'd from LOG | CONSOLE */ -static void message(int device, char *fmt, ...) - __attribute__ ((format (printf, 2, 3))); -static void message(int device, char *fmt, ...) -{ - va_list arguments; - int fd; - -#ifdef BB_SYSLOGD - - /* Log the message to syslogd */ - if (device & LOG) { - char msg[1024]; - - va_start(arguments, fmt); - vsnprintf(msg, sizeof(msg), fmt, arguments); - va_end(arguments); - openlog(applet_name, 0, LOG_USER); - syslog(LOG_USER|LOG_INFO, msg); - closelog(); - } -#else - static int log_fd = -1; - - /* Take full control of the log tty, and never close it. - * It's mine, all mine! Muhahahaha! */ - if (log_fd < 0) { - if (log == NULL) { - /* don't even try to log, because there is no such console */ - log_fd = -2; - /* log to main console instead */ - device = CONSOLE; - } else if ((log_fd = device_open(log, O_RDWR|O_NDELAY)) < 0) { - log_fd = -2; - fprintf(stderr, "Bummer, can't write to log on %s!\r\n", log); - log = NULL; - device = CONSOLE; - } - } - if ((device & LOG) && (log_fd >= 0)) { - va_start(arguments, fmt); - vdprintf(log_fd, fmt, arguments); - va_end(arguments); - } -#endif - - if (device & CONSOLE) { - /* Always send console messages to /dev/console so people will see them. */ - if ( - (fd = - device_open(_PATH_CONSOLE, - O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) { - va_start(arguments, fmt); - vdprintf(fd, fmt, arguments); - va_end(arguments); - close(fd); - } else { - fprintf(stderr, "Bummer, can't print: "); - va_start(arguments, fmt); - vfprintf(stderr, fmt, arguments); - va_end(arguments); - } - } -} - -/* Set terminal settings to reasonable defaults */ -static void set_term(int fd) -{ - struct termios tty; - - tcgetattr(fd, &tty); - - /* set control chars */ - tty.c_cc[VINTR] = 3; /* C-c */ - tty.c_cc[VQUIT] = 28; /* C-\ */ - tty.c_cc[VERASE] = 127; /* C-? */ - tty.c_cc[VKILL] = 21; /* C-u */ - tty.c_cc[VEOF] = 4; /* C-d */ - tty.c_cc[VSTART] = 17; /* C-q */ - tty.c_cc[VSTOP] = 19; /* C-s */ - tty.c_cc[VSUSP] = 26; /* C-z */ - - /* use line dicipline 0 */ - tty.c_line = 0; - - /* Make it be sane */ - tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD; - tty.c_cflag |= CREAD|HUPCL|CLOCAL; - - - /* input modes */ - tty.c_iflag = ICRNL | IXON | IXOFF; - - /* output modes */ - tty.c_oflag = OPOST | ONLCR; - - /* local modes */ - tty.c_lflag = - ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; - - tcsetattr(fd, TCSANOW, &tty); -} - -/* How much memory does this machine have? - Units are kBytes to avoid overflow on 4GB machines */ -static int check_free_memory() -{ - struct sysinfo info; - unsigned int result, u, s=10; - - if (sysinfo(&info) != 0) { - perror_msg("Error checking free memory"); - return -1; - } - - /* Kernels 2.0.x and 2.2.x return info.mem_unit==0 with values in bytes. - * Kernels 2.4.0 return info.mem_unit in bytes. */ - u = info.mem_unit; - if (u==0) u=1; - while ( (u&1) == 0 && s > 0 ) { u>>=1; s--; } - result = (info.totalram>>s) + (info.totalswap>>s); - result = result*u; - if (result < 0) result = INT_MAX; - return result; -} - -static void console_init() -{ - int fd; - int tried_devcons = 0; - int tried_vtprimary = 0; - struct vt_stat vt; - struct serial_struct sr; - char *s; - - if ((s = getenv("TERM")) != NULL) { - snprintf(termType, sizeof(termType) - 1, "TERM=%s", s); - } - - if ((s = getenv("CONSOLE")) != NULL) { - safe_strncpy(console, s, sizeof(console)); - } -#if #cpu(sparc) - /* sparc kernel supports console=tty[ab] parameter which is also - * passed to init, so catch it here */ - else if ((s = getenv("console")) != NULL) { - /* remap tty[ab] to /dev/ttyS[01] */ - if (strcmp(s, "ttya") == 0) - safe_strncpy(console, SC_0, sizeof(console)); - else if (strcmp(s, "ttyb") == 0) - safe_strncpy(console, SC_1, sizeof(console)); - } -#endif - else { - /* 2.2 kernels: identify the real console backend and try to use it */ - if (ioctl(0, TIOCGSERIAL, &sr) == 0) { - /* this is a serial console */ - snprintf(console, sizeof(console) - 1, SC_FORMAT, sr.line); - } else if (ioctl(0, VT_GETSTATE, &vt) == 0) { - /* this is linux virtual tty */ - snprintf(console, sizeof(console) - 1, VC_FORMAT, vt.v_active); - } else { - safe_strncpy(console, _PATH_CONSOLE, sizeof(console)); - tried_devcons++; - } - } - - while ((fd = open(console, O_RDONLY | O_NONBLOCK)) < 0) { - /* Can't open selected console -- try /dev/console */ - if (!tried_devcons) { - tried_devcons++; - safe_strncpy(console, _PATH_CONSOLE, sizeof(console)); - continue; - } - /* Can't open selected console -- try vt1 */ - if (!tried_vtprimary) { - tried_vtprimary++; - safe_strncpy(console, VC_1, sizeof(console)); - continue; - } - break; - } - if (fd < 0) { - /* Perhaps we should panic here? */ - safe_strncpy(console, "/dev/null", sizeof(console)); - } else { - /* check for serial console and disable logging to tty5 & running a - * shell to tty2-4 */ - if (ioctl(0, TIOCGSERIAL, &sr) == 0) { - log = NULL; - secondConsole = NULL; - thirdConsole = NULL; - fourthConsole = NULL; - /* Force the TERM setting to vt102 for serial console -- - * iff TERM is set to linux (the default) */ - if (strcmp( termType, "TERM=linux" ) == 0) - safe_strncpy(termType, "TERM=vt102", sizeof(termType)); - message(LOG | CONSOLE, - "serial console detected. Disabling virtual terminals.\r\n"); - } - close(fd); - } - message(LOG, "console=%s\n", console); -} - -static void fixup_argv(int argc, char **argv, char *new_argv0) -{ - int len; - /* Fix up argv[0] to be certain we claim to be init */ - len = strlen(argv[0]); - memset(argv[0], 0, len); - strncpy(argv[0], new_argv0, len); - - /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */ - len = 1; - while (argc > len) { - memset(argv[len], 0, strlen(argv[len])); - len++; - } -} - - -static pid_t run(char *command, char *terminal, int get_enter) -{ - int i, j; - int fd; - pid_t pid; - char *tmpCmd, *s; - char *cmd[255], *cmdpath; - char buf[255]; - struct stat sb; - static const char press_enter[] = - -#ifdef CUSTOMIZED_BANNER -#include CUSTOMIZED_BANNER -#endif - - "\nPlease press Enter to activate this console. "; - char *environment[MAXENV+1] = { - termType, - "HOME=/", - "PATH=/usr/bin:/bin:/usr/sbin:/sbin", - "SHELL=" SHELL, - "USER=root", - NULL - }; - - /* inherit environment to the child, merging our values -andy */ - for (i=0; environ[i]; i++) { - for (j=0; environment[j]; j++) { - s = strchr(environment[j], '='); - if (!strncmp(environ[i], environment[j], s - environment[j])) - break; - } - if (!environment[j]) { - environment[j++] = environ[i]; - environment[j] = NULL; - } - } - - if ((pid = fork()) == 0) { - /* Clean up */ - ioctl(0, TIOCNOTTY, 0); - close(0); - close(1); - close(2); - setsid(); - - /* Reset signal handlers set for parent process */ - signal(SIGUSR1, SIG_DFL); - signal(SIGUSR2, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGHUP, SIG_DFL); - - if ((fd = device_open(terminal, O_RDWR)) < 0) { - if (stat(terminal, &sb) != 0) { - message(LOG | CONSOLE, "device '%s' does not exist.\n", - terminal); - exit(1); - } - message(LOG | CONSOLE, "Bummer, can't open %s\r\n", terminal); - exit(1); - } - dup2(fd, 0); - dup2(fd, 1); - dup2(fd, 2); - ioctl(0, TIOCSCTTY, 1); - tcsetpgrp(0, getpgrp()); - set_term(0); - - /* See if any special /bin/sh requiring characters are present */ - if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { - cmd[0] = SHELL; - cmd[1] = "-c"; - strcpy(buf, "exec "); - strncat(buf, command, sizeof(buf) - strlen(buf) - 1); - cmd[2] = buf; - cmd[3] = NULL; - } else { - /* Convert command (char*) into cmd (char**, one word per string) */ - for (tmpCmd = command, i = 0; - (tmpCmd = strsep(&command, " \t")) != NULL;) { - if (*tmpCmd != '\0') { - cmd[i] = tmpCmd; - tmpCmd++; - i++; - } - } - cmd[i] = NULL; - } - - cmdpath = cmd[0]; - - /* - Interactive shells want to see a dash in argv[0]. This - typically is handled by login, argv will be setup this - way if a dash appears at the front of the command path - (like "-/bin/sh"). - */ - - if (*cmdpath == '-') { - - /* skip over the dash */ - ++cmdpath; - - /* find the last component in the command pathname */ - s = get_last_path_component(cmdpath); - - /* make a new argv[0] */ - if ((cmd[0] = malloc(strlen(s)+2)) == NULL) { - message(LOG | CONSOLE, "malloc failed"); - cmd[0] = cmdpath; - } else { - cmd[0][0] = '-'; - strcpy(cmd[0]+1, s); - } - } - - if (get_enter == TRUE) { - /* - * Save memory by not exec-ing anything large (like a shell) - * before the user wants it. This is critical if swap is not - * enabled and the system has low memory. Generally this will - * be run on the second virtual console, and the first will - * be allowed to start a shell or whatever an init script - * specifies. - */ -#ifdef DEBUG_INIT - message(LOG, "Waiting for enter to start '%s' (pid %d, console %s)\r\n", - cmd[0], getpid(), terminal); -#endif - write(fileno(stdout), press_enter, sizeof(press_enter) - 1); - getc(stdin); - } - -#ifdef DEBUG_INIT - /* Log the process name and args */ - message(LOG, "Starting pid %d, console %s: '%s'\r\n", - getpid(), terminal, command); -#endif - -#if defined BB_FEATURE_INIT_COREDUMPS - if (stat (CORE_ENABLE_FLAG_FILE, &sb) == 0) { - struct rlimit limit; - limit.rlim_cur = RLIM_INFINITY; - limit.rlim_max = RLIM_INFINITY; - setrlimit(RLIMIT_CORE, &limit); - } -#endif - - /* Now run it. The new program will take over this PID, - * so nothing further in init.c should be run. */ - execve(cmdpath, cmd, environment); - - /* We're still here? Some error happened. */ - message(LOG | CONSOLE, "Bummer, could not run '%s': %s\n", cmdpath, - strerror(errno)); - exit(-1); - } - return pid; -} - -static int waitfor(char *command, char *terminal, int get_enter) -{ - int status, wpid; - int pid = run(command, terminal, get_enter); - - while (1) { - wpid = wait(&status); - if (wpid > 0 && wpid != pid) { - continue; - } - if (wpid == pid) - break; - } - return wpid; -} - -/* Make sure there is enough memory to do something useful. * - * Calls "swapon -a" if needed so be sure /etc/fstab is present... */ -static void check_memory() -{ - struct stat statBuf; - - if (check_free_memory() > 1000) - return; - - if (stat("/etc/fstab", &statBuf) == 0) { - /* swapon -a requires /proc typically */ - waitfor("mount proc /proc -t proc", console, FALSE); - /* Try to turn on swap */ - waitfor("swapon -a", console, FALSE); - if (check_free_memory() < 1000) - goto goodnight; - } else - goto goodnight; - return; - - goodnight: - message(CONSOLE, - "Sorry, your computer does not have enough memory.\r\n"); - loop_forever(); -} - -/* Run all commands to be run right before halt/reboot */ -static void run_actions(initActionEnum action) -{ - initAction *a, *tmp; - for (a = initActionList; a; a = tmp) { - tmp = a->nextPtr; - if (a->action == action) { - waitfor(a->process, a->console, FALSE); - delete_initAction(a); - } - } -} - - -#ifndef DEBUG_INIT -static void shutdown_system(void) -{ - - /* first disable our SIGHUP signal */ - signal(SIGHUP, SIG_DFL); - - /* Allow Ctrl-Alt-Del to reboot system. */ - init_reboot(RB_ENABLE_CAD); - - message(CONSOLE|LOG, "\r\nThe system is going down NOW !!\r\n"); - sync(); - - /* Send signals to every process _except_ pid 1 */ - message(CONSOLE|LOG, "Sending SIGTERM to all processes.\r\n"); - kill(-1, SIGTERM); - sleep(1); - sync(); - - message(CONSOLE|LOG, "Sending SIGKILL to all processes.\r\n"); - kill(-1, SIGKILL); - sleep(1); - - /* run everything to be run at "shutdown" */ - run_actions(SHUTDOWN); - - sync(); - if (kernelVersion > 0 && kernelVersion <= KERNEL_VERSION(2,2,11)) { - /* bdflush, kupdate not needed for kernels >2.2.11 */ - bdflush(1, 0); - sync(); - } -} - -static void halt_signal(int sig) -{ - shutdown_system(); - message(CONSOLE|LOG, - "The system is halted. Press %s or turn off power\r\n", - (secondConsole == NULL) /* serial console */ - ? "Reset" : "CTRL-ALT-DEL"); - sync(); - - /* allow time for last message to reach serial console */ - sleep(2); - - if (sig == SIGUSR2 && kernelVersion >= KERNEL_VERSION(2,2,0)) - init_reboot(RB_POWER_OFF); - else - init_reboot(RB_HALT_SYSTEM); - - loop_forever(); -} - -static void reboot_signal(int sig) -{ - shutdown_system(); - message(CONSOLE|LOG, "Please stand by while rebooting the system.\r\n"); - sync(); - - /* allow time for last message to reach serial console */ - sleep(2); - - init_reboot(RB_AUTOBOOT); - - loop_forever(); -} - -static void ctrlaltdel_signal(int sig) -{ - run_actions(CTRLALTDEL); -} - -#endif /* ! DEBUG_INIT */ - -static void new_initAction(initActionEnum action, char *process, char *cons) -{ - initAction *newAction; - - if (*cons == '\0') - cons = console; - - /* If BusyBox detects that a serial console is in use, - * then entries not refering to the console or null devices will _not_ be run. - * The exception to this rule is the null device. - */ - if (secondConsole == NULL && strcmp(cons, console) - && strcmp(cons, "/dev/null")) - return; - if (strcmp(cons, "/dev/null") == 0 && action == ASKFIRST) - return; - - - newAction = calloc((size_t) (1), sizeof(initAction)); - if (!newAction) { - message(LOG | CONSOLE, "Memory allocation failure\n"); - loop_forever(); - } - newAction->nextPtr = initActionList; - initActionList = newAction; - strncpy(newAction->process, process, 255); - newAction->action = action; - strncpy(newAction->console, cons, 255); - newAction->pid = 0; -// message(LOG|CONSOLE, "process='%s' action='%d' console='%s'\n", -// newAction->process, newAction->action, newAction->console); -} - -static void delete_initAction(initAction * action) -{ - initAction *a, *b = NULL; - - for (a = initActionList; a; b = a, a = a->nextPtr) { - if (a == action) { - if (b == NULL) { - initActionList = a->nextPtr; - } else { - b->nextPtr = a->nextPtr; - } - free(a); - break; - } - } -} - -/* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined, - * then parse_inittab() simply adds in some default - * actions(i.e., runs INIT_SCRIPT and then starts a pair - * of "askfirst" shells). If BB_FEATURE_USE_INITTAB - * _is_ defined, but /etc/inittab is missing, this - * results in the same set of default behaviors. - * */ -static void parse_inittab(void) -{ -#ifdef BB_FEATURE_USE_INITTAB - FILE *file; - char buf[256], lineAsRead[256], tmpConsole[256]; - char *id, *runlev, *action, *process, *eol; - const struct initActionType *a = actions; - int foundIt; - - - file = fopen(INITTAB, "r"); - if (file == NULL) { - /* No inittab file -- set up some default behavior */ -#endif - /* Reboot on Ctrl-Alt-Del */ - new_initAction(CTRLALTDEL, "/sbin/reboot", console); - /* Swapoff on halt/reboot */ - new_initAction(SHUTDOWN, "/sbin/swapoff -a", console); - /* Umount all filesystems on halt/reboot */ - new_initAction(SHUTDOWN, "/bin/umount -a -r", console); - /* Askfirst shell on tty1 */ - new_initAction(ASKFIRST, LOGIN_SHELL, console); - /* Askfirst shell on tty2 */ - if (secondConsole != NULL) - new_initAction(ASKFIRST, LOGIN_SHELL, secondConsole); - /* Askfirst shell on tty3 */ - if (thirdConsole != NULL) - new_initAction(ASKFIRST, LOGIN_SHELL, thirdConsole); - /* Askfirst shell on tty4 */ - if (fourthConsole != NULL) - new_initAction(ASKFIRST, LOGIN_SHELL, fourthConsole); - /* sysinit */ - new_initAction(SYSINIT, INIT_SCRIPT, console); - - return; -#ifdef BB_FEATURE_USE_INITTAB - } - - while (fgets(buf, 255, file) != NULL) { - foundIt = FALSE; - /* Skip leading spaces */ - for (id = buf; *id == ' ' || *id == '\t'; id++); - - /* Skip the line if it's a comment */ - if (*id == '#' || *id == '\n') - continue; - - /* Trim the trailing \n */ - eol = strrchr(id, '\n'); - if (eol != NULL) - *eol = '\0'; - - /* Keep a copy around for posterity's sake (and error msgs) */ - strcpy(lineAsRead, buf); - - /* Separate the ID field from the runlevels */ - runlev = strchr(id, ':'); - if (runlev == NULL || *(runlev + 1) == '\0') { - message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead); - continue; - } else { - *runlev = '\0'; - ++runlev; - } - - /* Separate the runlevels from the action */ - action = strchr(runlev, ':'); - if (action == NULL || *(action + 1) == '\0') { - message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead); - continue; - } else { - *action = '\0'; - ++action; - } - - /* Separate the action from the process */ - process = strchr(action, ':'); - if (process == NULL || *(process + 1) == '\0') { - message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead); - continue; - } else { - *process = '\0'; - ++process; - } - - /* Ok, now process it */ - a = actions; - while (a->name != 0) { - if (strcmp(a->name, action) == 0) { - if (*id != '\0') { - strcpy(tmpConsole, "/dev/"); - strncat(tmpConsole, id, 200); - id = tmpConsole; - } - new_initAction(a->action, process, id); - foundIt = TRUE; - } - a++; - } - if (foundIt == TRUE) - continue; - else { - /* Choke on an unknown action */ - message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead); - } - } - return; -#endif /* BB_FEATURE_USE_INITTAB */ -} - - - -extern int init_main(int argc, char **argv) -{ - initAction *a, *tmp; - pid_t wpid; - int status; - -#ifndef DEBUG_INIT - /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ - if (getpid() != 1 -#ifdef BB_FEATURE_LINUXRC - && strstr(applet_name, "linuxrc") == NULL -#endif - ) - { - show_usage(); - } - /* Set up sig handlers -- be sure to - * clear all of these in run() */ - signal(SIGUSR1, halt_signal); - signal(SIGUSR2, halt_signal); - signal(SIGINT, ctrlaltdel_signal); - signal(SIGTERM, reboot_signal); - - /* Turn off rebooting via CTL-ALT-DEL -- we get a - * SIGINT on CAD so we can shut things down gracefully... */ - init_reboot(RB_DISABLE_CAD); -#endif - - /* Figure out what kernel this is running */ - kernelVersion = get_kernel_revision(); - - /* Figure out where the default console should be */ - console_init(); - - /* Close whatever files are open, and reset the console. */ - close(0); - close(1); - close(2); - set_term(0); - chdir("/"); - setsid(); - - /* Make sure PATH is set to something sane */ - putenv("PATH="_PATH_STDPATH); - - /* Hello world */ -#ifndef DEBUG_INIT - message( -#if ! defined BB_FEATURE_EXTRA_QUIET - CONSOLE| -#endif - LOG, - "init started: %s\r\n", full_version); -#else - message( -#if ! defined BB_FEATURE_EXTRA_QUIET - CONSOLE| -#endif - LOG, - "init(%d) started: %s\r\n", getpid(), full_version); -#endif - - - /* Make sure there is enough memory to do something useful. */ - check_memory(); - - /* Check if we are supposed to be in single user mode */ - if (argc > 1 && (!strcmp(argv[1], "single") || - !strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) { - /* Ask first then start a shell on tty2-4 */ - if (secondConsole != NULL) - new_initAction(ASKFIRST, LOGIN_SHELL, secondConsole); - if (thirdConsole != NULL) - new_initAction(ASKFIRST, LOGIN_SHELL, thirdConsole); - if (fourthConsole != NULL) - new_initAction(ASKFIRST, LOGIN_SHELL, fourthConsole); - /* Start a shell on tty1 */ - new_initAction(RESPAWN, LOGIN_SHELL, console); - } else { - /* Not in single user mode -- see what inittab says */ - - /* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined, - * then parse_inittab() simply adds in some default - * actions(i.e., runs INIT_SCRIPT and then starts a pair - * of "askfirst" shells */ - parse_inittab(); - } - - /* Make the command line just say "init" -- thats all, nothing else */ - fixup_argv(argc, argv, "init"); - - /* Now run everything that needs to be run */ - - /* First run the sysinit command */ - run_actions(SYSINIT); - - /* Next run anything that wants to block */ - run_actions(WAIT); - - /* Next run anything to be run only once */ - for (a = initActionList; a; a = tmp) { - tmp = a->nextPtr; - if (a->action == ONCE) { - run(a->process, a->console, FALSE); - /* Now remove the "once" entry from the list */ - delete_initAction(a); - } - } - /* If there is nothing else to do, stop */ - if (initActionList == NULL) { - message(LOG | CONSOLE, - "No more tasks for init -- sleeping forever.\n"); - loop_forever(); - } - - /* Now run the looping stuff for the rest of forever */ - while (1) { - for (a = initActionList; a; a = a->nextPtr) { - /* Only run stuff with pid==0. If they have - * a pid, that means they are still running */ - if (a->pid == 0) { - switch (a->action) { - case RESPAWN: - /* run the respawn stuff */ - a->pid = run(a->process, a->console, FALSE); - break; - case ASKFIRST: - /* run the askfirst stuff */ - a->pid = run(a->process, a->console, TRUE); - break; - /* silence the compiler's incessant whining */ - default: - break; - } - } - } - /* Wait for a child process to exit */ - wpid = wait(&status); - if (wpid > 0) { - /* Find out who died and clean up their corpse */ - for (a = initActionList; a; a = a->nextPtr) { - if (a->pid == wpid) { - a->pid = 0; - message(LOG, - "Process '%s' (pid %d) exited. Scheduling it for restart.\n", - a->process, wpid); - } - } - } - sleep(1); - } -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/init/halt.c b/busybox/init/halt.c deleted file mode 100644 index d66e28d0e..000000000 --- a/busybox/init/halt.c +++ /dev/null @@ -1,41 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini halt implementation for busybox - * - * - * 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 - * - */ - -#include "busybox.h" -#include - -extern int halt_main(int argc, char **argv) -{ -#ifdef BB_FEATURE_LINUXRC - /* don't assume init's pid == 1 */ - pid_t *pid = find_pid_by_name("init"); - if (!pid || *pid<=0) { - pid = find_pid_by_name("linuxrc"); - if (!pid || *pid<=0) - error_msg_and_die("no process killed"); - } - return(kill(*pid, SIGUSR1)); -#else - return(kill(1, SIGUSR1)); -#endif -} diff --git a/busybox/init/init.c b/busybox/init/init.c deleted file mode 100644 index 45b510fa1..000000000 --- a/busybox/init/init.c +++ /dev/null @@ -1,1031 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini init implementation for busybox - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * Adjusted by so many folks, it's impossible to keep track. - * - * 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 - * - */ - -/* Turn this on to disable all the dangerous - rebooting stuff when debugging. -#define DEBUG_INIT -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" -#ifdef BB_SYSLOGD -# include -#endif - - -/* From */ -struct vt_stat { - unsigned short v_active; /* active vt */ - unsigned short v_signal; /* signal to send */ - unsigned short v_state; /* vt bitmask */ -}; -static const int VT_GETSTATE = 0x5603; /* get global vt state info */ - -/* From */ -struct serial_struct { - int type; - int line; - int port; - int irq; - int flags; - int xmit_fifo_size; - int custom_divisor; - int baud_base; - unsigned short close_delay; - char reserved_char[2]; - int hub6; - unsigned short closing_wait; /* time to wait before closing */ - unsigned short closing_wait2; /* no longer used... */ - int reserved[4]; -}; - - - -#ifndef RB_HALT_SYSTEM -static const int RB_HALT_SYSTEM = 0xcdef0123; -static const int RB_ENABLE_CAD = 0x89abcdef; -static const int RB_DISABLE_CAD = 0; -#define RB_POWER_OFF 0x4321fedc -static const int RB_AUTOBOOT = 0x01234567; -#endif - -#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__) - #include - #define init_reboot(magic) reboot(magic) -#else - #define init_reboot(magic) reboot(0xfee1dead, 672274793, magic) -#endif - -#ifndef _PATH_STDPATH -#define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin" -#endif - - -#if defined BB_FEATURE_INIT_COREDUMPS -/* - * When a file named CORE_ENABLE_FLAG_FILE exists, setrlimit is called - * before processes are spawned to set core file size as unlimited. - * This is for debugging only. Don't use this is production, unless - * you want core dumps lying about.... - */ -#define CORE_ENABLE_FLAG_FILE "/.init_enable_core" -#include -#include -#endif - -#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) - -#if __GNU_LIBRARY__ > 5 - #include -#else - extern int bdflush (int func, long int data); -#endif - - -#define SHELL "/bin/sh" /* Default shell */ -#define LOGIN_SHELL "-" SHELL /* Default login shell */ -#define INITTAB "/etc/inittab" /* inittab file location */ -#ifndef INIT_SCRIPT -#define INIT_SCRIPT "/etc/init.d/rcS" /* Default sysinit script. */ -#endif - -#define MAXENV 16 /* Number of env. vars */ -//static const int MAXENV = 16; /* Number of env. vars */ -static const int LOG = 0x1; -static const int CONSOLE = 0x2; - -/* Allowed init action types */ -typedef enum { - SYSINIT = 1, - RESPAWN, - ASKFIRST, - WAIT, - ONCE, - CTRLALTDEL, - SHUTDOWN -} initActionEnum; - -/* A mapping between "inittab" action name strings and action type codes. */ -typedef struct initActionType { - const char *name; - initActionEnum action; -} initActionType; - -static const struct initActionType actions[] = { - {"sysinit", SYSINIT}, - {"respawn", RESPAWN}, - {"askfirst", ASKFIRST}, - {"wait", WAIT}, - {"once", ONCE}, - {"ctrlaltdel", CTRLALTDEL}, - {"shutdown", SHUTDOWN}, - {0, 0} -}; - -/* Set up a linked list of initActions, to be read from inittab */ -typedef struct initActionTag initAction; -struct initActionTag { - pid_t pid; - char process[256]; - char console[256]; - initAction *nextPtr; - initActionEnum action; -}; -static initAction *initActionList = NULL; - - -static char *secondConsole = VC_2; -static char *thirdConsole = VC_3; -static char *fourthConsole = VC_4; -static char *log = VC_5; -static int kernelVersion = 0; -static char termType[32] = "TERM=linux"; -static char console[32] = _PATH_CONSOLE; - -static void delete_initAction(initAction * action); - -static void loop_forever() -{ - while (1) - sleep (1); -} - -/* Print a message to the specified device. - * Device may be bitwise-or'd from LOG | CONSOLE */ -static void message(int device, char *fmt, ...) - __attribute__ ((format (printf, 2, 3))); -static void message(int device, char *fmt, ...) -{ - va_list arguments; - int fd; - -#ifdef BB_SYSLOGD - - /* Log the message to syslogd */ - if (device & LOG) { - char msg[1024]; - - va_start(arguments, fmt); - vsnprintf(msg, sizeof(msg), fmt, arguments); - va_end(arguments); - openlog(applet_name, 0, LOG_USER); - syslog(LOG_USER|LOG_INFO, msg); - closelog(); - } -#else - static int log_fd = -1; - - /* Take full control of the log tty, and never close it. - * It's mine, all mine! Muhahahaha! */ - if (log_fd < 0) { - if (log == NULL) { - /* don't even try to log, because there is no such console */ - log_fd = -2; - /* log to main console instead */ - device = CONSOLE; - } else if ((log_fd = device_open(log, O_RDWR|O_NDELAY)) < 0) { - log_fd = -2; - fprintf(stderr, "Bummer, can't write to log on %s!\r\n", log); - log = NULL; - device = CONSOLE; - } - } - if ((device & LOG) && (log_fd >= 0)) { - va_start(arguments, fmt); - vdprintf(log_fd, fmt, arguments); - va_end(arguments); - } -#endif - - if (device & CONSOLE) { - /* Always send console messages to /dev/console so people will see them. */ - if ( - (fd = - device_open(_PATH_CONSOLE, - O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) { - va_start(arguments, fmt); - vdprintf(fd, fmt, arguments); - va_end(arguments); - close(fd); - } else { - fprintf(stderr, "Bummer, can't print: "); - va_start(arguments, fmt); - vfprintf(stderr, fmt, arguments); - va_end(arguments); - } - } -} - -/* Set terminal settings to reasonable defaults */ -static void set_term(int fd) -{ - struct termios tty; - - tcgetattr(fd, &tty); - - /* set control chars */ - tty.c_cc[VINTR] = 3; /* C-c */ - tty.c_cc[VQUIT] = 28; /* C-\ */ - tty.c_cc[VERASE] = 127; /* C-? */ - tty.c_cc[VKILL] = 21; /* C-u */ - tty.c_cc[VEOF] = 4; /* C-d */ - tty.c_cc[VSTART] = 17; /* C-q */ - tty.c_cc[VSTOP] = 19; /* C-s */ - tty.c_cc[VSUSP] = 26; /* C-z */ - - /* use line dicipline 0 */ - tty.c_line = 0; - - /* Make it be sane */ - tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD; - tty.c_cflag |= CREAD|HUPCL|CLOCAL; - - - /* input modes */ - tty.c_iflag = ICRNL | IXON | IXOFF; - - /* output modes */ - tty.c_oflag = OPOST | ONLCR; - - /* local modes */ - tty.c_lflag = - ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; - - tcsetattr(fd, TCSANOW, &tty); -} - -/* How much memory does this machine have? - Units are kBytes to avoid overflow on 4GB machines */ -static int check_free_memory() -{ - struct sysinfo info; - unsigned int result, u, s=10; - - if (sysinfo(&info) != 0) { - perror_msg("Error checking free memory"); - return -1; - } - - /* Kernels 2.0.x and 2.2.x return info.mem_unit==0 with values in bytes. - * Kernels 2.4.0 return info.mem_unit in bytes. */ - u = info.mem_unit; - if (u==0) u=1; - while ( (u&1) == 0 && s > 0 ) { u>>=1; s--; } - result = (info.totalram>>s) + (info.totalswap>>s); - result = result*u; - if (result < 0) result = INT_MAX; - return result; -} - -static void console_init() -{ - int fd; - int tried_devcons = 0; - int tried_vtprimary = 0; - struct vt_stat vt; - struct serial_struct sr; - char *s; - - if ((s = getenv("TERM")) != NULL) { - snprintf(termType, sizeof(termType) - 1, "TERM=%s", s); - } - - if ((s = getenv("CONSOLE")) != NULL) { - safe_strncpy(console, s, sizeof(console)); - } -#if #cpu(sparc) - /* sparc kernel supports console=tty[ab] parameter which is also - * passed to init, so catch it here */ - else if ((s = getenv("console")) != NULL) { - /* remap tty[ab] to /dev/ttyS[01] */ - if (strcmp(s, "ttya") == 0) - safe_strncpy(console, SC_0, sizeof(console)); - else if (strcmp(s, "ttyb") == 0) - safe_strncpy(console, SC_1, sizeof(console)); - } -#endif - else { - /* 2.2 kernels: identify the real console backend and try to use it */ - if (ioctl(0, TIOCGSERIAL, &sr) == 0) { - /* this is a serial console */ - snprintf(console, sizeof(console) - 1, SC_FORMAT, sr.line); - } else if (ioctl(0, VT_GETSTATE, &vt) == 0) { - /* this is linux virtual tty */ - snprintf(console, sizeof(console) - 1, VC_FORMAT, vt.v_active); - } else { - safe_strncpy(console, _PATH_CONSOLE, sizeof(console)); - tried_devcons++; - } - } - - while ((fd = open(console, O_RDONLY | O_NONBLOCK)) < 0) { - /* Can't open selected console -- try /dev/console */ - if (!tried_devcons) { - tried_devcons++; - safe_strncpy(console, _PATH_CONSOLE, sizeof(console)); - continue; - } - /* Can't open selected console -- try vt1 */ - if (!tried_vtprimary) { - tried_vtprimary++; - safe_strncpy(console, VC_1, sizeof(console)); - continue; - } - break; - } - if (fd < 0) { - /* Perhaps we should panic here? */ - safe_strncpy(console, "/dev/null", sizeof(console)); - } else { - /* check for serial console and disable logging to tty5 & running a - * shell to tty2-4 */ - if (ioctl(0, TIOCGSERIAL, &sr) == 0) { - log = NULL; - secondConsole = NULL; - thirdConsole = NULL; - fourthConsole = NULL; - /* Force the TERM setting to vt102 for serial console -- - * iff TERM is set to linux (the default) */ - if (strcmp( termType, "TERM=linux" ) == 0) - safe_strncpy(termType, "TERM=vt102", sizeof(termType)); - message(LOG | CONSOLE, - "serial console detected. Disabling virtual terminals.\r\n"); - } - close(fd); - } - message(LOG, "console=%s\n", console); -} - -static void fixup_argv(int argc, char **argv, char *new_argv0) -{ - int len; - /* Fix up argv[0] to be certain we claim to be init */ - len = strlen(argv[0]); - memset(argv[0], 0, len); - strncpy(argv[0], new_argv0, len); - - /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */ - len = 1; - while (argc > len) { - memset(argv[len], 0, strlen(argv[len])); - len++; - } -} - - -static pid_t run(char *command, char *terminal, int get_enter) -{ - int i, j; - int fd; - pid_t pid; - char *tmpCmd, *s; - char *cmd[255], *cmdpath; - char buf[255]; - struct stat sb; - static const char press_enter[] = - -#ifdef CUSTOMIZED_BANNER -#include CUSTOMIZED_BANNER -#endif - - "\nPlease press Enter to activate this console. "; - char *environment[MAXENV+1] = { - termType, - "HOME=/", - "PATH=/usr/bin:/bin:/usr/sbin:/sbin", - "SHELL=" SHELL, - "USER=root", - NULL - }; - - /* inherit environment to the child, merging our values -andy */ - for (i=0; environ[i]; i++) { - for (j=0; environment[j]; j++) { - s = strchr(environment[j], '='); - if (!strncmp(environ[i], environment[j], s - environment[j])) - break; - } - if (!environment[j]) { - environment[j++] = environ[i]; - environment[j] = NULL; - } - } - - if ((pid = fork()) == 0) { - /* Clean up */ - ioctl(0, TIOCNOTTY, 0); - close(0); - close(1); - close(2); - setsid(); - - /* Reset signal handlers set for parent process */ - signal(SIGUSR1, SIG_DFL); - signal(SIGUSR2, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGHUP, SIG_DFL); - - if ((fd = device_open(terminal, O_RDWR)) < 0) { - if (stat(terminal, &sb) != 0) { - message(LOG | CONSOLE, "device '%s' does not exist.\n", - terminal); - exit(1); - } - message(LOG | CONSOLE, "Bummer, can't open %s\r\n", terminal); - exit(1); - } - dup2(fd, 0); - dup2(fd, 1); - dup2(fd, 2); - ioctl(0, TIOCSCTTY, 1); - tcsetpgrp(0, getpgrp()); - set_term(0); - - /* See if any special /bin/sh requiring characters are present */ - if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { - cmd[0] = SHELL; - cmd[1] = "-c"; - strcpy(buf, "exec "); - strncat(buf, command, sizeof(buf) - strlen(buf) - 1); - cmd[2] = buf; - cmd[3] = NULL; - } else { - /* Convert command (char*) into cmd (char**, one word per string) */ - for (tmpCmd = command, i = 0; - (tmpCmd = strsep(&command, " \t")) != NULL;) { - if (*tmpCmd != '\0') { - cmd[i] = tmpCmd; - tmpCmd++; - i++; - } - } - cmd[i] = NULL; - } - - cmdpath = cmd[0]; - - /* - Interactive shells want to see a dash in argv[0]. This - typically is handled by login, argv will be setup this - way if a dash appears at the front of the command path - (like "-/bin/sh"). - */ - - if (*cmdpath == '-') { - - /* skip over the dash */ - ++cmdpath; - - /* find the last component in the command pathname */ - s = get_last_path_component(cmdpath); - - /* make a new argv[0] */ - if ((cmd[0] = malloc(strlen(s)+2)) == NULL) { - message(LOG | CONSOLE, "malloc failed"); - cmd[0] = cmdpath; - } else { - cmd[0][0] = '-'; - strcpy(cmd[0]+1, s); - } - } - - if (get_enter == TRUE) { - /* - * Save memory by not exec-ing anything large (like a shell) - * before the user wants it. This is critical if swap is not - * enabled and the system has low memory. Generally this will - * be run on the second virtual console, and the first will - * be allowed to start a shell or whatever an init script - * specifies. - */ -#ifdef DEBUG_INIT - message(LOG, "Waiting for enter to start '%s' (pid %d, console %s)\r\n", - cmd[0], getpid(), terminal); -#endif - write(fileno(stdout), press_enter, sizeof(press_enter) - 1); - getc(stdin); - } - -#ifdef DEBUG_INIT - /* Log the process name and args */ - message(LOG, "Starting pid %d, console %s: '%s'\r\n", - getpid(), terminal, command); -#endif - -#if defined BB_FEATURE_INIT_COREDUMPS - if (stat (CORE_ENABLE_FLAG_FILE, &sb) == 0) { - struct rlimit limit; - limit.rlim_cur = RLIM_INFINITY; - limit.rlim_max = RLIM_INFINITY; - setrlimit(RLIMIT_CORE, &limit); - } -#endif - - /* Now run it. The new program will take over this PID, - * so nothing further in init.c should be run. */ - execve(cmdpath, cmd, environment); - - /* We're still here? Some error happened. */ - message(LOG | CONSOLE, "Bummer, could not run '%s': %s\n", cmdpath, - strerror(errno)); - exit(-1); - } - return pid; -} - -static int waitfor(char *command, char *terminal, int get_enter) -{ - int status, wpid; - int pid = run(command, terminal, get_enter); - - while (1) { - wpid = wait(&status); - if (wpid > 0 && wpid != pid) { - continue; - } - if (wpid == pid) - break; - } - return wpid; -} - -/* Make sure there is enough memory to do something useful. * - * Calls "swapon -a" if needed so be sure /etc/fstab is present... */ -static void check_memory() -{ - struct stat statBuf; - - if (check_free_memory() > 1000) - return; - - if (stat("/etc/fstab", &statBuf) == 0) { - /* swapon -a requires /proc typically */ - waitfor("mount proc /proc -t proc", console, FALSE); - /* Try to turn on swap */ - waitfor("swapon -a", console, FALSE); - if (check_free_memory() < 1000) - goto goodnight; - } else - goto goodnight; - return; - - goodnight: - message(CONSOLE, - "Sorry, your computer does not have enough memory.\r\n"); - loop_forever(); -} - -/* Run all commands to be run right before halt/reboot */ -static void run_actions(initActionEnum action) -{ - initAction *a, *tmp; - for (a = initActionList; a; a = tmp) { - tmp = a->nextPtr; - if (a->action == action) { - waitfor(a->process, a->console, FALSE); - delete_initAction(a); - } - } -} - - -#ifndef DEBUG_INIT -static void shutdown_system(void) -{ - - /* first disable our SIGHUP signal */ - signal(SIGHUP, SIG_DFL); - - /* Allow Ctrl-Alt-Del to reboot system. */ - init_reboot(RB_ENABLE_CAD); - - message(CONSOLE|LOG, "\r\nThe system is going down NOW !!\r\n"); - sync(); - - /* Send signals to every process _except_ pid 1 */ - message(CONSOLE|LOG, "Sending SIGTERM to all processes.\r\n"); - kill(-1, SIGTERM); - sleep(1); - sync(); - - message(CONSOLE|LOG, "Sending SIGKILL to all processes.\r\n"); - kill(-1, SIGKILL); - sleep(1); - - /* run everything to be run at "shutdown" */ - run_actions(SHUTDOWN); - - sync(); - if (kernelVersion > 0 && kernelVersion <= KERNEL_VERSION(2,2,11)) { - /* bdflush, kupdate not needed for kernels >2.2.11 */ - bdflush(1, 0); - sync(); - } -} - -static void halt_signal(int sig) -{ - shutdown_system(); - message(CONSOLE|LOG, - "The system is halted. Press %s or turn off power\r\n", - (secondConsole == NULL) /* serial console */ - ? "Reset" : "CTRL-ALT-DEL"); - sync(); - - /* allow time for last message to reach serial console */ - sleep(2); - - if (sig == SIGUSR2 && kernelVersion >= KERNEL_VERSION(2,2,0)) - init_reboot(RB_POWER_OFF); - else - init_reboot(RB_HALT_SYSTEM); - - loop_forever(); -} - -static void reboot_signal(int sig) -{ - shutdown_system(); - message(CONSOLE|LOG, "Please stand by while rebooting the system.\r\n"); - sync(); - - /* allow time for last message to reach serial console */ - sleep(2); - - init_reboot(RB_AUTOBOOT); - - loop_forever(); -} - -static void ctrlaltdel_signal(int sig) -{ - run_actions(CTRLALTDEL); -} - -#endif /* ! DEBUG_INIT */ - -static void new_initAction(initActionEnum action, char *process, char *cons) -{ - initAction *newAction; - - if (*cons == '\0') - cons = console; - - /* If BusyBox detects that a serial console is in use, - * then entries not refering to the console or null devices will _not_ be run. - * The exception to this rule is the null device. - */ - if (secondConsole == NULL && strcmp(cons, console) - && strcmp(cons, "/dev/null")) - return; - if (strcmp(cons, "/dev/null") == 0 && action == ASKFIRST) - return; - - - newAction = calloc((size_t) (1), sizeof(initAction)); - if (!newAction) { - message(LOG | CONSOLE, "Memory allocation failure\n"); - loop_forever(); - } - newAction->nextPtr = initActionList; - initActionList = newAction; - strncpy(newAction->process, process, 255); - newAction->action = action; - strncpy(newAction->console, cons, 255); - newAction->pid = 0; -// message(LOG|CONSOLE, "process='%s' action='%d' console='%s'\n", -// newAction->process, newAction->action, newAction->console); -} - -static void delete_initAction(initAction * action) -{ - initAction *a, *b = NULL; - - for (a = initActionList; a; b = a, a = a->nextPtr) { - if (a == action) { - if (b == NULL) { - initActionList = a->nextPtr; - } else { - b->nextPtr = a->nextPtr; - } - free(a); - break; - } - } -} - -/* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined, - * then parse_inittab() simply adds in some default - * actions(i.e., runs INIT_SCRIPT and then starts a pair - * of "askfirst" shells). If BB_FEATURE_USE_INITTAB - * _is_ defined, but /etc/inittab is missing, this - * results in the same set of default behaviors. - * */ -static void parse_inittab(void) -{ -#ifdef BB_FEATURE_USE_INITTAB - FILE *file; - char buf[256], lineAsRead[256], tmpConsole[256]; - char *id, *runlev, *action, *process, *eol; - const struct initActionType *a = actions; - int foundIt; - - - file = fopen(INITTAB, "r"); - if (file == NULL) { - /* No inittab file -- set up some default behavior */ -#endif - /* Reboot on Ctrl-Alt-Del */ - new_initAction(CTRLALTDEL, "/sbin/reboot", console); - /* Swapoff on halt/reboot */ - new_initAction(SHUTDOWN, "/sbin/swapoff -a", console); - /* Umount all filesystems on halt/reboot */ - new_initAction(SHUTDOWN, "/bin/umount -a -r", console); - /* Askfirst shell on tty1 */ - new_initAction(ASKFIRST, LOGIN_SHELL, console); - /* Askfirst shell on tty2 */ - if (secondConsole != NULL) - new_initAction(ASKFIRST, LOGIN_SHELL, secondConsole); - /* Askfirst shell on tty3 */ - if (thirdConsole != NULL) - new_initAction(ASKFIRST, LOGIN_SHELL, thirdConsole); - /* Askfirst shell on tty4 */ - if (fourthConsole != NULL) - new_initAction(ASKFIRST, LOGIN_SHELL, fourthConsole); - /* sysinit */ - new_initAction(SYSINIT, INIT_SCRIPT, console); - - return; -#ifdef BB_FEATURE_USE_INITTAB - } - - while (fgets(buf, 255, file) != NULL) { - foundIt = FALSE; - /* Skip leading spaces */ - for (id = buf; *id == ' ' || *id == '\t'; id++); - - /* Skip the line if it's a comment */ - if (*id == '#' || *id == '\n') - continue; - - /* Trim the trailing \n */ - eol = strrchr(id, '\n'); - if (eol != NULL) - *eol = '\0'; - - /* Keep a copy around for posterity's sake (and error msgs) */ - strcpy(lineAsRead, buf); - - /* Separate the ID field from the runlevels */ - runlev = strchr(id, ':'); - if (runlev == NULL || *(runlev + 1) == '\0') { - message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead); - continue; - } else { - *runlev = '\0'; - ++runlev; - } - - /* Separate the runlevels from the action */ - action = strchr(runlev, ':'); - if (action == NULL || *(action + 1) == '\0') { - message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead); - continue; - } else { - *action = '\0'; - ++action; - } - - /* Separate the action from the process */ - process = strchr(action, ':'); - if (process == NULL || *(process + 1) == '\0') { - message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead); - continue; - } else { - *process = '\0'; - ++process; - } - - /* Ok, now process it */ - a = actions; - while (a->name != 0) { - if (strcmp(a->name, action) == 0) { - if (*id != '\0') { - strcpy(tmpConsole, "/dev/"); - strncat(tmpConsole, id, 200); - id = tmpConsole; - } - new_initAction(a->action, process, id); - foundIt = TRUE; - } - a++; - } - if (foundIt == TRUE) - continue; - else { - /* Choke on an unknown action */ - message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead); - } - } - return; -#endif /* BB_FEATURE_USE_INITTAB */ -} - - - -extern int init_main(int argc, char **argv) -{ - initAction *a, *tmp; - pid_t wpid; - int status; - -#ifndef DEBUG_INIT - /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ - if (getpid() != 1 -#ifdef BB_FEATURE_LINUXRC - && strstr(applet_name, "linuxrc") == NULL -#endif - ) - { - show_usage(); - } - /* Set up sig handlers -- be sure to - * clear all of these in run() */ - signal(SIGUSR1, halt_signal); - signal(SIGUSR2, halt_signal); - signal(SIGINT, ctrlaltdel_signal); - signal(SIGTERM, reboot_signal); - - /* Turn off rebooting via CTL-ALT-DEL -- we get a - * SIGINT on CAD so we can shut things down gracefully... */ - init_reboot(RB_DISABLE_CAD); -#endif - - /* Figure out what kernel this is running */ - kernelVersion = get_kernel_revision(); - - /* Figure out where the default console should be */ - console_init(); - - /* Close whatever files are open, and reset the console. */ - close(0); - close(1); - close(2); - set_term(0); - chdir("/"); - setsid(); - - /* Make sure PATH is set to something sane */ - putenv("PATH="_PATH_STDPATH); - - /* Hello world */ -#ifndef DEBUG_INIT - message( -#if ! defined BB_FEATURE_EXTRA_QUIET - CONSOLE| -#endif - LOG, - "init started: %s\r\n", full_version); -#else - message( -#if ! defined BB_FEATURE_EXTRA_QUIET - CONSOLE| -#endif - LOG, - "init(%d) started: %s\r\n", getpid(), full_version); -#endif - - - /* Make sure there is enough memory to do something useful. */ - check_memory(); - - /* Check if we are supposed to be in single user mode */ - if (argc > 1 && (!strcmp(argv[1], "single") || - !strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) { - /* Ask first then start a shell on tty2-4 */ - if (secondConsole != NULL) - new_initAction(ASKFIRST, LOGIN_SHELL, secondConsole); - if (thirdConsole != NULL) - new_initAction(ASKFIRST, LOGIN_SHELL, thirdConsole); - if (fourthConsole != NULL) - new_initAction(ASKFIRST, LOGIN_SHELL, fourthConsole); - /* Start a shell on tty1 */ - new_initAction(RESPAWN, LOGIN_SHELL, console); - } else { - /* Not in single user mode -- see what inittab says */ - - /* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined, - * then parse_inittab() simply adds in some default - * actions(i.e., runs INIT_SCRIPT and then starts a pair - * of "askfirst" shells */ - parse_inittab(); - } - - /* Make the command line just say "init" -- thats all, nothing else */ - fixup_argv(argc, argv, "init"); - - /* Now run everything that needs to be run */ - - /* First run the sysinit command */ - run_actions(SYSINIT); - - /* Next run anything that wants to block */ - run_actions(WAIT); - - /* Next run anything to be run only once */ - for (a = initActionList; a; a = tmp) { - tmp = a->nextPtr; - if (a->action == ONCE) { - run(a->process, a->console, FALSE); - /* Now remove the "once" entry from the list */ - delete_initAction(a); - } - } - /* If there is nothing else to do, stop */ - if (initActionList == NULL) { - message(LOG | CONSOLE, - "No more tasks for init -- sleeping forever.\n"); - loop_forever(); - } - - /* Now run the looping stuff for the rest of forever */ - while (1) { - for (a = initActionList; a; a = a->nextPtr) { - /* Only run stuff with pid==0. If they have - * a pid, that means they are still running */ - if (a->pid == 0) { - switch (a->action) { - case RESPAWN: - /* run the respawn stuff */ - a->pid = run(a->process, a->console, FALSE); - break; - case ASKFIRST: - /* run the askfirst stuff */ - a->pid = run(a->process, a->console, TRUE); - break; - /* silence the compiler's incessant whining */ - default: - break; - } - } - } - /* Wait for a child process to exit */ - wpid = wait(&status); - if (wpid > 0) { - /* Find out who died and clean up their corpse */ - for (a = initActionList; a; a = a->nextPtr) { - if (a->pid == wpid) { - a->pid = 0; - message(LOG, - "Process '%s' (pid %d) exited. Scheduling it for restart.\n", - a->process, wpid); - } - } - } - sleep(1); - } -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/init/poweroff.c b/busybox/init/poweroff.c deleted file mode 100644 index db20a4572..000000000 --- a/busybox/init/poweroff.c +++ /dev/null @@ -1,41 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini poweroff implementation for busybox - * - * - * 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 - * - */ - -#include "busybox.h" -#include - -extern int poweroff_main(int argc, char **argv) -{ -#ifdef BB_FEATURE_LINUXRC - /* don't assume init's pid == 1 */ - pid_t *pid = find_pid_by_name("init"); - if (!pid || *pid<=0) { - pid = find_pid_by_name("linuxrc"); - if (!pid || *pid<=0) - error_msg_and_die("no process killed"); - } - return(kill(*pid, SIGUSR2)); -#else - return(kill(1, SIGUSR2)); -#endif -} diff --git a/busybox/init/reboot.c b/busybox/init/reboot.c deleted file mode 100644 index 35afd74ff..000000000 --- a/busybox/init/reboot.c +++ /dev/null @@ -1,49 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini reboot implementation for busybox - * - * - * 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 - * - */ - -#include "busybox.h" -#include - -extern int reboot_main(int argc, char **argv) -{ -#ifdef BB_FEATURE_LINUXRC - /* don't assume init's pid == 1 */ - pid_t *pid = find_pid_by_name("init"); - if (!pid || *pid<=0) { - pid = find_pid_by_name("linuxrc"); - if (!pid || *pid<=0) - error_msg_and_die("no process killed"); - } - return(kill(*pid, SIGTERM)); -#else - return(kill(1, SIGTERM)); -#endif -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/insmod.c b/busybox/insmod.c deleted file mode 100644 index 413af5ce7..000000000 --- a/busybox/insmod.c +++ /dev/null @@ -1,3481 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini insmod implementation for busybox - * - * This version of insmod supports x86, ARM, SH3/4, powerpc, m68k, - * and MIPS. - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen - * and Ron Alder - * - * Modified by Bryan Rittmeyer to support SH4 - * and (theoretically) SH3. I have only tested SH4 in little endian mode. - * - * Modified by Alcove, Julien Gaulmin and - * Nicolas Ferre to support ARM7TDMI. Only - * very minor changes required to also work with StrongArm and presumably - * all ARM based systems. - * - * Magnus Damm added PowerPC support 20-Feb-2001. - * PowerPC specific code stolen from modutils-2.3.16, - * written by Paul Mackerras, Copyright 1996, 1997 Linux International. - * I've only tested the code on mpc8xx platforms in big-endian mode. - * Did some cleanup and added BB_USE_xxx_ENTRIES... - * - * Quinn Jensen added MIPS support 23-Feb-2001. - * based on modutils-2.4.2 - * MIPS specific support for Elf loading and relocation. - * Copyright 1996, 1997 Linux International. - * Contributed by Ralf Baechle - * - * Based almost entirely on the Linux modutils-2.3.11 implementation. - * Copyright 1996, 1997 Linux International. - * New implementation contributed by Richard Henderson - * Based on original work by Bjorn Ekwall - * Restructured (and partly rewritten) by: - * Björn Ekwall February 1999 - * - * 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 -#include -#include "busybox.h" - -#ifdef BB_FEATURE_NEW_MODULE_INTERFACE -# undef BB_FEATURE_OLD_MODULE_INTERFACE -# define new_sys_init_module init_module -#else -# define old_sys_init_module init_module -#endif - -#ifdef BB_FEATURE_INSMOD_LOADINKMEM -#define LOADBITS 0 -#else -#define LOADBITS 1 -#endif - -#if defined(__powerpc__) -#define BB_USE_PLT_ENTRIES -#define BB_PLT_ENTRY_SIZE 16 -#endif - -#if defined(__arm__) -#define BB_USE_PLT_ENTRIES -#define BB_PLT_ENTRY_SIZE 8 -#define BB_USE_GOT_ENTRIES -#define BB_GOT_ENTRY_SIZE 8 -#endif - -#if defined(__sh__) -#define BB_USE_GOT_ENTRIES -#define BB_GOT_ENTRY_SIZE 4 -#endif - -#if defined(__i386__) -#define BB_USE_GOT_ENTRIES -#define BB_GOT_ENTRY_SIZE 4 -#endif - -#if defined(__mips__) -// neither used -#endif - -//---------------------------------------------------------------------------- -//--------modutils module.h, lines 45-242 -//---------------------------------------------------------------------------- - -/* Definitions for the Linux module syscall interface. - Copyright 1996, 1997 Linux International. - - Contributed by Richard Henderson - - This file is part of the Linux modutils. - - 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. */ - - -#ifndef MODUTILS_MODULE_H -static const int MODUTILS_MODULE_H = 1; - -/* This file contains the structures used by the 2.0 and 2.1 kernels. - We do not use the kernel headers directly because we do not wish - to be dependant on a particular kernel version to compile insmod. */ - - -/*======================================================================*/ -/* The structures used by Linux 2.0. */ - -/* The symbol format used by get_kernel_syms(2). */ -struct old_kernel_sym -{ - unsigned long value; - char name[60]; -}; - -struct old_module_ref -{ - unsigned long module; /* kernel addresses */ - unsigned long next; -}; - -struct old_module_symbol -{ - unsigned long addr; - unsigned long name; -}; - -struct old_symbol_table -{ - int size; /* total, including string table!!! */ - int n_symbols; - int n_refs; - struct old_module_symbol symbol[0]; /* actual size defined by n_symbols */ - struct old_module_ref ref[0]; /* actual size defined by n_refs */ -}; - -struct old_mod_routines -{ - unsigned long init; - unsigned long cleanup; -}; - -struct old_module -{ - unsigned long next; - unsigned long ref; /* the list of modules that refer to me */ - unsigned long symtab; - unsigned long name; - int size; /* size of module in pages */ - unsigned long addr; /* address of module */ - int state; - unsigned long cleanup; /* cleanup routine */ -}; - -/* Sent to init_module(2) or'ed into the code size parameter. */ -static const int OLD_MOD_AUTOCLEAN = 0x40000000; /* big enough, but no sign problems... */ - -int get_kernel_syms(struct old_kernel_sym *); -int old_sys_init_module(const char *name, char *code, unsigned codesize, - struct old_mod_routines *, struct old_symbol_table *); - -/*======================================================================*/ -/* For sizeof() which are related to the module platform and not to the - environment isnmod is running in, use sizeof_xx instead of sizeof(xx). */ - -#define tgt_sizeof_char sizeof(char) -#define tgt_sizeof_short sizeof(short) -#define tgt_sizeof_int sizeof(int) -#define tgt_sizeof_long sizeof(long) -#define tgt_sizeof_char_p sizeof(char *) -#define tgt_sizeof_void_p sizeof(void *) -#define tgt_long long - -#if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64) -#undef tgt_sizeof_long -#undef tgt_sizeof_char_p -#undef tgt_sizeof_void_p -#undef tgt_long -static const int tgt_sizeof_long = 8; -static const int tgt_sizeof_char_p = 8; -static const int tgt_sizeof_void_p = 8; -#define tgt_long long long -#endif - -/*======================================================================*/ -/* The structures used in Linux 2.1. */ - -/* Note: new_module_symbol does not use tgt_long intentionally */ -struct new_module_symbol -{ - unsigned long value; - unsigned long name; -}; - -struct new_module_persist; - -struct new_module_ref -{ - unsigned tgt_long dep; /* kernel addresses */ - unsigned tgt_long ref; - unsigned tgt_long next_ref; -}; - -struct new_module -{ - unsigned tgt_long size_of_struct; /* == sizeof(module) */ - unsigned tgt_long next; - unsigned tgt_long name; - unsigned tgt_long size; - - tgt_long usecount; - unsigned tgt_long flags; /* AUTOCLEAN et al */ - - unsigned nsyms; - unsigned ndeps; - - unsigned tgt_long syms; - unsigned tgt_long deps; - unsigned tgt_long refs; - unsigned tgt_long init; - unsigned tgt_long cleanup; - unsigned tgt_long ex_table_start; - unsigned tgt_long ex_table_end; -#ifdef __alpha__ - unsigned tgt_long gp; -#endif - /* Everything after here is extension. */ - unsigned tgt_long persist_start; - unsigned tgt_long persist_end; - unsigned tgt_long can_unload; - unsigned tgt_long runsize; -#ifdef BB_FEATURE_NEW_MODULE_INTERFACE - const char *kallsyms_start; /* All symbols for kernel debugging */ - const char *kallsyms_end; - const char *archdata_start; /* arch specific data for module */ - const char *archdata_end; - const char *kernel_data; /* Reserved for kernel internal use */ -#endif -}; - -#define ARCHDATA_SEC_NAME "__archdata" -#define KALLSYMS_SEC_NAME "__kallsyms" - - -struct new_module_info -{ - unsigned long addr; - unsigned long size; - unsigned long flags; - long usecount; -}; - -/* Bits of module.flags. */ -static const int NEW_MOD_RUNNING = 1; -static const int NEW_MOD_DELETED = 2; -static const int NEW_MOD_AUTOCLEAN = 4; -static const int NEW_MOD_VISITED = 8; -static const int NEW_MOD_USED_ONCE = 16; - -int new_sys_init_module(const char *name, const struct new_module *); -int query_module(const char *name, int which, void *buf, size_t bufsize, - size_t *ret); - -/* Values for query_module's which. */ - -static const int QM_MODULES = 1; -static const int QM_DEPS = 2; -static const int QM_REFS = 3; -static const int QM_SYMBOLS = 4; -static const int QM_INFO = 5; - -/*======================================================================*/ -/* The system calls unchanged between 2.0 and 2.1. */ - -unsigned long create_module(const char *, size_t); -int delete_module(const char *); - - -#endif /* module.h */ - -//---------------------------------------------------------------------------- -//--------end of modutils module.h -//---------------------------------------------------------------------------- - - - -//---------------------------------------------------------------------------- -//--------modutils obj.h, lines 253-462 -//---------------------------------------------------------------------------- - -/* Elf object file loading and relocation routines. - Copyright 1996, 1997 Linux International. - - Contributed by Richard Henderson - - This file is part of the Linux modutils. - - 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. */ - - -#ifndef MODUTILS_OBJ_H -static const int MODUTILS_OBJ_H = 1; - -/* The relocatable object is manipulated using elfin types. */ - -#include -#include - - -/* Machine-specific elf macros for i386 et al. */ - -/* the SH changes have only been tested on the SH4 in =little endian= mode */ -/* I'm not sure about big endian, so let's warn: */ - -#if (defined(__SH4__) || defined(__SH3__)) && defined(__BIG_ENDIAN__) -#error insmod.c may require changes for use on big endian SH4/SH3 -#endif - -/* it may or may not work on the SH1/SH2... So let's error on those - also */ -#if (defined(__sh__) && (!(defined(__SH3__) || defined(__SH4__)))) -#error insmod.c may require changes for non-SH3/SH4 use -#endif - -#define ELFCLASSM ELFCLASS32 - -#if (defined(__mc68000__)) -#define ELFDATAM ELFDATA2MSB -#endif - - - -#if defined(__sh__) - -#define MATCH_MACHINE(x) (x == EM_SH) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela -#define ELFDATAM ELFDATA2LSB - -#elif defined(__arm__) - -#define MATCH_MACHINE(x) (x == EM_ARM) -#define SHT_RELM SHT_REL -#define Elf32_RelM Elf32_Rel -#define ELFDATAM ELFDATA2LSB - -#elif defined(__powerpc__) - -#define MATCH_MACHINE(x) (x == EM_PPC) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela -#define ELFDATAM ELFDATA2MSB - -#elif defined(__mips__) - -/* Account for ELF spec changes. */ -#ifndef EM_MIPS_RS3_LE -#ifdef EM_MIPS_RS4_BE -#define EM_MIPS_RS3_LE EM_MIPS_RS4_BE -#else -#define EM_MIPS_RS3_LE 10 -#endif -#endif /* !EM_MIPS_RS3_LE */ - -#define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE) -#define SHT_RELM SHT_REL -#define Elf32_RelM Elf32_Rel -#ifdef __MIPSEB__ -#define ELFDATAM ELFDATA2MSB -#endif -#ifdef __MIPSEL__ -#define ELFDATAM ELFDATA2LSB -#endif - -#elif defined(__i386__) - -/* presumably we can use these for anything but the SH and ARM*/ -/* this is the previous behavior, but it does result in - insmod.c being broken on anything except i386 */ -#ifndef EM_486 -#define MATCH_MACHINE(x) (x == EM_386) -#else -#define MATCH_MACHINE(x) (x == EM_386 || x == EM_486) -#endif - -#define SHT_RELM SHT_REL -#define Elf32_RelM Elf32_Rel -#define ELFDATAM ELFDATA2LSB - -#elif defined(__mc68000__) - -#define MATCH_MACHINE(x) (x == EM_68K) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela - -#else -#error Sorry, but insmod.c does not yet support this architecture... -#endif - -#ifndef ElfW -# if ELFCLASSM == ELFCLASS32 -# define ElfW(x) Elf32_ ## x -# define ELFW(x) ELF32_ ## x -# else -# define ElfW(x) Elf64_ ## x -# define ELFW(x) ELF64_ ## x -# endif -#endif - -/* For some reason this is missing from libc5. */ -#ifndef ELF32_ST_INFO -# define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) -#endif - -#ifndef ELF64_ST_INFO -# define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) -#endif - -struct obj_string_patch; -struct obj_symbol_patch; - -struct obj_section -{ - ElfW(Shdr) header; - const char *name; - char *contents; - struct obj_section *load_next; - int idx; -}; - -struct obj_symbol -{ - struct obj_symbol *next; /* hash table link */ - const char *name; - unsigned long value; - unsigned long size; - int secidx; /* the defining section index/module */ - int info; - int ksymidx; /* for export to the kernel symtab */ - int referenced; /* actually used in the link */ -}; - -/* Hardcode the hash table size. We shouldn't be needing so many - symbols that we begin to degrade performance, and we get a big win - by giving the compiler a constant divisor. */ - -#define HASH_BUCKETS 521 - -struct obj_file -{ - ElfW(Ehdr) header; - ElfW(Addr) baseaddr; - struct obj_section **sections; - struct obj_section *load_order; - struct obj_section **load_order_search_start; - struct obj_string_patch *string_patches; - struct obj_symbol_patch *symbol_patches; - int (*symbol_cmp)(const char *, const char *); - unsigned long (*symbol_hash)(const char *); - unsigned long local_symtab_size; - struct obj_symbol **local_symtab; - struct obj_symbol *symtab[HASH_BUCKETS]; -}; - -enum obj_reloc -{ - obj_reloc_ok, - obj_reloc_overflow, - obj_reloc_dangerous, - obj_reloc_unhandled -}; - -struct obj_string_patch -{ - struct obj_string_patch *next; - int reloc_secidx; - ElfW(Addr) reloc_offset; - ElfW(Addr) string_offset; -}; - -struct obj_symbol_patch -{ - struct obj_symbol_patch *next; - int reloc_secidx; - ElfW(Addr) reloc_offset; - struct obj_symbol *sym; -}; - - -/* Generic object manipulation routines. */ - -static unsigned long obj_elf_hash(const char *); - -static unsigned long obj_elf_hash_n(const char *, unsigned long len); - -static struct obj_symbol *obj_find_symbol (struct obj_file *f, - const char *name); - -static ElfW(Addr) obj_symbol_final_value(struct obj_file *f, - struct obj_symbol *sym); - -#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING -static void obj_set_symbol_compare(struct obj_file *f, - int (*cmp)(const char *, const char *), - unsigned long (*hash)(const char *)); -#endif - -static struct obj_section *obj_find_section (struct obj_file *f, - const char *name); - -static void obj_insert_section_load_order (struct obj_file *f, - struct obj_section *sec); - -static struct obj_section *obj_create_alloced_section (struct obj_file *f, - const char *name, - unsigned long align, - unsigned long size); - -static struct obj_section *obj_create_alloced_section_first (struct obj_file *f, - const char *name, - unsigned long align, - unsigned long size); - -static void *obj_extend_section (struct obj_section *sec, unsigned long more); - -static int obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, - const char *string); - -static int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, - struct obj_symbol *sym); - -static int obj_check_undefineds(struct obj_file *f); - -static void obj_allocate_commons(struct obj_file *f); - -static unsigned long obj_load_size (struct obj_file *f); - -static int obj_relocate (struct obj_file *f, ElfW(Addr) base); - -static struct obj_file *obj_load(FILE *f, int loadprogbits); - -static int obj_create_image (struct obj_file *f, char *image); - -/* Architecture specific manipulation routines. */ - -static struct obj_file *arch_new_file (void); - -static struct obj_section *arch_new_section (void); - -static struct obj_symbol *arch_new_symbol (void); - -static enum obj_reloc arch_apply_relocation (struct obj_file *f, - struct obj_section *targsec, - struct obj_section *symsec, - struct obj_symbol *sym, - ElfW(RelM) *rel, ElfW(Addr) value); - -static int arch_create_got (struct obj_file *f); - -static int arch_init_module (struct obj_file *f, struct new_module *); - -#endif /* obj.h */ -//---------------------------------------------------------------------------- -//--------end of modutils obj.h -//---------------------------------------------------------------------------- - - - - - -#define _PATH_MODULES "/lib/modules" -static const int STRVERSIONLEN = 32; - -/*======================================================================*/ - -static int flag_force_load = 0; -static int flag_autoclean = 0; -static int flag_verbose = 0; -static int flag_export = 1; - - -/*======================================================================*/ - -/* previously, these were named i386_* but since we could be - compiling for the sh, I've renamed them to the more general - arch_* These structures are the same between the x86 and SH, - and we can't support anything else right now anyway. In the - future maybe they should be #if defined'd */ - -/* Done ;-) */ - - - -#if defined(BB_USE_PLT_ENTRIES) -struct arch_plt_entry -{ - int offset; - int allocated:1; - int inited:1; /* has been set up */ -}; -#endif - -#if defined(BB_USE_GOT_ENTRIES) -struct arch_got_entry { - int offset; - unsigned offset_done:1; - unsigned reloc_done:1; -}; -#endif - -#if defined(__mips__) -struct mips_hi16 -{ - struct mips_hi16 *next; - Elf32_Addr *addr; - Elf32_Addr value; -}; -#endif - -struct arch_file { - struct obj_file root; -#if defined(BB_USE_PLT_ENTRIES) - struct obj_section *plt; -#endif -#if defined(BB_USE_GOT_ENTRIES) - struct obj_section *got; -#endif -#if defined(__mips__) - struct mips_hi16 *mips_hi16_list; -#endif -}; - -struct arch_symbol { - struct obj_symbol root; -#if defined(BB_USE_PLT_ENTRIES) - struct arch_plt_entry pltent; -#endif -#if defined(BB_USE_GOT_ENTRIES) - struct arch_got_entry gotent; -#endif -}; - - -struct external_module { - const char *name; - ElfW(Addr) addr; - int used; - size_t nsyms; - struct new_module_symbol *syms; -}; - -static struct new_module_symbol *ksyms; -static size_t nksyms; - -static struct external_module *ext_modules; -static int n_ext_modules; -static int n_ext_modules_used; -extern int delete_module(const char *); - -static char m_filename[FILENAME_MAX + 1]; -static char m_fullName[FILENAME_MAX + 1]; - - - -/*======================================================================*/ - - -static int check_module_name_match(const char *filename, struct stat *statbuf, - void *userdata) -{ - char *fullname = (char *) userdata; - - if (fullname[0] == '\0') - return (FALSE); - else { - char *tmp, *tmp1 = strdup(filename); - tmp = get_last_path_component(tmp1); - if (strcmp(tmp, fullname) == 0) { - free(tmp1); - /* Stop searching if we find a match */ - safe_strncpy(m_filename, filename, sizeof(m_filename)); - return (TRUE); - } - free(tmp1); - } - return (FALSE); -} - - -/*======================================================================*/ - -static struct obj_file *arch_new_file(void) -{ - struct arch_file *f; - f = xmalloc(sizeof(*f)); - -#if defined(BB_USE_PLT_ENTRIES) - f->plt = NULL; -#endif -#if defined(BB_USE_GOT_ENTRIES) - f->got = NULL; -#endif -#if defined(__mips__) - f->mips_hi16_list = NULL; -#endif - - return &f->root; -} - -static struct obj_section *arch_new_section(void) -{ - return xmalloc(sizeof(struct obj_section)); -} - -static struct obj_symbol *arch_new_symbol(void) -{ - struct arch_symbol *sym; - sym = xmalloc(sizeof(*sym)); - -#if defined(BB_USE_PLT_ENTRIES) - memset(&sym->pltent, 0, sizeof(sym->pltent)); -#endif -#if defined(BB_USE_GOT_ENTRIES) - memset(&sym->gotent, 0, sizeof(sym->gotent)); -#endif - - return &sym->root; -} - -static enum obj_reloc -arch_apply_relocation(struct obj_file *f, - struct obj_section *targsec, - struct obj_section *symsec, - struct obj_symbol *sym, - ElfW(RelM) *rel, ElfW(Addr) v) -{ - struct arch_file *ifile = (struct arch_file *) f; -#if !(defined(__mips__)) - struct arch_symbol *isym = (struct arch_symbol *) sym; -#endif - - ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset); - ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset; -#if defined(BB_USE_GOT_ENTRIES) - ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0; -#endif -#if defined(BB_USE_PLT_ENTRIES) - ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0; - struct arch_plt_entry *pe; - unsigned long *ip; -#endif - enum obj_reloc ret = obj_reloc_ok; - - switch (ELF32_R_TYPE(rel->r_info)) { - -/* even though these constants seem to be the same for - the i386 and the sh, we "#if define" them for clarity - and in case that ever changes */ -#if defined(__sh__) - case R_SH_NONE: -#elif defined(__arm__) - case R_ARM_NONE: -#elif defined(__i386__) - case R_386_NONE: -#elif defined(__mc68000__) - case R_68K_NONE: -#elif defined(__powerpc__) - case R_PPC_NONE: -#elif defined(__mips__) - case R_MIPS_NONE: -#endif - break; - -#if defined(__sh__) - case R_SH_DIR32: -#elif defined(__arm__) - case R_ARM_ABS32: -#elif defined(__i386__) - case R_386_32: -#elif defined(__mc68000__) - case R_68K_32: -#elif defined(__powerpc__) - case R_PPC_ADDR32: -#elif defined(__mips__) - case R_MIPS_32: -#endif - *loc += v; - break; -#if defined(__mc68000__) - case R_68K_8: - if (v > 0xff) - ret = obj_reloc_overflow; - *(char *)loc = v; - break; - case R_68K_16: - if (v > 0xffff) - ret = obj_reloc_overflow; - *(short *)loc = v; - break; -#endif /* __mc68000__ */ - -#if defined(__powerpc__) - case R_PPC_ADDR16_HA: - *(unsigned short *)loc = (v + 0x8000) >> 16; - break; - - case R_PPC_ADDR16_HI: - *(unsigned short *)loc = v >> 16; - break; - - case R_PPC_ADDR16_LO: - *(unsigned short *)loc = v; - break; -#endif - -#if defined(__mips__) - case R_MIPS_26: - if (v % 4) - ret = obj_reloc_dangerous; - if ((v & 0xf0000000) != ((dot + 4) & 0xf0000000)) - ret = obj_reloc_overflow; - *loc = - (*loc & ~0x03ffffff) | ((*loc + (v >> 2)) & - 0x03ffffff); - break; - - case R_MIPS_HI16: - { - struct mips_hi16 *n; - - /* We cannot relocate this one now because we don't know the value - of the carry we need to add. Save the information, and let LO16 - do the actual relocation. */ - n = (struct mips_hi16 *) xmalloc(sizeof *n); - n->addr = loc; - n->value = v; - n->next = ifile->mips_hi16_list; - ifile->mips_hi16_list = n; - break; - } - - case R_MIPS_LO16: - { - unsigned long insnlo = *loc; - Elf32_Addr val, vallo; - - /* Sign extend the addend we extract from the lo insn. */ - vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; - - if (ifile->mips_hi16_list != NULL) { - struct mips_hi16 *l; - - l = ifile->mips_hi16_list; - while (l != NULL) { - struct mips_hi16 *next; - unsigned long insn; - - /* The value for the HI16 had best be the same. */ - assert(v == l->value); - - /* Do the HI16 relocation. Note that we actually don't - need to know anything about the LO16 itself, except where - to find the low 16 bits of the addend needed by the LO16. */ - insn = *l->addr; - val = - ((insn & 0xffff) << 16) + - vallo; - val += v; - - /* Account for the sign extension that will happen in the - low bits. */ - val = - ((val >> 16) + - ((val & 0x8000) != - 0)) & 0xffff; - - insn = (insn & ~0xffff) | val; - *l->addr = insn; - - next = l->next; - free(l); - l = next; - } - - ifile->mips_hi16_list = NULL; - } - - /* Ok, we're done with the HI16 relocs. Now deal with the LO16. */ - val = v + vallo; - insnlo = (insnlo & ~0xffff) | (val & 0xffff); - *loc = insnlo; - break; - } -#endif - -#if defined(__arm__) -#elif defined(__sh__) - case R_SH_REL32: - *loc += v - dot; - break; -#elif defined(__i386__) - case R_386_PLT32: - case R_386_PC32: - *loc += v - dot; - break; -#elif defined(__mc68000__) - case R_68K_PC8: - v -= dot; - if ((Elf32_Sword)v > 0x7f || (Elf32_Sword)v < -(Elf32_Sword)0x80) - ret = obj_reloc_overflow; - *(char *)loc = v; - break; - case R_68K_PC16: - v -= dot; - if ((Elf32_Sword)v > 0x7fff || (Elf32_Sword)v < -(Elf32_Sword)0x8000) - ret = obj_reloc_overflow; - *(short *)loc = v; - break; - case R_68K_PC32: - *(int *)loc = v - dot; - break; -#elif defined(__powerpc__) - case R_PPC_REL32: - *loc = v - dot; - break; -#endif - -#if defined(__sh__) - case R_SH_PLT32: - *loc = v - dot; - break; -#elif defined(__i386__) -#endif - -#if defined(BB_USE_PLT_ENTRIES) - -#if defined(__arm__) - case R_ARM_PC24: - case R_ARM_PLT32: -#endif -#if defined(__powerpc__) - case R_PPC_REL24: -#endif - /* find the plt entry and initialize it if necessary */ - assert(isym != NULL); - - pe = (struct arch_plt_entry*) &isym->pltent; - - if (! pe->inited) { - ip = (unsigned long *) (ifile->plt->contents + pe->offset); - - /* generate some machine code */ - -#if defined(__arm__) - ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */ - ip[1] = v; /* sym@ */ -#endif -#if defined(__powerpc__) - ip[0] = 0x3d600000 + ((v + 0x8000) >> 16); /* lis r11,sym@ha */ - ip[1] = 0x396b0000 + (v & 0xffff); /* addi r11,r11,sym@l */ - ip[2] = 0x7d6903a6; /* mtctr r11 */ - ip[3] = 0x4e800420; /* bctr */ -#endif - pe->inited = 1; - } - - /* relative distance to target */ - v -= dot; - /* if the target is too far away.... */ - if ((int)v < -0x02000000 || (int)v >= 0x02000000) { - /* go via the plt */ - v = plt + pe->offset - dot; - } - if (v & 3) - ret = obj_reloc_dangerous; - - /* merge the offset into the instruction. */ -#if defined(__arm__) - /* Convert to words. */ - v >>= 2; - - *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff); -#endif -#if defined(__powerpc__) - *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc); -#endif - break; -#endif /* BB_USE_PLT_ENTRIES */ - -#if defined(__arm__) -#elif defined(__sh__) - case R_SH_GLOB_DAT: - case R_SH_JMP_SLOT: - *loc = v; - break; -#elif defined(__i386__) - case R_386_GLOB_DAT: - case R_386_JMP_SLOT: - *loc = v; - break; -#elif defined(__mc68000__) - case R_68K_GLOB_DAT: - case R_68K_JMP_SLOT: - *loc = v; - break; -#endif - -#if defined(__arm__) -#elif defined(__sh__) - case R_SH_RELATIVE: - *loc += f->baseaddr + rel->r_addend; - break; -#elif defined(__i386__) - case R_386_RELATIVE: - *loc += f->baseaddr; - break; -#elif defined(__mc68000__) - case R_68K_RELATIVE: - *(int *)loc += f->baseaddr; - break; -#endif - -#if defined(BB_USE_GOT_ENTRIES) - -#if !defined(__68k__) -#if defined(__sh__) - case R_SH_GOTPC: -#elif defined(__arm__) - case R_ARM_GOTPC: -#elif defined(__i386__) - case R_386_GOTPC: -#endif - assert(got != 0); -#if defined(__sh__) - *loc += got - dot + rel->r_addend;; -#elif defined(__i386__) || defined(__arm__) || defined(__m68k_) - *loc += got - dot; -#endif - break; -#endif // __68k__ - -#if defined(__sh__) - case R_SH_GOT32: -#elif defined(__arm__) - case R_ARM_GOT32: -#elif defined(__i386__) - case R_386_GOT32: -#elif defined(__mc68000__) - case R_68K_GOT32: -#endif - assert(isym != NULL); - /* needs an entry in the .got: set it, once */ - if (!isym->gotent.reloc_done) { - isym->gotent.reloc_done = 1; - *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v; - } - /* make the reloc with_respect_to_.got */ -#if defined(__sh__) - *loc += isym->gotent.offset + rel->r_addend; -#elif defined(__i386__) || defined(__arm__) || defined(__mc68000__) - *loc += isym->gotent.offset; -#endif - break; - - /* address relative to the got */ -#if !defined(__mc68000__) -#if defined(__sh__) - case R_SH_GOTOFF: -#elif defined(__arm__) - case R_ARM_GOTOFF: -#elif defined(__i386__) - case R_386_GOTOFF: -#elif defined(__mc68000__) - case R_68K_GOTOFF: -#endif - assert(got != 0); - *loc += v - got; - break; -#endif // __mc68000__ - -#endif /* BB_USE_GOT_ENTRIES */ - - default: - printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info)); - ret = obj_reloc_unhandled; - break; - } - - return ret; -} - -static int arch_create_got(struct obj_file *f) -{ -#if defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES) - struct arch_file *ifile = (struct arch_file *) f; - int i; -#if defined(BB_USE_GOT_ENTRIES) - int got_offset = 0, gotneeded = 0; -#endif -#if defined(BB_USE_PLT_ENTRIES) - int plt_offset = 0, pltneeded = 0; -#endif - struct obj_section *relsec, *symsec, *strsec; - ElfW(RelM) *rel, *relend; - ElfW(Sym) *symtab, *extsym; - const char *strtab, *name; - struct arch_symbol *intsym; - - for (i = 0; i < f->header.e_shnum; ++i) { - relsec = f->sections[i]; - if (relsec->header.sh_type != SHT_RELM) - continue; - - symsec = f->sections[relsec->header.sh_link]; - strsec = f->sections[symsec->header.sh_link]; - - rel = (ElfW(RelM) *) relsec->contents; - relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM))); - symtab = (ElfW(Sym) *) symsec->contents; - strtab = (const char *) strsec->contents; - - for (; rel < relend; ++rel) { - extsym = &symtab[ELF32_R_SYM(rel->r_info)]; - - switch (ELF32_R_TYPE(rel->r_info)) { -#if defined(__arm__) - case R_ARM_GOT32: - break; -#elif defined(__sh__) - case R_SH_GOT32: - break; -#elif defined(__i386__) - case R_386_GOT32: - break; -#elif defined(__mc68000__) - case R_68K_GOT32: - break; -#endif - -#if defined(__powerpc__) - case R_PPC_REL24: - pltneeded = 1; - break; -#endif - -#if defined(__arm__) - case R_ARM_PC24: - case R_ARM_PLT32: - pltneeded = 1; - break; - - case R_ARM_GOTPC: - case R_ARM_GOTOFF: - gotneeded = 1; - if (got_offset == 0) - got_offset = 4; -#elif defined(__sh__) - case R_SH_GOTPC: - case R_SH_GOTOFF: - gotneeded = 1; -#elif defined(__i386__) - case R_386_GOTPC: - case R_386_GOTOFF: - gotneeded = 1; -#endif - - default: - continue; - } - - if (extsym->st_name != 0) { - name = strtab + extsym->st_name; - } else { - name = f->sections[extsym->st_shndx]->name; - } - intsym = (struct arch_symbol *) obj_find_symbol(f, name); -#if defined(BB_USE_GOT_ENTRIES) - if (!intsym->gotent.offset_done) { - intsym->gotent.offset_done = 1; - intsym->gotent.offset = got_offset; - got_offset += BB_GOT_ENTRY_SIZE; - } -#endif -#if defined(BB_USE_PLT_ENTRIES) - if (pltneeded && intsym->pltent.allocated == 0) { - intsym->pltent.allocated = 1; - intsym->pltent.offset = plt_offset; - plt_offset += BB_PLT_ENTRY_SIZE; - intsym->pltent.inited = 0; - pltneeded = 0; - } -#endif - } - } - -#if defined(BB_USE_GOT_ENTRIES) - if (got_offset) { - struct obj_section* myrelsec = obj_find_section(f, ".got"); - - if (myrelsec) { - obj_extend_section(myrelsec, got_offset); - } else { - myrelsec = obj_create_alloced_section(f, ".got", - BB_GOT_ENTRY_SIZE, - got_offset); - assert(myrelsec); - } - - ifile->got = myrelsec; - } -#endif - -#if defined(BB_USE_PLT_ENTRIES) - if (plt_offset) - ifile->plt = obj_create_alloced_section(f, ".plt", - BB_PLT_ENTRY_SIZE, - plt_offset); -#endif -#endif - return 1; -} - -static int arch_init_module(struct obj_file *f, struct new_module *mod) -{ - return 1; -} - - -/*======================================================================*/ - -/* Standard ELF hash function. */ -static inline unsigned long obj_elf_hash_n(const char *name, unsigned long n) -{ - unsigned long h = 0; - unsigned long g; - unsigned char ch; - - while (n > 0) { - ch = *name++; - h = (h << 4) + ch; - if ((g = (h & 0xf0000000)) != 0) { - h ^= g >> 24; - h &= ~g; - } - n--; - } - return h; -} - -static unsigned long obj_elf_hash(const char *name) -{ - return obj_elf_hash_n(name, strlen(name)); -} - -#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING -/* String comparison for non-co-versioned kernel and module. */ - -static int ncv_strcmp(const char *a, const char *b) -{ - size_t alen = strlen(a), blen = strlen(b); - - if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R') - return strncmp(a, b, alen); - else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R') - return strncmp(a, b, blen); - else - return strcmp(a, b); -} - -/* String hashing for non-co-versioned kernel and module. Here - we are simply forced to drop the crc from the hash. */ - -static unsigned long ncv_symbol_hash(const char *str) -{ - size_t len = strlen(str); - if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R') - len -= 10; - return obj_elf_hash_n(str, len); -} - -static void -obj_set_symbol_compare(struct obj_file *f, - int (*cmp) (const char *, const char *), - unsigned long (*hash) (const char *)) -{ - if (cmp) - f->symbol_cmp = cmp; - if (hash) { - struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next; - int i; - - f->symbol_hash = hash; - - memcpy(tmptab, f->symtab, sizeof(tmptab)); - memset(f->symtab, 0, sizeof(f->symtab)); - - for (i = 0; i < HASH_BUCKETS; ++i) - for (sym = tmptab[i]; sym; sym = next) { - unsigned long h = hash(sym->name) % HASH_BUCKETS; - next = sym->next; - sym->next = f->symtab[h]; - f->symtab[h] = sym; - } - } -} - -#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ - -static struct obj_symbol * -obj_add_symbol(struct obj_file *f, const char *name, - unsigned long symidx, int info, - int secidx, ElfW(Addr) value, - unsigned long size) -{ - struct obj_symbol *sym; - unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; - int n_type = ELFW(ST_TYPE) (info); - int n_binding = ELFW(ST_BIND) (info); - - for (sym = f->symtab[hash]; sym; sym = sym->next) - if (f->symbol_cmp(sym->name, name) == 0) { - int o_secidx = sym->secidx; - int o_info = sym->info; - int o_type = ELFW(ST_TYPE) (o_info); - int o_binding = ELFW(ST_BIND) (o_info); - - /* A redefinition! Is it legal? */ - - if (secidx == SHN_UNDEF) - return sym; - else if (o_secidx == SHN_UNDEF) - goto found; - else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) { - /* Cope with local and global symbols of the same name - in the same object file, as might have been created - by ld -r. The only reason locals are now seen at this - level at all is so that we can do semi-sensible things - with parameters. */ - - struct obj_symbol *nsym, **p; - - nsym = arch_new_symbol(); - nsym->next = sym->next; - nsym->ksymidx = -1; - - /* Excise the old (local) symbol from the hash chain. */ - for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next) - continue; - *p = sym = nsym; - goto found; - } else if (n_binding == STB_LOCAL) { - /* Another symbol of the same name has already been defined. - Just add this to the local table. */ - sym = arch_new_symbol(); - sym->next = NULL; - sym->ksymidx = -1; - f->local_symtab[symidx] = sym; - goto found; - } else if (n_binding == STB_WEAK) - return sym; - else if (o_binding == STB_WEAK) - goto found; - /* Don't unify COMMON symbols with object types the programmer - doesn't expect. */ - else if (secidx == SHN_COMMON - && (o_type == STT_NOTYPE || o_type == STT_OBJECT)) - return sym; - else if (o_secidx == SHN_COMMON - && (n_type == STT_NOTYPE || n_type == STT_OBJECT)) - goto found; - else { - /* Don't report an error if the symbol is coming from - the kernel or some external module. */ - if (secidx <= SHN_HIRESERVE) - error_msg("%s multiply defined", name); - return sym; - } - } - - /* Completely new symbol. */ - sym = arch_new_symbol(); - sym->next = f->symtab[hash]; - f->symtab[hash] = sym; - sym->ksymidx = -1; - - if (ELFW(ST_BIND)(info) == STB_LOCAL && symidx != -1) { - if (symidx >= f->local_symtab_size) - error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld", - name, (long) symidx, (long) f->local_symtab_size); - else - f->local_symtab[symidx] = sym; - } - - found: - sym->name = name; - sym->value = value; - sym->size = size; - sym->secidx = secidx; - sym->info = info; - - return sym; -} - -static struct obj_symbol * -obj_find_symbol(struct obj_file *f, const char *name) -{ - struct obj_symbol *sym; - unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; - - for (sym = f->symtab[hash]; sym; sym = sym->next) - if (f->symbol_cmp(sym->name, name) == 0) - return sym; - - return NULL; -} - -static ElfW(Addr) - obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym) -{ - if (sym) { - if (sym->secidx >= SHN_LORESERVE) - return sym->value; - - return sym->value + f->sections[sym->secidx]->header.sh_addr; - } else { - /* As a special case, a NULL sym has value zero. */ - return 0; - } -} - -static struct obj_section *obj_find_section(struct obj_file *f, const char *name) -{ - int i, n = f->header.e_shnum; - - for (i = 0; i < n; ++i) - if (strcmp(f->sections[i]->name, name) == 0) - return f->sections[i]; - - return NULL; -} - -static int obj_load_order_prio(struct obj_section *a) -{ - unsigned long af, ac; - - af = a->header.sh_flags; - - ac = 0; - if (a->name[0] != '.' || strlen(a->name) != 10 || - strcmp(a->name + 5, ".init")) - ac |= 32; - if (af & SHF_ALLOC) - ac |= 16; - if (!(af & SHF_WRITE)) - ac |= 8; - if (af & SHF_EXECINSTR) - ac |= 4; - if (a->header.sh_type != SHT_NOBITS) - ac |= 2; - - return ac; -} - -static void -obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec) -{ - struct obj_section **p; - int prio = obj_load_order_prio(sec); - for (p = f->load_order_search_start; *p; p = &(*p)->load_next) - if (obj_load_order_prio(*p) < prio) - break; - sec->load_next = *p; - *p = sec; -} - -static struct obj_section *obj_create_alloced_section(struct obj_file *f, - const char *name, - unsigned long align, - unsigned long size) -{ - int newidx = f->header.e_shnum++; - struct obj_section *sec; - - f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec)); - f->sections[newidx] = sec = arch_new_section(); - - memset(sec, 0, sizeof(*sec)); - sec->header.sh_type = SHT_PROGBITS; - sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; - sec->header.sh_size = size; - sec->header.sh_addralign = align; - sec->name = name; - sec->idx = newidx; - if (size) - sec->contents = xmalloc(size); - - obj_insert_section_load_order(f, sec); - - return sec; -} - -static struct obj_section *obj_create_alloced_section_first(struct obj_file *f, - const char *name, - unsigned long align, - unsigned long size) -{ - int newidx = f->header.e_shnum++; - struct obj_section *sec; - - f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec)); - f->sections[newidx] = sec = arch_new_section(); - - memset(sec, 0, sizeof(*sec)); - sec->header.sh_type = SHT_PROGBITS; - sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; - sec->header.sh_size = size; - sec->header.sh_addralign = align; - sec->name = name; - sec->idx = newidx; - if (size) - sec->contents = xmalloc(size); - - sec->load_next = f->load_order; - f->load_order = sec; - if (f->load_order_search_start == &f->load_order) - f->load_order_search_start = &sec->load_next; - - return sec; -} - -static void *obj_extend_section(struct obj_section *sec, unsigned long more) -{ - unsigned long oldsize = sec->header.sh_size; - if (more) { - sec->contents = xrealloc(sec->contents, sec->header.sh_size += more); - } - return sec->contents + oldsize; -} - - -/* Conditionally add the symbols from the given symbol set to the - new module. */ - -static int -add_symbols_from( - struct obj_file *f, - int idx, struct new_module_symbol *syms, size_t nsyms) -{ - struct new_module_symbol *s; - size_t i; - int used = 0; - - for (i = 0, s = syms; i < nsyms; ++i, ++s) { - - /* Only add symbols that are already marked external. If we - override locals we may cause problems for argument initialization. - We will also create a false dependency on the module. */ - struct obj_symbol *sym; - - sym = obj_find_symbol(f, (char *) s->name); - if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) { - sym = obj_add_symbol(f, (char *) s->name, -1, - ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), - idx, s->value, 0); - /* Did our symbol just get installed? If so, mark the - module as "used". */ - if (sym->secidx == idx) - used = 1; - } - } - - return used; -} - -static void add_kernel_symbols(struct obj_file *f) -{ - struct external_module *m; - int i, nused = 0; - - /* Add module symbols first. */ - - for (i = 0, m = ext_modules; i < n_ext_modules; ++i, ++m) - if (m->nsyms - && add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms, - m->nsyms)) m->used = 1, ++nused; - - n_ext_modules_used = nused; - - /* And finally the symbols from the kernel proper. */ - - if (nksyms) - add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms); -} - -static char *get_modinfo_value(struct obj_file *f, const char *key) -{ - struct obj_section *sec; - char *p, *v, *n, *ep; - size_t klen = strlen(key); - - sec = obj_find_section(f, ".modinfo"); - if (sec == NULL) - return NULL; - p = sec->contents; - ep = p + sec->header.sh_size; - while (p < ep) { - v = strchr(p, '='); - n = strchr(p, '\0'); - if (v) { - if (p + klen == v && strncmp(p, key, klen) == 0) - return v + 1; - } else { - if (p + klen == n && strcmp(p, key) == 0) - return n; - } - p = n + 1; - } - - return NULL; -} - - -/*======================================================================*/ -/* Functions relating to module loading in pre 2.1 kernels. */ - -static int -old_process_module_arguments(struct obj_file *f, int argc, char **argv) -{ - while (argc > 0) { - char *p, *q; - struct obj_symbol *sym; - int *loc; - - p = *argv; - if ((q = strchr(p, '=')) == NULL) { - argc--; - continue; - } - *q++ = '\0'; - - sym = obj_find_symbol(f, p); - - /* Also check that the parameter was not resolved from the kernel. */ - if (sym == NULL || sym->secidx > SHN_HIRESERVE) { - error_msg("symbol for parameter %s not found", p); - return 0; - } - - loc = (int *) (f->sections[sym->secidx]->contents + sym->value); - - /* Do C quoting if we begin with a ". */ - if (*q == '"') { - char *r, *str; - - str = alloca(strlen(q)); - for (r = str, q++; *q != '"'; ++q, ++r) { - if (*q == '\0') { - error_msg("improperly terminated string argument for %s", p); - return 0; - } else if (*q == '\\') - switch (*++q) { - case 'a': - *r = '\a'; - break; - case 'b': - *r = '\b'; - break; - case 'e': - *r = '\033'; - break; - case 'f': - *r = '\f'; - break; - case 'n': - *r = '\n'; - break; - case 'r': - *r = '\r'; - break; - case 't': - *r = '\t'; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - { - int c = *q - '0'; - if (q[1] >= '0' && q[1] <= '7') { - c = (c * 8) + *++q - '0'; - if (q[1] >= '0' && q[1] <= '7') - c = (c * 8) + *++q - '0'; - } - *r = c; - } - break; - - default: - *r = *q; - break; - } else - *r = *q; - } - *r = '\0'; - obj_string_patch(f, sym->secidx, sym->value, str); - } else if (*q >= '0' && *q <= '9') { - do - *loc++ = strtoul(q, &q, 0); - while (*q++ == ','); - } else { - char *contents = f->sections[sym->secidx]->contents; - char *myloc = contents + sym->value; - char *r; /* To search for commas */ - - /* Break the string with comas */ - while ((r = strchr(q, ',')) != (char *) NULL) { - *r++ = '\0'; - obj_string_patch(f, sym->secidx, myloc - contents, q); - myloc += sizeof(char *); - q = r; - } - - /* last part */ - obj_string_patch(f, sym->secidx, myloc - contents, q); - } - - argc--, argv++; - } - - return 1; -} - -#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING -static int old_is_module_checksummed(struct obj_file *f) -{ - return obj_find_symbol(f, "Using_Versions") != NULL; -} -/* Get the module's kernel version in the canonical integer form. */ - -static int -old_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) -{ - struct obj_symbol *sym; - char *p, *q; - int a, b, c; - - sym = obj_find_symbol(f, "kernel_version"); - if (sym == NULL) - return -1; - - p = f->sections[sym->secidx]->contents + sym->value; - strncpy(str, p, STRVERSIONLEN); - - a = strtoul(p, &p, 10); - if (*p != '.') - return -1; - b = strtoul(p + 1, &p, 10); - if (*p != '.') - return -1; - c = strtoul(p + 1, &q, 10); - if (p + 1 == q) - return -1; - - return a << 16 | b << 8 | c; -} - -#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ - -#ifdef BB_FEATURE_OLD_MODULE_INTERFACE - -/* Fetch all the symbols and divvy them up as appropriate for the modules. */ - -static int old_get_kernel_symbols(const char *m_name) -{ - struct old_kernel_sym *ks, *k; - struct new_module_symbol *s; - struct external_module *mod; - int nks, nms, nmod, i; - - nks = get_kernel_syms(NULL); - if (nks <= 0) { - if (nks) - perror_msg("get_kernel_syms: %s", m_name); - else - error_msg("No kernel symbols"); - return 0; - } - - ks = k = xmalloc(nks * sizeof(*ks)); - - if (get_kernel_syms(ks) != nks) { - perror("inconsistency with get_kernel_syms -- is someone else " - "playing with modules?"); - free(ks); - return 0; - } - - /* Collect the module information. */ - - mod = NULL; - nmod = -1; - - while (k->name[0] == '#' && k->name[1]) { - struct old_kernel_sym *k2; - - /* Find out how many symbols this module has. */ - for (k2 = k + 1; k2->name[0] != '#'; ++k2) - continue; - nms = k2 - k - 1; - - mod = xrealloc(mod, (++nmod + 1) * sizeof(*mod)); - mod[nmod].name = k->name + 1; - mod[nmod].addr = k->value; - mod[nmod].used = 0; - mod[nmod].nsyms = nms; - mod[nmod].syms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL); - - for (i = 0, ++k; i < nms; ++i, ++s, ++k) { - s->name = (unsigned long) k->name; - s->value = k->value; - } - - k = k2; - } - - ext_modules = mod; - n_ext_modules = nmod + 1; - - /* Now collect the symbols for the kernel proper. */ - - if (k->name[0] == '#') - ++k; - - nksyms = nms = nks - (k - ks); - ksyms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL); - - for (i = 0; i < nms; ++i, ++s, ++k) { - s->name = (unsigned long) k->name; - s->value = k->value; - } - - return 1; -} - -/* Return the kernel symbol checksum version, or zero if not used. */ - -static int old_is_kernel_checksummed(void) -{ - /* Using_Versions is the first symbol. */ - if (nksyms > 0 - && strcmp((char *) ksyms[0].name, - "Using_Versions") == 0) return ksyms[0].value; - else - return 0; -} - - -static int old_create_mod_use_count(struct obj_file *f) -{ - struct obj_section *sec; - - sec = obj_create_alloced_section_first(f, ".moduse", sizeof(long), - sizeof(long)); - - obj_add_symbol(f, "mod_use_count_", -1, - ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0, - sizeof(long)); - - return 1; -} - -static int -old_init_module(const char *m_name, struct obj_file *f, - unsigned long m_size) -{ - char *image; - struct old_mod_routines routines; - struct old_symbol_table *symtab; - int ret; - - /* Create the symbol table */ - { - int nsyms = 0, strsize = 0, total; - - /* Size things first... */ - if (flag_export) { - int i; - for (i = 0; i < HASH_BUCKETS; ++i) { - struct obj_symbol *sym; - for (sym = f->symtab[i]; sym; sym = sym->next) - if (ELFW(ST_BIND) (sym->info) != STB_LOCAL - && sym->secidx <= SHN_HIRESERVE) - { - sym->ksymidx = nsyms++; - strsize += strlen(sym->name) + 1; - } - } - } - - total = (sizeof(struct old_symbol_table) - + nsyms * sizeof(struct old_module_symbol) - + n_ext_modules_used * sizeof(struct old_module_ref) - + strsize); - symtab = xmalloc(total); - symtab->size = total; - symtab->n_symbols = nsyms; - symtab->n_refs = n_ext_modules_used; - - if (flag_export && nsyms) { - struct old_module_symbol *ksym; - char *str; - int i; - - ksym = symtab->symbol; - str = ((char *) ksym + nsyms * sizeof(struct old_module_symbol) - + n_ext_modules_used * sizeof(struct old_module_ref)); - - for (i = 0; i < HASH_BUCKETS; ++i) { - struct obj_symbol *sym; - for (sym = f->symtab[i]; sym; sym = sym->next) - if (sym->ksymidx >= 0) { - ksym->addr = obj_symbol_final_value(f, sym); - ksym->name = - (unsigned long) str - (unsigned long) symtab; - - strcpy(str, sym->name); - str += strlen(sym->name) + 1; - ksym++; - } - } - } - - if (n_ext_modules_used) { - struct old_module_ref *ref; - int i; - - ref = (struct old_module_ref *) - ((char *) symtab->symbol + nsyms * sizeof(struct old_module_symbol)); - - for (i = 0; i < n_ext_modules; ++i) - if (ext_modules[i].used) - ref++->module = ext_modules[i].addr; - } - } - - /* Fill in routines. */ - - routines.init = - obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); - routines.cleanup = - obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module")); - - /* Whew! All of the initialization is complete. Collect the final - module image and give it to the kernel. */ - - image = xmalloc(m_size); - obj_create_image(f, image); - - /* image holds the complete relocated module, accounting correctly for - mod_use_count. However the old module kernel support assume that - it is receiving something which does not contain mod_use_count. */ - ret = old_sys_init_module(m_name, image + sizeof(long), - m_size | (flag_autoclean ? OLD_MOD_AUTOCLEAN - : 0), &routines, symtab); - if (ret) - perror_msg("init_module: %s", m_name); - - free(image); - free(symtab); - - return ret == 0; -} - -#else - -#define old_create_mod_use_count(x) TRUE -#define old_init_module(x, y, z) TRUE - -#endif /* BB_FEATURE_OLD_MODULE_INTERFACE */ - - - -/*======================================================================*/ -/* Functions relating to module loading after 2.1.18. */ - -static int -new_process_module_arguments(struct obj_file *f, int argc, char **argv) -{ - while (argc > 0) { - char *p, *q, *key; - struct obj_symbol *sym; - char *contents, *loc; - int min, max, n; - - p = *argv; - if ((q = strchr(p, '=')) == NULL) { - argc--; - continue; - } - - key = alloca(q - p + 6); - memcpy(key, "parm_", 5); - memcpy(key + 5, p, q - p); - key[q - p + 5] = 0; - - p = get_modinfo_value(f, key); - key += 5; - if (p == NULL) { - error_msg("invalid parameter %s", key); - return 0; - } - - sym = obj_find_symbol(f, key); - - /* Also check that the parameter was not resolved from the kernel. */ - if (sym == NULL || sym->secidx > SHN_HIRESERVE) { - error_msg("symbol for parameter %s not found", key); - return 0; - } - - if (isdigit(*p)) { - min = strtoul(p, &p, 10); - if (*p == '-') - max = strtoul(p + 1, &p, 10); - else - max = min; - } else - min = max = 1; - - contents = f->sections[sym->secidx]->contents; - loc = contents + sym->value; - n = (*++q != '\0'); - - while (1) { - if ((*p == 's') || (*p == 'c')) { - char *str; - - /* Do C quoting if we begin with a ", else slurp the lot. */ - if (*q == '"') { - char *r; - - str = alloca(strlen(q)); - for (r = str, q++; *q != '"'; ++q, ++r) { - if (*q == '\0') { - error_msg("improperly terminated string argument for %s", - key); - return 0; - } else if (*q == '\\') - switch (*++q) { - case 'a': - *r = '\a'; - break; - case 'b': - *r = '\b'; - break; - case 'e': - *r = '\033'; - break; - case 'f': - *r = '\f'; - break; - case 'n': - *r = '\n'; - break; - case 'r': - *r = '\r'; - break; - case 't': - *r = '\t'; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - { - int c = *q - '0'; - if (q[1] >= '0' && q[1] <= '7') { - c = (c * 8) + *++q - '0'; - if (q[1] >= '0' && q[1] <= '7') - c = (c * 8) + *++q - '0'; - } - *r = c; - } - break; - - default: - *r = *q; - break; - } else - *r = *q; - } - *r = '\0'; - ++q; - } else { - char *r; - - /* In this case, the string is not quoted. We will break - it using the coma (like for ints). If the user wants to - include comas in a string, he just has to quote it */ - - /* Search the next coma */ - r = strchr(q, ','); - - /* Found ? */ - if (r != (char *) NULL) { - /* Recopy the current field */ - str = alloca(r - q + 1); - memcpy(str, q, r - q); - - /* I don't know if it is usefull, as the previous case - doesn't null terminate the string ??? */ - str[r - q] = '\0'; - - /* Keep next fields */ - q = r; - } else { - /* last string */ - str = q; - q = ""; - } - } - - if (*p == 's') { - /* Normal string */ - obj_string_patch(f, sym->secidx, loc - contents, str); - loc += tgt_sizeof_char_p; - } else { - /* Array of chars (in fact, matrix !) */ - unsigned long charssize; /* size of each member */ - - /* Get the size of each member */ - /* Probably we should do that outside the loop ? */ - if (!isdigit(*(p + 1))) { - error_msg("parameter type 'c' for %s must be followed by" - " the maximum size", key); - return 0; - } - charssize = strtoul(p + 1, (char **) NULL, 10); - - /* Check length */ - if (strlen(str) >= charssize) { - error_msg("string too long for %s (max %ld)", key, - charssize - 1); - return 0; - } - - /* Copy to location */ - strcpy((char *) loc, str); - loc += charssize; - } - } else { - long v = strtoul(q, &q, 0); - switch (*p) { - case 'b': - *loc++ = v; - break; - case 'h': - *(short *) loc = v; - loc += tgt_sizeof_short; - break; - case 'i': - *(int *) loc = v; - loc += tgt_sizeof_int; - break; - case 'l': - *(long *) loc = v; - loc += tgt_sizeof_long; - break; - - default: - error_msg("unknown parameter type '%c' for %s", *p, key); - return 0; - } - } - - retry_end_of_value: - switch (*q) { - case '\0': - goto end_of_arg; - - case ' ': - case '\t': - case '\n': - case '\r': - ++q; - goto retry_end_of_value; - - case ',': - if (++n > max) { - error_msg("too many values for %s (max %d)", key, max); - return 0; - } - ++q; - break; - - default: - error_msg("invalid argument syntax for %s", key); - return 0; - } - } - - end_of_arg: - if (n < min) { - error_msg("too few values for %s (min %d)", key, min); - return 0; - } - - argc--, argv++; - } - - return 1; -} - -#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING -static int new_is_module_checksummed(struct obj_file *f) -{ - const char *p = get_modinfo_value(f, "using_checksums"); - if (p) - return atoi(p); - else - return 0; -} - -/* Get the module's kernel version in the canonical integer form. */ - -static int -new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) -{ - char *p, *q; - int a, b, c; - - p = get_modinfo_value(f, "kernel_version"); - if (p == NULL) - return -1; - strncpy(str, p, STRVERSIONLEN); - - a = strtoul(p, &p, 10); - if (*p != '.') - return -1; - b = strtoul(p + 1, &p, 10); - if (*p != '.') - return -1; - c = strtoul(p + 1, &q, 10); - if (p + 1 == q) - return -1; - - return a << 16 | b << 8 | c; -} - -#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ - - -#ifdef BB_FEATURE_NEW_MODULE_INTERFACE - -/* Fetch the loaded modules, and all currently exported symbols. */ - -static int new_get_kernel_symbols(void) -{ - char *module_names, *mn; - struct external_module *modules, *m; - struct new_module_symbol *syms, *s; - size_t ret, bufsize, nmod, nsyms, i, j; - - /* Collect the loaded modules. */ - - module_names = xmalloc(bufsize = 256); - retry_modules_load: - if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) { - if (errno == ENOSPC && bufsize < ret) { - module_names = xrealloc(module_names, bufsize = ret); - goto retry_modules_load; - } - perror_msg("QM_MODULES"); - return 0; - } - - n_ext_modules = nmod = ret; - - /* Collect the modules' symbols. */ - - if (nmod){ - ext_modules = modules = xmalloc(nmod * sizeof(*modules)); - memset(modules, 0, nmod * sizeof(*modules)); - for (i = 0, mn = module_names, m = modules; - i < nmod; ++i, ++m, mn += strlen(mn) + 1) { - struct new_module_info info; - - if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) { - if (errno == ENOENT) { - /* The module was removed out from underneath us. */ - continue; - } - perror_msg("query_module: QM_INFO: %s", mn); - return 0; - } - - syms = xmalloc(bufsize = 1024); - retry_mod_sym_load: - if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) { - switch (errno) { - case ENOSPC: - syms = xrealloc(syms, bufsize = ret); - goto retry_mod_sym_load; - case ENOENT: - /* The module was removed out from underneath us. */ - continue; - default: - perror_msg("query_module: QM_SYMBOLS: %s", mn); - return 0; - } - } - nsyms = ret; - - m->name = mn; - m->addr = info.addr; - m->nsyms = nsyms; - m->syms = syms; - - for (j = 0, s = syms; j < nsyms; ++j, ++s) { - s->name += (unsigned long) syms; - } - } - } - - /* Collect the kernel's symbols. */ - - syms = xmalloc(bufsize = 16 * 1024); - retry_kern_sym_load: - if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) { - if (errno == ENOSPC && bufsize < ret) { - syms = xrealloc(syms, bufsize = ret); - goto retry_kern_sym_load; - } - perror_msg("kernel: QM_SYMBOLS"); - return 0; - } - nksyms = nsyms = ret; - ksyms = syms; - - for (j = 0, s = syms; j < nsyms; ++j, ++s) { - s->name += (unsigned long) syms; - } - return 1; -} - - -/* Return the kernel symbol checksum version, or zero if not used. */ - -static int new_is_kernel_checksummed(void) -{ - struct new_module_symbol *s; - size_t i; - - /* Using_Versions is not the first symbol, but it should be in there. */ - - for (i = 0, s = ksyms; i < nksyms; ++i, ++s) - if (strcmp((char *) s->name, "Using_Versions") == 0) - return s->value; - - return 0; -} - - -static int new_create_this_module(struct obj_file *f, const char *m_name) -{ - struct obj_section *sec; - - sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long, - sizeof(struct new_module)); - memset(sec->contents, 0, sizeof(struct new_module)); - - obj_add_symbol(f, "__this_module", -1, - ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0, - sizeof(struct new_module)); - - obj_string_patch(f, sec->idx, offsetof(struct new_module, name), - m_name); - - return 1; -} - - -static int new_create_module_ksymtab(struct obj_file *f) -{ - struct obj_section *sec; - int i; - - /* We must always add the module references. */ - - if (n_ext_modules_used) { - struct new_module_ref *dep; - struct obj_symbol *tm; - - sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p, - (sizeof(struct new_module_ref) - * n_ext_modules_used)); - if (!sec) - return 0; - - tm = obj_find_symbol(f, "__this_module"); - dep = (struct new_module_ref *) sec->contents; - for (i = 0; i < n_ext_modules; ++i) - if (ext_modules[i].used) { - dep->dep = ext_modules[i].addr; - obj_symbol_patch(f, sec->idx, - (char *) &dep->ref - sec->contents, tm); - dep->next_ref = 0; - ++dep; - } - } - - if (flag_export && !obj_find_section(f, "__ksymtab")) { - size_t nsyms; - int *loaded; - - sec = - obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, - 0); - - /* We don't want to export symbols residing in sections that - aren't loaded. There are a number of these created so that - we make sure certain module options don't appear twice. */ - - loaded = alloca(sizeof(int) * (i = f->header.e_shnum)); - while (--i >= 0) - loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0; - - for (nsyms = i = 0; i < HASH_BUCKETS; ++i) { - struct obj_symbol *sym; - for (sym = f->symtab[i]; sym; sym = sym->next) - if (ELFW(ST_BIND) (sym->info) != STB_LOCAL - && sym->secidx <= SHN_HIRESERVE - && (sym->secidx >= SHN_LORESERVE - || loaded[sym->secidx])) { - ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p; - - obj_symbol_patch(f, sec->idx, ofs, sym); - obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, - sym->name); - - nsyms++; - } - } - - obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p); - } - - return 1; -} - - -static int -new_init_module(const char *m_name, struct obj_file *f, - unsigned long m_size) -{ - struct new_module *module; - struct obj_section *sec; - void *image; - int ret; - tgt_long m_addr; - - sec = obj_find_section(f, ".this"); - if (!sec || !sec->contents) { - perror_msg_and_die("corrupt module %s?",m_name); - } - module = (struct new_module *) sec->contents; - m_addr = sec->header.sh_addr; - - module->size_of_struct = sizeof(*module); - module->size = m_size; - module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0; - - sec = obj_find_section(f, "__ksymtab"); - if (sec && sec->header.sh_size) { - module->syms = sec->header.sh_addr; - module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p); - } - - if (n_ext_modules_used) { - sec = obj_find_section(f, ".kmodtab"); - module->deps = sec->header.sh_addr; - module->ndeps = n_ext_modules_used; - } - - module->init = - obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); - module->cleanup = - obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module")); - - sec = obj_find_section(f, "__ex_table"); - if (sec) { - module->ex_table_start = sec->header.sh_addr; - module->ex_table_end = sec->header.sh_addr + sec->header.sh_size; - } - - sec = obj_find_section(f, ".text.init"); - if (sec) { - module->runsize = sec->header.sh_addr - m_addr; - } - sec = obj_find_section(f, ".data.init"); - if (sec) { - if (!module->runsize || - module->runsize > sec->header.sh_addr - m_addr) - module->runsize = sec->header.sh_addr - m_addr; - } - sec = obj_find_section(f, ARCHDATA_SEC_NAME); - if (sec && sec->header.sh_size) { - module->archdata_start = (void*)sec->header.sh_addr; - module->archdata_end = module->archdata_start + sec->header.sh_size; - } - sec = obj_find_section(f, KALLSYMS_SEC_NAME); - if (sec && sec->header.sh_size) { - module->kallsyms_start = (void*)sec->header.sh_addr; - module->kallsyms_end = module->kallsyms_start + sec->header.sh_size; - } - - if (!arch_init_module(f, module)) - return 0; - - /* Whew! All of the initialization is complete. Collect the final - module image and give it to the kernel. */ - - image = xmalloc(m_size); - obj_create_image(f, image); - - ret = new_sys_init_module(m_name, (struct new_module *) image); - if (ret) - perror_msg("init_module: %s", m_name); - - free(image); - - return ret == 0; -} - -#else - -#define new_init_module(x, y, z) TRUE -#define new_create_this_module(x, y) 0 -#define new_create_module_ksymtab(x) -#define query_module(v, w, x, y, z) -1 - -#endif /* BB_FEATURE_NEW_MODULE_INTERFACE */ - - -/*======================================================================*/ - -static int -obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, - const char *string) -{ - struct obj_string_patch *p; - struct obj_section *strsec; - size_t len = strlen(string) + 1; - char *loc; - - p = xmalloc(sizeof(*p)); - p->next = f->string_patches; - p->reloc_secidx = secidx; - p->reloc_offset = offset; - f->string_patches = p; - - strsec = obj_find_section(f, ".kstrtab"); - if (strsec == NULL) { - strsec = obj_create_alloced_section(f, ".kstrtab", 1, len); - p->string_offset = 0; - loc = strsec->contents; - } else { - p->string_offset = strsec->header.sh_size; - loc = obj_extend_section(strsec, len); - } - memcpy(loc, string, len); - - return 1; -} - -static int -obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, - struct obj_symbol *sym) -{ - struct obj_symbol_patch *p; - - p = xmalloc(sizeof(*p)); - p->next = f->symbol_patches; - p->reloc_secidx = secidx; - p->reloc_offset = offset; - p->sym = sym; - f->symbol_patches = p; - - return 1; -} - -static int obj_check_undefineds(struct obj_file *f) -{ - unsigned long i; - int ret = 1; - - for (i = 0; i < HASH_BUCKETS; ++i) { - struct obj_symbol *sym; - for (sym = f->symtab[i]; sym; sym = sym->next) - if (sym->secidx == SHN_UNDEF) { - if (ELFW(ST_BIND) (sym->info) == STB_WEAK) { - sym->secidx = SHN_ABS; - sym->value = 0; - } else { - error_msg("unresolved symbol %s", sym->name); - ret = 0; - } - } - } - - return ret; -} - -static void obj_allocate_commons(struct obj_file *f) -{ - struct common_entry { - struct common_entry *next; - struct obj_symbol *sym; - } *common_head = NULL; - - unsigned long i; - - for (i = 0; i < HASH_BUCKETS; ++i) { - struct obj_symbol *sym; - for (sym = f->symtab[i]; sym; sym = sym->next) - if (sym->secidx == SHN_COMMON) { - /* Collect all COMMON symbols and sort them by size so as to - minimize space wasted by alignment requirements. */ - { - struct common_entry **p, *n; - for (p = &common_head; *p; p = &(*p)->next) - if (sym->size <= (*p)->sym->size) - break; - - n = alloca(sizeof(*n)); - n->next = *p; - n->sym = sym; - *p = n; - } - } - } - - for (i = 1; i < f->local_symtab_size; ++i) { - struct obj_symbol *sym = f->local_symtab[i]; - if (sym && sym->secidx == SHN_COMMON) { - struct common_entry **p, *n; - for (p = &common_head; *p; p = &(*p)->next) - if (sym == (*p)->sym) - break; - else if (sym->size < (*p)->sym->size) { - n = alloca(sizeof(*n)); - n->next = *p; - n->sym = sym; - *p = n; - break; - } - } - } - - if (common_head) { - /* Find the bss section. */ - for (i = 0; i < f->header.e_shnum; ++i) - if (f->sections[i]->header.sh_type == SHT_NOBITS) - break; - - /* If for some reason there hadn't been one, create one. */ - if (i == f->header.e_shnum) { - struct obj_section *sec; - - f->sections = xrealloc(f->sections, (i + 1) * sizeof(sec)); - f->sections[i] = sec = arch_new_section(); - f->header.e_shnum = i + 1; - - memset(sec, 0, sizeof(*sec)); - sec->header.sh_type = SHT_PROGBITS; - sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; - sec->name = ".bss"; - sec->idx = i; - } - - /* Allocate the COMMONS. */ - { - ElfW(Addr) bss_size = f->sections[i]->header.sh_size; - ElfW(Addr) max_align = f->sections[i]->header.sh_addralign; - struct common_entry *c; - - for (c = common_head; c; c = c->next) { - ElfW(Addr) align = c->sym->value; - - if (align > max_align) - max_align = align; - if (bss_size & (align - 1)) - bss_size = (bss_size | (align - 1)) + 1; - - c->sym->secidx = i; - c->sym->value = bss_size; - - bss_size += c->sym->size; - } - - f->sections[i]->header.sh_size = bss_size; - f->sections[i]->header.sh_addralign = max_align; - } - } - - /* For the sake of patch relocation and parameter initialization, - allocate zeroed data for NOBITS sections now. Note that after - this we cannot assume NOBITS are really empty. */ - for (i = 0; i < f->header.e_shnum; ++i) { - struct obj_section *s = f->sections[i]; - if (s->header.sh_type == SHT_NOBITS) { - if (s->header.sh_size != 0) - s->contents = memset(xmalloc(s->header.sh_size), - 0, s->header.sh_size); - else - s->contents = NULL; - - s->header.sh_type = SHT_PROGBITS; - } - } -} - -static unsigned long obj_load_size(struct obj_file *f) -{ - unsigned long dot = 0; - struct obj_section *sec; - - /* Finalize the positions of the sections relative to one another. */ - - for (sec = f->load_order; sec; sec = sec->load_next) { - ElfW(Addr) align; - - align = sec->header.sh_addralign; - if (align && (dot & (align - 1))) - dot = (dot | (align - 1)) + 1; - - sec->header.sh_addr = dot; - dot += sec->header.sh_size; - } - - return dot; -} - -static int obj_relocate(struct obj_file *f, ElfW(Addr) base) -{ - int i, n = f->header.e_shnum; - int ret = 1; - - /* Finalize the addresses of the sections. */ - - f->baseaddr = base; - for (i = 0; i < n; ++i) - f->sections[i]->header.sh_addr += base; - - /* And iterate over all of the relocations. */ - - for (i = 0; i < n; ++i) { - struct obj_section *relsec, *symsec, *targsec, *strsec; - ElfW(RelM) * rel, *relend; - ElfW(Sym) * symtab; - const char *strtab; - - relsec = f->sections[i]; - if (relsec->header.sh_type != SHT_RELM) - continue; - - symsec = f->sections[relsec->header.sh_link]; - targsec = f->sections[relsec->header.sh_info]; - strsec = f->sections[symsec->header.sh_link]; - - rel = (ElfW(RelM) *) relsec->contents; - relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM))); - symtab = (ElfW(Sym) *) symsec->contents; - strtab = (const char *) strsec->contents; - - for (; rel < relend; ++rel) { - ElfW(Addr) value = 0; - struct obj_symbol *intsym = NULL; - unsigned long symndx; - ElfW(Sym) * extsym = 0; - const char *errmsg; - - /* Attempt to find a value to use for this relocation. */ - - symndx = ELFW(R_SYM) (rel->r_info); - if (symndx) { - /* Note we've already checked for undefined symbols. */ - - extsym = &symtab[symndx]; - if (ELFW(ST_BIND) (extsym->st_info) == STB_LOCAL) { - /* Local symbols we look up in the local table to be sure - we get the one that is really intended. */ - intsym = f->local_symtab[symndx]; - } else { - /* Others we look up in the hash table. */ - const char *name; - if (extsym->st_name) - name = strtab + extsym->st_name; - else - name = f->sections[extsym->st_shndx]->name; - intsym = obj_find_symbol(f, name); - } - - value = obj_symbol_final_value(f, intsym); - intsym->referenced = 1; - } -#if SHT_RELM == SHT_RELA -#if defined(__alpha__) && defined(AXP_BROKEN_GAS) - /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9. */ - if (!extsym || !extsym->st_name || - ELFW(ST_BIND) (extsym->st_info) != STB_LOCAL) -#endif - value += rel->r_addend; -#endif - - /* Do it! */ - switch (arch_apply_relocation - (f, targsec, symsec, intsym, rel, value)) { - case obj_reloc_ok: - break; - - case obj_reloc_overflow: - errmsg = "Relocation overflow"; - goto bad_reloc; - case obj_reloc_dangerous: - errmsg = "Dangerous relocation"; - goto bad_reloc; - case obj_reloc_unhandled: - errmsg = "Unhandled relocation"; - bad_reloc: - if (extsym) { - error_msg("%s of type %ld for %s", errmsg, - (long) ELFW(R_TYPE) (rel->r_info), - strtab + extsym->st_name); - } else { - error_msg("%s of type %ld", errmsg, - (long) ELFW(R_TYPE) (rel->r_info)); - } - ret = 0; - break; - } - } - } - - /* Finally, take care of the patches. */ - - if (f->string_patches) { - struct obj_string_patch *p; - struct obj_section *strsec; - ElfW(Addr) strsec_base; - strsec = obj_find_section(f, ".kstrtab"); - strsec_base = strsec->header.sh_addr; - - for (p = f->string_patches; p; p = p->next) { - struct obj_section *targsec = f->sections[p->reloc_secidx]; - *(ElfW(Addr) *) (targsec->contents + p->reloc_offset) - = strsec_base + p->string_offset; - } - } - - if (f->symbol_patches) { - struct obj_symbol_patch *p; - - for (p = f->symbol_patches; p; p = p->next) { - struct obj_section *targsec = f->sections[p->reloc_secidx]; - *(ElfW(Addr) *) (targsec->contents + p->reloc_offset) - = obj_symbol_final_value(f, p->sym); - } - } - - return ret; -} - -static int obj_create_image(struct obj_file *f, char *image) -{ - struct obj_section *sec; - ElfW(Addr) base = f->baseaddr; - - for (sec = f->load_order; sec; sec = sec->load_next) { - char *secimg; - - if (sec->contents == 0 || sec->header.sh_size == 0) - continue; - - secimg = image + (sec->header.sh_addr - base); - - /* Note that we allocated data for NOBITS sections earlier. */ - memcpy(secimg, sec->contents, sec->header.sh_size); - } - - return 1; -} - -/*======================================================================*/ - -static struct obj_file *obj_load(FILE * fp, int loadprogbits) -{ - struct obj_file *f; - ElfW(Shdr) * section_headers; - int shnum, i; - char *shstrtab; - - /* Read the file header. */ - - f = arch_new_file(); - memset(f, 0, sizeof(*f)); - f->symbol_cmp = strcmp; - f->symbol_hash = obj_elf_hash; - f->load_order_search_start = &f->load_order; - - fseek(fp, 0, SEEK_SET); - if (fread(&f->header, sizeof(f->header), 1, fp) != 1) { - perror_msg("error reading ELF header"); - return NULL; - } - - if (f->header.e_ident[EI_MAG0] != ELFMAG0 - || f->header.e_ident[EI_MAG1] != ELFMAG1 - || f->header.e_ident[EI_MAG2] != ELFMAG2 - || f->header.e_ident[EI_MAG3] != ELFMAG3) { - error_msg("not an ELF file"); - return NULL; - } - if (f->header.e_ident[EI_CLASS] != ELFCLASSM - || f->header.e_ident[EI_DATA] != ELFDATAM - || f->header.e_ident[EI_VERSION] != EV_CURRENT - || !MATCH_MACHINE(f->header.e_machine)) { - error_msg("ELF file not for this architecture"); - return NULL; - } - if (f->header.e_type != ET_REL) { - error_msg("ELF file not a relocatable object"); - return NULL; - } - - /* Read the section headers. */ - - if (f->header.e_shentsize != sizeof(ElfW(Shdr))) { - error_msg("section header size mismatch: %lu != %lu", - (unsigned long) f->header.e_shentsize, - (unsigned long) sizeof(ElfW(Shdr))); - return NULL; - } - - shnum = f->header.e_shnum; - f->sections = xmalloc(sizeof(struct obj_section *) * shnum); - memset(f->sections, 0, sizeof(struct obj_section *) * shnum); - - section_headers = alloca(sizeof(ElfW(Shdr)) * shnum); - fseek(fp, f->header.e_shoff, SEEK_SET); - if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) { - perror_msg("error reading ELF section headers"); - return NULL; - } - - /* Read the section data. */ - - for (i = 0; i < shnum; ++i) { - struct obj_section *sec; - - f->sections[i] = sec = arch_new_section(); - memset(sec, 0, sizeof(*sec)); - - sec->header = section_headers[i]; - sec->idx = i; - - if(sec->header.sh_size) switch (sec->header.sh_type) { - case SHT_NULL: - case SHT_NOTE: - case SHT_NOBITS: - /* ignore */ - break; - - case SHT_PROGBITS: -#if LOADBITS - if (!loadprogbits) { - sec->contents = NULL; - break; - } -#endif - case SHT_SYMTAB: - case SHT_STRTAB: - case SHT_RELM: - if (sec->header.sh_size > 0) { - sec->contents = xmalloc(sec->header.sh_size); - fseek(fp, sec->header.sh_offset, SEEK_SET); - if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) { - perror_msg("error reading ELF section data"); - return NULL; - } - } else { - sec->contents = NULL; - } - break; - -#if SHT_RELM == SHT_REL - case SHT_RELA: - error_msg("RELA relocations not supported on this architecture"); - return NULL; -#else - case SHT_REL: - error_msg("REL relocations not supported on this architecture"); - return NULL; -#endif - - default: - if (sec->header.sh_type >= SHT_LOPROC) { - /* Assume processor specific section types are debug - info and can safely be ignored. If this is ever not - the case (Hello MIPS?), don't put ifdefs here but - create an arch_load_proc_section(). */ - break; - } - - error_msg("can't handle sections of type %ld", - (long) sec->header.sh_type); - return NULL; - } - } - - /* Do what sort of interpretation as needed by each section. */ - - shstrtab = f->sections[f->header.e_shstrndx]->contents; - - for (i = 0; i < shnum; ++i) { - struct obj_section *sec = f->sections[i]; - sec->name = shstrtab + sec->header.sh_name; - } - - for (i = 0; i < shnum; ++i) { - struct obj_section *sec = f->sections[i]; - - /* .modinfo should be contents only but gcc has no attribute for that. - * The kernel may have marked .modinfo as ALLOC, ignore this bit. - */ - if (strcmp(sec->name, ".modinfo") == 0) - sec->header.sh_flags &= ~SHF_ALLOC; - - if (sec->header.sh_flags & SHF_ALLOC) - obj_insert_section_load_order(f, sec); - - switch (sec->header.sh_type) { - case SHT_SYMTAB: - { - unsigned long nsym, j; - char *strtab; - ElfW(Sym) * sym; - - if (sec->header.sh_entsize != sizeof(ElfW(Sym))) { - error_msg("symbol size mismatch: %lu != %lu", - (unsigned long) sec->header.sh_entsize, - (unsigned long) sizeof(ElfW(Sym))); - return NULL; - } - - nsym = sec->header.sh_size / sizeof(ElfW(Sym)); - strtab = f->sections[sec->header.sh_link]->contents; - sym = (ElfW(Sym) *) sec->contents; - - /* Allocate space for a table of local symbols. */ - j = f->local_symtab_size = sec->header.sh_info; - f->local_symtab = xcalloc(j, sizeof(struct obj_symbol *)); - - /* Insert all symbols into the hash table. */ - for (j = 1, ++sym; j < nsym; ++j, ++sym) { - const char *name; - if (sym->st_name) - name = strtab + sym->st_name; - else - name = f->sections[sym->st_shndx]->name; - - obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx, - sym->st_value, sym->st_size); - } - } - break; - - case SHT_RELM: - if (sec->header.sh_entsize != sizeof(ElfW(RelM))) { - error_msg("relocation entry size mismatch: %lu != %lu", - (unsigned long) sec->header.sh_entsize, - (unsigned long) sizeof(ElfW(RelM))); - return NULL; - } - break; - /* XXX Relocation code from modutils-2.3.19 is not here. - * Why? That's about 20 lines of code from obj/obj_load.c, - * which gets done in a second pass through the sections. - * This BusyBox insmod does similar work in obj_relocate(). */ - } - } - - return f; -} - -#ifdef BB_FEATURE_INSMOD_LOADINKMEM -/* - * load the unloaded sections directly into the memory allocated by - * kernel for the module - */ - -static int obj_load_progbits(FILE * fp, struct obj_file* f, char* imagebase) -{ - ElfW(Addr) base = f->baseaddr; - struct obj_section* sec; - - for (sec = f->load_order; sec; sec = sec->load_next) { - - /* section already loaded? */ - if (sec->contents != NULL) - continue; - - if (sec->header.sh_size == 0) - continue; - - sec->contents = imagebase + (sec->header.sh_addr - base); - fseek(fp, sec->header.sh_offset, SEEK_SET); - if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) { - error_msg("error reading ELF section data: %s\n", strerror(errno)); - return 0; - } - - } - return 1; -} -#endif - -static void hide_special_symbols(struct obj_file *f) -{ - static const char *const specials[] = { - "cleanup_module", - "init_module", - "kernel_version", - NULL - }; - - struct obj_symbol *sym; - const char *const *p; - - for (p = specials; *p; ++p) - if ((sym = obj_find_symbol(f, *p)) != NULL) - sym->info = - ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info)); -} - - - -extern int insmod_main( int argc, char **argv) -{ - int opt; - int k_crcs; - int k_new_syscalls; - int len; - char *tmp; - unsigned long m_size; - ElfW(Addr) m_addr; - FILE *fp; - struct obj_file *f; - struct stat st; - char m_name[FILENAME_MAX + 1] = "\0"; - int exit_status = EXIT_FAILURE; - int m_has_modinfo; -#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING - struct utsname uts_info; - char m_strversion[STRVERSIONLEN]; - int m_version; - int m_crcs; -#endif - - /* Parse any options */ - while ((opt = getopt(argc, argv, "fkvxLo:")) > 0) { - switch (opt) { - case 'f': /* force loading */ - flag_force_load = 1; - break; - case 'k': /* module loaded by kerneld, auto-cleanable */ - flag_autoclean = 1; - break; - case 'v': /* verbose output */ - flag_verbose = 1; - break; - case 'x': /* do not export externs */ - flag_export = 0; - break; - case 'o': /* name the output module */ - strncpy(m_name, optarg, FILENAME_MAX); - break; - case 'L': /* Stub warning */ - /* This is needed for compatibility with modprobe. - * In theory, this does locking, but we don't do - * that. So be careful and plan your life around not - * loading the same module 50 times concurrently. */ - break; - default: - show_usage(); - } - } - - if (argv[optind] == NULL) { - show_usage(); - } - - /* Grab the module name */ - if ((tmp = strrchr(argv[optind], '/')) != NULL) { - tmp++; - } else { - tmp = argv[optind]; - } - len = strlen(tmp); - - if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') - len -= 2; - memcpy(m_fullName, tmp, len); - m_fullName[len]='\0'; - if (*m_name == '\0') { - strcpy(m_name, m_fullName); - } - strcat(m_fullName, ".o"); - - /* Get a filedesc for the module. Check we we have a complete path */ - if (stat(argv[optind], &st) < 0 || !S_ISREG(st.st_mode) || - (fp = fopen(argv[optind], "r")) == NULL) { - struct utsname myuname; - - /* Hmm. Could not open it. First search under /lib/modules/`uname -r`, - * but do not error out yet if we fail to find it... */ - if (uname(&myuname) == 0) { - char module_dir[FILENAME_MAX]; - char real_module_dir[FILENAME_MAX]; - snprintf (module_dir, sizeof(module_dir), "%s/%s", - _PATH_MODULES, myuname.release); - /* Jump through hoops in case /lib/modules/`uname -r` - * is a symlink. We do not want recursive_action to - * follow symlinks, but we do want to follow the - * /lib/modules/`uname -r` dir, So resolve it ourselves - * if it is a link... */ - if (realpath (module_dir, real_module_dir) == NULL) - strcpy(real_module_dir, module_dir); - recursive_action(real_module_dir, TRUE, FALSE, FALSE, - check_module_name_match, 0, m_fullName); - } - - /* Check if we have found anything yet */ - if (m_filename[0] == '\0' || ((fp = fopen(m_filename, "r")) == NULL)) - { - char module_dir[FILENAME_MAX]; - if (realpath (_PATH_MODULES, module_dir) == NULL) - strcpy(module_dir, _PATH_MODULES); - /* No module found under /lib/modules/`uname -r`, this - * time cast the net a bit wider. Search /lib/modules/ */ - if (recursive_action(module_dir, TRUE, FALSE, FALSE, - check_module_name_match, 0, m_fullName) == FALSE) - { - if (m_filename[0] == '\0' - || ((fp = fopen(m_filename, "r")) == NULL)) - { - error_msg("%s: no module by that name found", m_fullName); - return EXIT_FAILURE; - } - } else - error_msg_and_die("%s: no module by that name found", m_fullName); - } - } else - safe_strncpy(m_filename, argv[optind], sizeof(m_filename)); - - printf("Using %s\n", m_filename); - - if ((f = obj_load(fp, LOADBITS)) == NULL) - perror_msg_and_die("Could not load the module"); - - if (get_modinfo_value(f, "kernel_version") == NULL) - m_has_modinfo = 0; - else - m_has_modinfo = 1; - -#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING - /* Version correspondence? */ - - if (uname(&uts_info) < 0) - uts_info.release[0] = '\0'; - if (m_has_modinfo) { - m_version = new_get_module_version(f, m_strversion); - } else { - m_version = old_get_module_version(f, m_strversion); - if (m_version == -1) { - error_msg("couldn't find the kernel version the module was " - "compiled for"); - goto out; - } - } - - if (strncmp(uts_info.release, m_strversion, STRVERSIONLEN) != 0) { - if (flag_force_load) { - error_msg("Warning: kernel-module version mismatch\n" - "\t%s was compiled for kernel version %s\n" - "\twhile this kernel is version %s", - m_filename, m_strversion, uts_info.release); - } else { - error_msg("kernel-module version mismatch\n" - "\t%s was compiled for kernel version %s\n" - "\twhile this kernel is version %s.", - m_filename, m_strversion, uts_info.release); - goto out; - } - } - k_crcs = 0; -#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ - - k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL); - - if (k_new_syscalls) { -#ifdef BB_FEATURE_NEW_MODULE_INTERFACE - if (!new_get_kernel_symbols()) - goto out; - k_crcs = new_is_kernel_checksummed(); -#else - error_msg("Not configured to support new kernels"); - goto out; -#endif - } else { -#ifdef BB_FEATURE_OLD_MODULE_INTERFACE - if (!old_get_kernel_symbols(m_name)) - goto out; - k_crcs = old_is_kernel_checksummed(); -#else - error_msg("Not configured to support old kernels"); - goto out; -#endif - } - -#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING - if (m_has_modinfo) - m_crcs = new_is_module_checksummed(f); - else - m_crcs = old_is_module_checksummed(f); - - if (m_crcs != k_crcs) - obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash); -#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ - - /* Let the module know about the kernel symbols. */ - add_kernel_symbols(f); - - /* Allocate common symbols, symbol tables, and string tables. */ - - if (k_new_syscalls - ? !new_create_this_module(f, m_name) - : !old_create_mod_use_count(f)) - { - goto out; - } - - if (!obj_check_undefineds(f)) { - goto out; - } - obj_allocate_commons(f); - - /* done with the module name, on to the optional var=value arguments */ - ++optind; - - if (optind < argc) { - if (m_has_modinfo - ? !new_process_module_arguments(f, argc - optind, argv + optind) - : !old_process_module_arguments(f, argc - optind, argv + optind)) - { - goto out; - } - } - - arch_create_got(f); - hide_special_symbols(f); - - if (k_new_syscalls) - new_create_module_ksymtab(f); - - /* Find current size of the module */ - m_size = obj_load_size(f); - - - m_addr = create_module(m_name, m_size); - if (m_addr==-1) switch (errno) { - case EEXIST: - error_msg("A module named %s already exists", m_name); - goto out; - case ENOMEM: - error_msg("Can't allocate kernel memory for module; needed %lu bytes", - m_size); - goto out; - default: - perror_msg("create_module: %s", m_name); - goto out; - } - -#if !LOADBITS - /* - * the PROGBITS section was not loaded by the obj_load - * now we can load them directly into the kernel memory - */ - if (!obj_load_progbits(fp, f, (char*)m_addr)) { - delete_module(m_name); - goto out; - } -#endif - - if (!obj_relocate(f, m_addr)) { - delete_module(m_name); - goto out; - } - - if (k_new_syscalls - ? !new_init_module(m_name, f, m_size) - : !old_init_module(m_name, f, m_size)) - { - delete_module(m_name); - goto out; - } - - exit_status = EXIT_SUCCESS; - -out: - fclose(fp); - return(exit_status); -} diff --git a/busybox/install.sh b/busybox/install.sh deleted file mode 100755 index d163a2ef8..000000000 --- a/busybox/install.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh - -export LC_ALL=POSIX -export LC_CTYPE=POSIX - -prefix=$1 -if [ "$prefix" = "" ]; then - echo "No installation directory, aborting." - exit 1; -fi -if [ "$2" = "--hardlinks" ]; then - linkopts="-f" -else - linkopts="-fs" -fi -h=`sort busybox.links | uniq` - - -rm -f $prefix/bin/busybox || exit 1 -mkdir -p $prefix/bin || exit 1 -install -m 755 busybox $prefix/bin/busybox || exit 1 - -for i in $h ; do - appdir=`dirname $i` - mkdir -p $prefix/$appdir || exit 1 - if [ "$2" = "--hardlinks" ]; then - bb_path="$prefix/bin/busybox" - else - case "$appdir" in - /) - bb_path="bin/busybox" - ;; - /bin) - bb_path="busybox" - ;; - /sbin) - bb_path="../bin/busybox" - ;; - /usr/bin|/usr/sbin) - bb_path="../../bin/busybox" - ;; - *) - echo "Unknown installation directory: $appdir" - exit 1 - ;; - esac - fi - echo " $prefix$i -> $bb_path" - ln $linkopts $bb_path $prefix$i || exit 1 -done - -exit 0 diff --git a/busybox/kill.c b/busybox/kill.c deleted file mode 100644 index 3884ebdf4..000000000 --- a/busybox/kill.c +++ /dev/null @@ -1,142 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini kill/killall implementation for busybox - * - * 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 - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -static const int KILL = 0; -static const int KILLALL = 1; - - -extern int kill_main(int argc, char **argv) -{ - int whichApp, sig = SIGTERM; - const char *name; - -#ifdef BB_KILLALL - /* Figure out what we are trying to do here */ - whichApp = (strcmp(applet_name, "killall") == 0)? KILLALL : KILL; -#else - whichApp = KILL; -#endif - - argc--; - argv++; - /* Parse any options */ - if (argc < 1) - show_usage(); - - while (argc > 0 && **argv == '-') { - while (*++(*argv)) { - switch (**argv) { - case 'l': - if(argc>1) { - for(argv++; *argv; argv++) { - name = u_signal_names(*argv, &sig, -1); - if(name!=NULL) - printf("%s\n", name); - } - } else { - int col = 0; - for(sig=1; sig < NSIG; sig++) { - name = u_signal_names(0, &sig, 1); - if(name==NULL) /* unnamed */ - continue; - col += printf("%2d) %-16s", sig, name); - if (col > 60) { - printf("\n"); - col = 0; - } - } - printf("\n"); - } - return EXIT_SUCCESS; - case '-': - show_usage(); - default: - name = u_signal_names(*argv, &sig, 0); - if(name==NULL) - error_msg_and_die( "bad signal name: %s", *argv); - argc--; - argv++; - goto do_it_now; - } - argc--; - argv++; - } - } - - do_it_now: - - if (whichApp == KILL) { - /* Looks like they want to do a kill. Do that */ - while (--argc >= 0) { - int pid; - - if (!isdigit(**argv)) - perror_msg_and_die( "Bad PID"); - pid = strtol(*argv, NULL, 0); - if (kill(pid, sig) != 0) - perror_msg_and_die( "Could not kill pid '%d'", pid); - argv++; - } - } -#ifdef BB_KILLALL - else { - int all_found = TRUE; - pid_t myPid=getpid(); - /* Looks like they want to do a killall. Do that */ - while (--argc >= 0) { - pid_t* pidList; - - pidList = find_pid_by_name( *argv); - if (!pidList || *pidList<=0) { - all_found = FALSE; - error_msg_and_die( "%s: no process killed", *argv); - } - - for(; pidList && *pidList!=0; pidList++) { - if (*pidList==myPid) - continue; - if (kill(*pidList, sig) != 0) - perror_msg_and_die( "Could not kill pid '%d'", *pidList); - } - /* Note that we don't bother to free the memory - * allocated in find_pid_by_name(). It will be freed - * upon exit, so we can save a byte or two */ - argv++; - } - if (all_found == FALSE) - return EXIT_FAILURE; - } -#endif - - return EXIT_SUCCESS; -} diff --git a/busybox/klogd.c b/busybox/klogd.c deleted file mode 100644 index d7b54e9c8..000000000 --- a/busybox/klogd.c +++ /dev/null @@ -1,153 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini klogd implementation for busybox - * - * Copyright (C) 2001 by Gennady Feldman . - * Changes: Made this a standalone busybox module which uses standalone - * syslog() client interface. - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * - * Copyright (C) 2000 by Karl M. Hegbloom - * - * "circular buffer" Copyright (C) 2000 by Gennady Feldman - * - * Maintainer: Gennady Feldman as of Mar 12, 2001 - * - * 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 /* for our signal() handlers */ -#include /* strncpy() */ -#include /* errno and friends */ -#include -#include -#include - -#if __GNU_LIBRARY__ < 5 -# ifdef __alpha__ -# define klogctl syslog -# endif -#else -# include -#endif - -#include "busybox.h" - -static void klogd_signal(int sig) -{ - klogctl(7, NULL, 0); - klogctl(0, 0, 0); - //logMessage(0, "Kernel log daemon exiting."); - syslog_msg(LOG_DAEMON, 0, "Kernel log daemon exiting."); - exit(TRUE); -} - -static void doKlogd (void) __attribute__ ((noreturn)); -static void doKlogd (void) -{ - int priority = LOG_INFO; - char log_buffer[4096]; - int i, n, lastc; - char *start; - - /* Set up sig handlers */ - signal(SIGINT, klogd_signal); - signal(SIGKILL, klogd_signal); - signal(SIGTERM, klogd_signal); - signal(SIGHUP, SIG_IGN); - - /* "Open the log. Currently a NOP." */ - klogctl(1, NULL, 0); - - syslog_msg(LOG_DAEMON, 0, "klogd started: " BB_BANNER); - - while (1) { - /* Use kernel syscalls */ - memset(log_buffer, '\0', sizeof(log_buffer)); - n = klogctl(2, log_buffer, sizeof(log_buffer)); - if (n < 0) { - char message[80]; - - if (errno == EINTR) - continue; - snprintf(message, 79, "klogd: Error return from sys_sycall: %d - %s.\n", - errno, strerror(errno)); - syslog_msg(LOG_DAEMON, LOG_SYSLOG | LOG_ERR, message); - exit(1); - } - - /* klogctl buffer parsing modelled after code in dmesg.c */ - start=&log_buffer[0]; - lastc='\0'; - for (i=0; i') i++; - start = &log_buffer[i]; - } - if (log_buffer[i] == '\n') { - log_buffer[i] = '\0'; /* zero terminate this message */ - syslog_msg(LOG_DAEMON, LOG_KERN | priority, start); - start = &log_buffer[i+1]; - priority = LOG_INFO; - } - lastc = log_buffer[i]; - } - } -} - -extern int klogd_main(int argc, char **argv) -{ - /* no options, no getopt */ - int opt; - int doFork = TRUE; - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "n")) > 0) { - switch (opt) { - case 'n': - doFork = FALSE; - break; - default: - show_usage(); - } - } - - if (doFork == TRUE) { - if (daemon(0, 1) < 0) - perror_msg_and_die("daemon"); - } - doKlogd(); - - return EXIT_SUCCESS; -} - -/* -Local Variables -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/lash.c b/busybox/lash.c deleted file mode 100644 index b3f7cb6a8..000000000 --- a/busybox/lash.c +++ /dev/null @@ -1,1638 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * lash -- the BusyBox Lame-Ass SHell - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * - * Based in part on ladsh.c by Michael K. Johnson and Erik W. Troan, which is - * under the following liberal license: "We have placed this source code in the - * public domain. Use it in any project, free or commercial." - * - * 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 - * - */ - -/* This shell's parsing engine is officially at a dead-end. - * Future work shell work should be done using hush.c - */ - -//For debugging/development on the shell only... -//#define DEBUG_SHELL - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" -#include "cmdedit.h" - -#ifdef BB_LOCALE_SUPPORT -#include -#endif - -#include -#define expand_t glob_t - - -static const int MAX_READ = 128; /* size of input buffer for `read' builtin */ -#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" - - -enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE, - REDIRECT_APPEND -}; - -static const unsigned int DEFAULT_CONTEXT=0x1; -static const unsigned int IF_TRUE_CONTEXT=0x2; -static const unsigned int IF_FALSE_CONTEXT=0x4; -static const unsigned int THEN_EXP_CONTEXT=0x8; -static const unsigned int ELSE_EXP_CONTEXT=0x10; - - -struct jobset { - struct job *head; /* head of list of running jobs */ - struct job *fg; /* current foreground job */ -}; - -struct redir_struct { - enum redir_type type; /* type of redirection */ - int fd; /* file descriptor being redirected */ - char *filename; /* file to redirect fd to */ -}; - -struct child_prog { - pid_t pid; /* 0 if exited */ - char **argv; /* program name and arguments */ - int num_redirects; /* elements in redirection array */ - struct redir_struct *redirects; /* I/O redirects */ - int is_stopped; /* is the program currently running? */ - struct job *family; /* pointer back to the child's parent job */ -}; - -struct job { - int jobid; /* job number */ - int num_progs; /* total number of programs in job */ - int running_progs; /* number of programs running */ - char *text; /* name of job */ - char *cmdbuf; /* buffer various argv's point into */ - pid_t pgrp; /* process group ID for the job */ - struct child_prog *progs; /* array of programs in job */ - struct job *next; /* to track background commands */ - int stopped_progs; /* number of programs alive, but stopped */ - unsigned int job_context; /* bitmask defining current context */ - struct jobset *job_list; -}; - -struct built_in_command { - char *cmd; /* name */ - char *descr; /* description */ - int (*function) (struct child_prog *); /* function ptr */ -}; - -struct close_me { - int fd; - struct close_me *next; -}; - -/* function prototypes for builtins */ -static int builtin_cd(struct child_prog *cmd); -static int builtin_exec(struct child_prog *cmd); -static int builtin_exit(struct child_prog *cmd); -static int builtin_fg_bg(struct child_prog *cmd); -static int builtin_help(struct child_prog *cmd); -static int builtin_jobs(struct child_prog *dummy); -static int builtin_pwd(struct child_prog *dummy); -static int builtin_export(struct child_prog *cmd); -static int builtin_source(struct child_prog *cmd); -static int builtin_unset(struct child_prog *cmd); -static int builtin_read(struct child_prog *cmd); - - -/* function prototypes for shell stuff */ -static void mark_open(int fd); -static void mark_closed(int fd); -static void close_all(void); -static void checkjobs(struct jobset *job_list); -static void remove_job(struct jobset *j_list, struct job *job); -static int get_command(FILE * source, char *command); -static int parse_command(char **command_ptr, struct job *job, int *inbg); -static int run_command(struct job *newjob, int inbg, int outpipe[2]); -static int pseudo_exec(struct child_prog *cmd) __attribute__ ((noreturn)); -static int busy_loop(FILE * input); - - -/* Table of built-in functions (these are non-forking builtins, meaning they - * can change global variables in the parent shell process but they will not - * work with pipes and redirects; 'unset foo | whatever' will not work) */ -static struct built_in_command bltins[] = { - {"bg", "Resume a job in the background", builtin_fg_bg}, - {"cd", "Change working directory", builtin_cd}, - {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec}, - {"exit", "Exit from shell()", builtin_exit}, - {"fg", "Bring job into the foreground", builtin_fg_bg}, - {"jobs", "Lists the active jobs", builtin_jobs}, - {"export", "Set environment variable", builtin_export}, - {"unset", "Unset environment variable", builtin_unset}, - {"read", "Input environment variable", builtin_read}, - {".", "Source-in and run commands in a file", builtin_source}, - /* to do: add ulimit */ - {NULL, NULL, NULL} -}; - -/* Table of forking built-in functions (things that fork cannot change global - * variables in the parent process, such as the current working directory) */ -static struct built_in_command bltins_forking[] = { - {"pwd", "Print current directory", builtin_pwd}, - {"help", "List shell built-in commands", builtin_help}, - {NULL, NULL, NULL} -}; - - -static int shell_context; /* Type prompt trigger (PS1 or PS2) */ - - -/* Globals that are static to this file */ -static const char *cwd; -static char *local_pending_command = NULL; -static struct jobset job_list = { NULL, NULL }; -static int argc; -static char **argv; -static struct close_me *close_me_head; -static int last_return_code; -static int last_bg_pid; -static unsigned int last_jobid; -static int shell_terminal; -static pid_t shell_pgrp; -static char *PS1; -static char *PS2 = "> "; - - -#ifdef DEBUG_SHELL -static inline void debug_printf(const char *format, ...) -{ - va_list args; - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); -} -#else -static inline void debug_printf(const char *format, ...) { } -#endif - -/* - Most builtins need access to the struct child_prog that has - their arguments, previously coded as cmd->progs[0]. That coding - can exhibit a bug, if the builtin is not the first command in - a pipeline: "echo foo | exec sort" will attempt to exec foo. - -builtin previous use notes ------- ----------------- --------- -cd cmd->progs[0] -exec cmd->progs[0] squashed bug: didn't look for applets or forking builtins -exit cmd->progs[0] -fg_bg cmd->progs[0], job_list->head, job_list->fg -help 0 -jobs job_list->head -pwd 0 -export cmd->progs[0] -source cmd->progs[0] -unset cmd->progs[0] -read cmd->progs[0] - -I added "struct job *family;" to struct child_prog, -and switched API to builtin_foo(struct child_prog *child); -So cmd->text becomes child->family->text - cmd->job_context becomes child->family->job_context - cmd->progs[0] becomes *child - job_list becomes child->family->job_list - */ - -/* built-in 'cd ' handler */ -static int builtin_cd(struct child_prog *child) -{ - char *newdir; - - if (child->argv[1] == NULL) - newdir = getenv("HOME"); - else - newdir = child->argv[1]; - if (chdir(newdir)) { - printf("cd: %s: %m\n", newdir); - return EXIT_FAILURE; - } - cwd = xgetcwd((char *)cwd); - if (!cwd) - cwd = unknown; - return EXIT_SUCCESS; -} - -/* built-in 'exec' handler */ -static int builtin_exec(struct child_prog *child) -{ - if (child->argv[1] == NULL) - return EXIT_SUCCESS; /* Really? */ - child->argv++; - close_all(); - pseudo_exec(child); - /* never returns */ -} - -/* built-in 'exit' handler */ -static int builtin_exit(struct child_prog *child) -{ - if (child->argv[1] == NULL) - exit(EXIT_SUCCESS); - - exit (atoi(child->argv[1])); -} - -/* built-in 'fg' and 'bg' handler */ -static int builtin_fg_bg(struct child_prog *child) -{ - int i, jobnum; - struct job *job=NULL; - - /* If they gave us no args, assume they want the last backgrounded task */ - if (!child->argv[1]) { - for (job = child->family->job_list->head; job; job = job->next) { - if (job->jobid == last_jobid) { - break; - } - } - if (!job) { - error_msg("%s: no current job", child->argv[0]); - return EXIT_FAILURE; - } - } else { - if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { - error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]); - return EXIT_FAILURE; - } - for (job = child->family->job_list->head; job; job = job->next) { - if (job->jobid == jobnum) { - break; - } - } - if (!job) { - error_msg("%s: %d: no such job", child->argv[0], jobnum); - return EXIT_FAILURE; - } - } - - if (*child->argv[0] == 'f') { - /* Put the job into the foreground. */ - tcsetpgrp(shell_terminal, job->pgrp); - - child->family->job_list->fg = job; - } - - /* Restart the processes in the job */ - for (i = 0; i < job->num_progs; i++) - job->progs[i].is_stopped = 0; - - job->stopped_progs = 0; - - if ( (i=kill(- job->pgrp, SIGCONT)) < 0) { - if (i == ESRCH) { - remove_job(&job_list, job); - } else { - perror_msg("kill (SIGCONT)"); - } - } - - return EXIT_SUCCESS; -} - -/* built-in 'help' handler */ -static int builtin_help(struct child_prog *dummy) -{ - struct built_in_command *x; - - printf("\nBuilt-in commands:\n"); - printf("-------------------\n"); - for (x = bltins; x->cmd; x++) { - if (x->descr==NULL) - continue; - printf("%s\t%s\n", x->cmd, x->descr); - } - for (x = bltins_forking; x->cmd; x++) { - if (x->descr==NULL) - continue; - printf("%s\t%s\n", x->cmd, x->descr); - } - printf("\n\n"); - return EXIT_SUCCESS; -} - -/* built-in 'jobs' handler */ -static int builtin_jobs(struct child_prog *child) -{ - struct job *job; - char *status_string; - - for (job = child->family->job_list->head; job; job = job->next) { - if (job->running_progs == job->stopped_progs) - status_string = "Stopped"; - else - status_string = "Running"; - - printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text); - } - return EXIT_SUCCESS; -} - - -/* built-in 'pwd' handler */ -static int builtin_pwd(struct child_prog *dummy) -{ - cwd = xgetcwd((char *)cwd); - if (!cwd) - cwd = unknown; - puts(cwd); - return EXIT_SUCCESS; -} - -/* built-in 'export VAR=value' handler */ -static int builtin_export(struct child_prog *child) -{ - int res; - char *v = child->argv[1]; - - if (v == NULL) { - char **e; - for (e = environ; *e; e++) { - puts(*e); - } - return 0; - } - res = putenv(v); - if (res) - fprintf(stderr, "export: %m\n"); -#ifdef BB_FEATURE_SH_FANCY_PROMPT - if (strncmp(v, "PS1=", 4)==0) - PS1 = getenv("PS1"); -#endif - -#ifdef BB_LOCALE_SUPPORT - if(strncmp(v, "LC_ALL=", 7)==0) - setlocale(LC_ALL, getenv("LC_ALL")); - if(strncmp(v, "LC_CTYPE=", 9)==0) - setlocale(LC_CTYPE, getenv("LC_CTYPE")); -#endif - - return (res); -} - -/* built-in 'read VAR' handler */ -static int builtin_read(struct child_prog *child) -{ - int res = 0, len, newlen; - char *s; - char string[MAX_READ]; - - if (child->argv[1]) { - /* argument (VAR) given: put "VAR=" into buffer */ - strcpy(string, child->argv[1]); - len = strlen(string); - string[len++] = '='; - string[len] = '\0'; - fgets(&string[len], sizeof(string) - len, stdin); /* read string */ - newlen = strlen(string); - if(newlen > len) - string[--newlen] = '\0'; /* chomp trailing newline */ - /* - ** string should now contain "VAR=" - ** copy it (putenv() won't do that, so we must make sure - ** the string resides in a static buffer!) - */ - res = -1; - if((s = strdup(string))) - res = putenv(s); - if (res) - fprintf(stderr, "read: %m\n"); - } - else - fgets(string, sizeof(string), stdin); - - return (res); -} - -/* Built-in '.' handler (read-in and execute commands from file) */ -static int builtin_source(struct child_prog *child) -{ - FILE *input; - int status; - int fd; - - if (child->argv[1] == NULL) - return EXIT_FAILURE; - - input = fopen(child->argv[1], "r"); - if (!input) { - printf( "Couldn't open file '%s'\n", child->argv[1]); - return EXIT_FAILURE; - } - - fd=fileno(input); - mark_open(fd); - /* Now run the file */ - status = busy_loop(input); - fclose(input); - mark_closed(fd); - return (status); -} - -/* built-in 'unset VAR' handler */ -static int builtin_unset(struct child_prog *child) -{ - if (child->argv[1] == NULL) { - printf( "unset: parameter required.\n"); - return EXIT_FAILURE; - } - unsetenv(child->argv[1]); - return EXIT_SUCCESS; -} - -static void mark_open(int fd) -{ - struct close_me *new = xmalloc(sizeof(struct close_me)); - new->fd = fd; - new->next = close_me_head; - close_me_head = new; -} - -static void mark_closed(int fd) -{ - struct close_me *tmp; - if (close_me_head == NULL || close_me_head->fd != fd) - error_msg_and_die("corrupt close_me"); - tmp = close_me_head; - close_me_head = close_me_head->next; - free(tmp); -} - -static void close_all() -{ - struct close_me *c, *tmp; - for (c=close_me_head; c; c=tmp) { - close(c->fd); - tmp=c->next; - free(c); - } - close_me_head = NULL; -} - - -/* free up all memory from a job */ -static void free_job(struct job *cmd) -{ - int i; - struct jobset *keep; - - for (i = 0; i < cmd->num_progs; i++) { - free(cmd->progs[i].argv); - if (cmd->progs[i].redirects) - free(cmd->progs[i].redirects); - } - if (cmd->progs) - free(cmd->progs); - if (cmd->text) - free(cmd->text); - if (cmd->cmdbuf) - free(cmd->cmdbuf); - keep = cmd->job_list; - memset(cmd, 0, sizeof(struct job)); - cmd->job_list = keep; -} - -/* remove a job from a jobset */ -static void remove_job(struct jobset *j_list, struct job *job) -{ - struct job *prevjob; - - free_job(job); - if (job == j_list->head) { - j_list->head = job->next; - } else { - prevjob = j_list->head; - while (prevjob->next != job) - prevjob = prevjob->next; - prevjob->next = job->next; - } - - if (j_list->head) - last_jobid = j_list->head->jobid; - else - last_jobid = 0; - - free(job); -} - -/* Checks to see if any background processes have exited -- if they - have, figure out why and see if a job has completed */ -static void checkjobs(struct jobset *j_list) -{ - struct job *job; - pid_t childpid; - int status; - int prognum = 0; - - while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { - for (job = j_list->head; job; job = job->next) { - prognum = 0; - while (prognum < job->num_progs && - job->progs[prognum].pid != childpid) prognum++; - if (prognum < job->num_progs) - break; - } - - /* This happens on backticked commands */ - if(job==NULL) - return; - - if (WIFEXITED(status) || WIFSIGNALED(status)) { - /* child exited */ - job->running_progs--; - job->progs[prognum].pid = 0; - - if (!job->running_progs) { - printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text); - last_jobid=0; - remove_job(j_list, job); - } - } else { - /* child stopped */ - job->stopped_progs++; - job->progs[prognum].is_stopped = 1; - -#if 0 - /* Printing this stuff is a pain, since it tends to - * overwrite the prompt an inconveinient moments. So - * don't do that. */ - if (job->stopped_progs == job->num_progs) { - printf(JOB_STATUS_FORMAT, job->jobid, "Stopped", - job->text); - } -#endif - } - } - - if (childpid == -1 && errno != ECHILD) - perror_msg("waitpid"); -} - -/* squirrel != NULL means we squirrel away copies of stdin, stdout, - * and stderr if they are redirected. */ -static int setup_redirects(struct child_prog *prog, int squirrel[]) -{ - int i; - int openfd; - int mode = O_RDONLY; - struct redir_struct *redir = prog->redirects; - - for (i = 0; i < prog->num_redirects; i++, redir++) { - switch (redir->type) { - case REDIRECT_INPUT: - mode = O_RDONLY; - break; - case REDIRECT_OVERWRITE: - mode = O_WRONLY | O_CREAT | O_TRUNC; - break; - case REDIRECT_APPEND: - mode = O_WRONLY | O_CREAT | O_APPEND; - break; - } - - openfd = open(redir->filename, mode, 0666); - if (openfd < 0) { - /* this could get lost if stderr has been redirected, but - bash and ash both lose it as well (though zsh doesn't!) */ - perror_msg("error opening %s", redir->filename); - return 1; - } - - if (openfd != redir->fd) { - if (squirrel && redir->fd < 3) { - squirrel[redir->fd] = dup(redir->fd); - } - dup2(openfd, redir->fd); - close(openfd); - } - } - - return 0; -} - -static void restore_redirects(int squirrel[]) -{ - int i, fd; - for (i=0; i<3; i++) { - fd = squirrel[i]; - if (fd != -1) { - /* No error checking. I sure wouldn't know what - * to do with an error if I found one! */ - dup2(fd, i); - close(fd); - } - } -} - -static inline void cmdedit_set_initial_prompt(void) -{ -#ifndef BB_FEATURE_SH_FANCY_PROMPT - PS1 = NULL; -#else - PS1 = getenv("PS1"); - if(PS1==0) - PS1 = "\\w \\$ "; -#endif -} - -static inline void setup_prompt_string(char **prompt_str) -{ -#ifndef BB_FEATURE_SH_FANCY_PROMPT - /* Set up the prompt */ - if (shell_context == 0) { - if (PS1) - free(PS1); - PS1=xmalloc(strlen(cwd)+4); - sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); - *prompt_str = PS1; - } else { - *prompt_str = PS2; - } -#else - *prompt_str = (shell_context==0)? PS1 : PS2; -#endif -} - -static int get_command(FILE * source, char *command) -{ - char *prompt_str; - - if (source == NULL) { - if (local_pending_command) { - /* a command specified (-c option): return it & mark it done */ - strcpy(command, local_pending_command); - free(local_pending_command); - local_pending_command = NULL; - return 0; - } - return 1; - } - - if (source == stdin) { - setup_prompt_string(&prompt_str); - -#ifdef BB_FEATURE_COMMAND_EDITING - /* - ** enable command line editing only while a command line - ** is actually being read; otherwise, we'll end up bequeathing - ** atexit() handlers and other unwanted stuff to our - ** child processes (rob@sysgo.de) - */ - cmdedit_read_input(prompt_str, command); - return 0; -#else - fputs(prompt_str, stdout); -#endif - } - - if (!fgets(command, BUFSIZ - 2, source)) { - if (source == stdin) - printf("\n"); - return 1; - } - - return 0; -} - -static char* itoa(register int i) -{ - static char a[7]; /* Max 7 ints */ - register char *b = a + sizeof(a) - 1; - int sign = (i < 0); - - if (sign) - i = -i; - *b = 0; - do - { - *--b = '0' + (i % 10); - i /= 10; - } - while (i); - if (sign) - *--b = '-'; - return b; -} - -char * strsep_space( char *string, int * ix) -{ - char *token, *begin; - - begin = string; - - /* Short circuit the trivial case */ - if ( !string || ! string[*ix]) - return NULL; - - /* Find the end of the token. */ - while( string && string[*ix] && !isspace(string[*ix]) ) { - (*ix)++; - } - - /* Find the end of any whitespace trailing behind - * the token and let that be part of the token */ - while( string && string[*ix] && isspace(string[*ix]) ) { - (*ix)++; - } - - if (! string && *ix==0) { - /* Nothing useful was found */ - return NULL; - } - - token = xmalloc(*ix+1); - token[*ix] = '\0'; - strncpy(token, string, *ix); - - return token; -} - -static int expand_arguments(char *command) -{ - int total_length=0, length, i, retval, ix = 0; - expand_t expand_result; - char *tmpcmd, *cmd, *cmd_copy; - char *src, *dst, *var; - const char *out_of_space = "out of space during expansion"; - int flags = GLOB_NOCHECK -#ifdef GLOB_BRACE - | GLOB_BRACE -#endif -#ifdef GLOB_TILDE - | GLOB_TILDE -#endif - ; - - /* get rid of the terminating \n */ - chomp(command); - - /* Fix up escape sequences to be the Real Thing(tm) */ - while( command && command[ix]) { - if (command[ix] == '\\') { - const char *tmp = command+ix+1; - command[ix] = process_escape_sequence( &tmp ); - memmove(command+ix + 1, tmp, strlen(tmp)+1); - } - ix++; - } - /* Use glob and then fixup environment variables and such */ - - /* It turns out that glob is very stupid. We have to feed it one word at a - * time since it can't cope with a full string. Here we convert command - * (char*) into cmd (char**, one word per string) */ - - /* We need a clean copy, so strsep can mess up the copy while - * we write stuff into the original (in a minute) */ - cmd = cmd_copy = strdup(command); - *command = '\0'; - for (ix = 0, tmpcmd = cmd; - (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) { - if (*tmpcmd == '\0') - break; - /* we need to trim() the result for glob! */ - trim(tmpcmd); - retval = glob(tmpcmd, flags, NULL, &expand_result); - free(tmpcmd); /* Free mem allocated by strsep_space */ - if (retval == GLOB_NOSPACE) { - /* Mem may have been allocated... */ - globfree (&expand_result); - error_msg(out_of_space); - return FALSE; - } else if (retval != 0) { - /* Some other error. GLOB_NOMATCH shouldn't - * happen because of the GLOB_NOCHECK flag in - * the glob call. */ - error_msg("syntax error"); - return FALSE; - } else { - /* Convert from char** (one word per string) to a simple char*, - * but don't overflow command which is BUFSIZ in length */ - for (i=0; i < expand_result.gl_pathc; i++) { - length=strlen(expand_result.gl_pathv[i]); - if (total_length+length+1 >= BUFSIZ) { - error_msg(out_of_space); - return FALSE; - } - strcat(command+total_length, " "); - total_length+=1; - strcat(command+total_length, expand_result.gl_pathv[i]); - total_length+=length; - } - globfree (&expand_result); - } - } - free(cmd_copy); - trim(command); - - /* Now do the shell variable substitutions which - * wordexp can't do for us, namely $? and $! */ - src = command; - while((dst = strchr(src,'$')) != NULL){ - var = NULL; - switch(*(dst+1)) { - case '?': - var = itoa(last_return_code); - break; - case '!': - if (last_bg_pid==-1) - *(var)='\0'; - else - var = itoa(last_bg_pid); - break; - /* Everything else like $$, $#, $[0-9], etc. should all be - * expanded by wordexp(), so we can in theory skip that stuff - * here, but just to be on the safe side (i.e., since uClibc - * wordexp doesn't do this stuff yet), lets leave it in for - * now. */ - case '$': - var = itoa(getpid()); - break; - case '#': - var = itoa(argc-1); - break; - case '0':case '1':case '2':case '3':case '4': - case '5':case '6':case '7':case '8':case '9': - { - int ixx=*(dst + 1)-48; - if (ixx >= argc) { - var='\0'; - } else { - var = argv[ixx]; - } - } - break; - - } - if (var) { - /* a single character construction was found, and - * already handled in the case statement */ - src=dst+2; - } else { - /* Looks like an environment variable */ - char delim_hold; - int num_skip_chars=0; - int dstlen = strlen(dst); - /* Is this a ${foo} type variable? */ - if (dstlen >=2 && *(dst+1) == '{') { - src=strchr(dst+1, '}'); - num_skip_chars=1; - } else { - src=dst+1; - while(isalnum(*src) || *src=='_') src++; - } - if (src == NULL) { - src = dst+dstlen; - } - delim_hold=*src; - *src='\0'; /* temporary */ - var = getenv(dst + 1 + num_skip_chars); - *src=delim_hold; - src += num_skip_chars; - } - if (var == NULL) { - /* Seems we got an un-expandable variable. So delete it. */ - var = ""; - } - { - int subst_len = strlen(var); - int trail_len = strlen(src); - if (dst+subst_len+trail_len >= command+BUFSIZ) { - error_msg(out_of_space); - return FALSE; - } - /* Move stuff to the end of the string to accommodate - * filling the created gap with the new stuff */ - memmove(dst+subst_len, src, trail_len+1); - /* Now copy in the new stuff */ - memcpy(dst, var, subst_len); - src = dst+subst_len; - } - } - - return TRUE; -} - -/* Return cmd->num_progs as 0 if no command is present (e.g. an empty - line). If a valid command is found, command_ptr is set to point to - the beginning of the next command (if the original command had more - then one job associated with it) or NULL if no more commands are - present. */ -static int parse_command(char **command_ptr, struct job *job, int *inbg) -{ - char *command; - char *return_command = NULL; - char *src, *buf, *chptr; - int argc_l = 0; - int done = 0; - int argv_alloced; - int i, saw_quote = 0; - char quote = '\0'; - int count; - struct child_prog *prog; - - /* skip leading white space */ - while (**command_ptr && isspace(**command_ptr)) - (*command_ptr)++; - - /* this handles empty lines or leading '#' characters */ - if (!**command_ptr || (**command_ptr == '#')) { - job->num_progs=0; - return 0; - } - - *inbg = 0; - job->num_progs = 1; - job->progs = xmalloc(sizeof(*job->progs)); - - /* We set the argv elements to point inside of this string. The - memory is freed by free_job(). Allocate twice the original - length in case we need to quote every single character. - - Getting clean memory relieves us of the task of NULL - terminating things and makes the rest of this look a bit - cleaner (though it is, admittedly, a tad less efficient) */ - job->cmdbuf = command = xcalloc(2*strlen(*command_ptr) + 1, sizeof(char)); - job->text = NULL; - - prog = job->progs; - prog->num_redirects = 0; - prog->redirects = NULL; - prog->is_stopped = 0; - prog->family = job; - - argv_alloced = 5; - prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced); - prog->argv[0] = job->cmdbuf; - - buf = command; - src = *command_ptr; - while (*src && !done) { - if (quote == *src) { - quote = '\0'; - } else if (quote) { - if (*src == '\\') { - src++; - if (!*src) { - error_msg("character expected after \\"); - free_job(job); - return 1; - } - - /* in shell, "\'" should yield \' */ - if (*src != quote) { - *buf++ = '\\'; - *buf++ = '\\'; - } - } else if (*src == '*' || *src == '?' || *src == '[' || - *src == ']') *buf++ = '\\'; - *buf++ = *src; - } else if (isspace(*src)) { - if (*prog->argv[argc_l] || saw_quote) { - buf++, argc_l++; - /* +1 here leaves room for the NULL which ends argv */ - if ((argc_l + 1) == argv_alloced) { - argv_alloced += 5; - prog->argv = xrealloc(prog->argv, - sizeof(*prog->argv) * - argv_alloced); - } - prog->argv[argc_l] = buf; - saw_quote = 0; - } - } else - switch (*src) { - case '"': - case '\'': - quote = *src; - saw_quote = 1; - break; - - case '#': /* comment */ - if (*(src-1)== '$') - *buf++ = *src; - else - done = 1; - break; - - case '>': /* redirects */ - case '<': - i = prog->num_redirects++; - prog->redirects = xrealloc(prog->redirects, - sizeof(*prog->redirects) * - (i + 1)); - - prog->redirects[i].fd = -1; - if (buf != prog->argv[argc_l]) { - /* the stuff before this character may be the file number - being redirected */ - prog->redirects[i].fd = - strtol(prog->argv[argc_l], &chptr, 10); - - if (*chptr && *prog->argv[argc_l]) { - buf++, argc_l++; - prog->argv[argc_l] = buf; - } - } - - if (prog->redirects[i].fd == -1) { - if (*src == '>') - prog->redirects[i].fd = 1; - else - prog->redirects[i].fd = 0; - } - - if (*src++ == '>') { - if (*src == '>') - prog->redirects[i].type = - REDIRECT_APPEND, src++; - else - prog->redirects[i].type = REDIRECT_OVERWRITE; - } else { - prog->redirects[i].type = REDIRECT_INPUT; - } - - /* This isn't POSIX sh compliant. Oh well. */ - chptr = src; - while (isspace(*chptr)) - chptr++; - - if (!*chptr) { - error_msg("file name expected after %c", *(src-1)); - free_job(job); - job->num_progs=0; - return 1; - } - - prog->redirects[i].filename = buf; - while (*chptr && !isspace(*chptr)) - *buf++ = *chptr++; - - src = chptr - 1; /* we src++ later */ - prog->argv[argc_l] = ++buf; - break; - - case '|': /* pipe */ - /* finish this command */ - if (*prog->argv[argc_l] || saw_quote) - argc_l++; - if (!argc_l) { - error_msg("empty command in pipe"); - free_job(job); - job->num_progs=0; - return 1; - } - prog->argv[argc_l] = NULL; - - /* and start the next */ - job->num_progs++; - job->progs = xrealloc(job->progs, - sizeof(*job->progs) * job->num_progs); - prog = job->progs + (job->num_progs - 1); - prog->num_redirects = 0; - prog->redirects = NULL; - prog->is_stopped = 0; - prog->family = job; - argc_l = 0; - - argv_alloced = 5; - prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced); - prog->argv[0] = ++buf; - - src++; - while (*src && isspace(*src)) - src++; - - if (!*src) { - error_msg("empty command in pipe"); - free_job(job); - job->num_progs=0; - return 1; - } - src--; /* we'll ++ it at the end of the loop */ - - break; - - case '&': /* background */ - *inbg = 1; - case ';': /* multiple commands */ - done = 1; - return_command = *command_ptr + (src - *command_ptr) + 1; - break; - - case '\\': - src++; - if (!*src) { - error_msg("character expected after \\"); - free_job(job); - return 1; - } - if (*src == '*' || *src == '[' || *src == ']' - || *src == '?') *buf++ = '\\'; - /* fallthrough */ - default: - *buf++ = *src; - } - - src++; - } - - if (*prog->argv[argc_l] || saw_quote) { - argc_l++; - } - if (!argc_l) { - free_job(job); - return 0; - } - prog->argv[argc_l] = NULL; - - if (!return_command) { - job->text = xmalloc(strlen(*command_ptr) + 1); - strcpy(job->text, *command_ptr); - } else { - /* This leaves any trailing spaces, which is a bit sloppy */ - count = return_command - *command_ptr; - job->text = xmalloc(count + 1); - strncpy(job->text, *command_ptr, count); - job->text[count] = '\0'; - } - - *command_ptr = return_command; - - return 0; -} - -/* Run the child_prog, no matter what kind of command it uses. - */ -static int pseudo_exec(struct child_prog *child) -{ - struct built_in_command *x; -#ifdef BB_FEATURE_SH_STANDALONE_SHELL - char *name; -#endif - - /* Check if the command matches any of the non-forking builtins. - * Depending on context, this might be redundant. But it's - * easier to waste a few CPU cycles than it is to figure out - * if this is one of those cases. - */ - for (x = bltins; x->cmd; x++) { - if (strcmp(child->argv[0], x->cmd) == 0 ) { - exit(x->function(child)); - } - } - - /* Check if the command matches any of the forking builtins. */ - for (x = bltins_forking; x->cmd; x++) { - if (strcmp(child->argv[0], x->cmd) == 0) { - applet_name=x->cmd; - exit (x->function(child)); - } - } -#ifdef BB_FEATURE_SH_STANDALONE_SHELL - /* Check if the command matches any busybox internal - * commands ("applets") here. Following discussions from - * November 2000 on busybox@opensource.lineo.com, don't use - * get_last_path_component(). This way explicit (with - * slashes) filenames will never be interpreted as an - * applet, just like with builtins. This way the user can - * override an applet with an explicit filename reference. - * The only downside to this change is that an explicit - * /bin/foo invocation will fork and exec /bin/foo, even if - * /bin/foo is a symlink to busybox. - */ - name = child->argv[0]; - -#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN - /* If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then - * if you run /bin/cat, it will use BusyBox cat even if - * /bin/cat exists on the filesystem and is _not_ busybox. - * Some systems want this, others do not. Choose wisely. :-) - */ - name = get_last_path_component(name); -#endif - - { - char** argv_l=child->argv; - int argc_l; - for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++); - optind = 1; - run_applet_by_name(name, argc_l, child->argv); - } -#endif - - execvp(child->argv[0], child->argv); - perror_msg_and_die("%s", child->argv[0]); -} - -static void insert_job(struct job *newjob, int inbg) -{ - struct job *thejob; - struct jobset *j_list=newjob->job_list; - - /* find the ID for thejob to use */ - newjob->jobid = 1; - for (thejob = j_list->head; thejob; thejob = thejob->next) - if (thejob->jobid >= newjob->jobid) - newjob->jobid = thejob->jobid + 1; - - /* add thejob to the list of running jobs */ - if (!j_list->head) { - thejob = j_list->head = xmalloc(sizeof(*thejob)); - } else { - for (thejob = j_list->head; thejob->next; thejob = thejob->next) /* nothing */; - thejob->next = xmalloc(sizeof(*thejob)); - thejob = thejob->next; - } - - *thejob = *newjob; /* physically copy the struct job */ - thejob->next = NULL; - thejob->running_progs = thejob->num_progs; - thejob->stopped_progs = 0; - - if (inbg) { - /* we don't wait for background thejobs to return -- append it - to the list of backgrounded thejobs and leave it alone */ - printf("[%d] %d\n", thejob->jobid, - newjob->progs[newjob->num_progs - 1].pid); - last_jobid = newjob->jobid; - last_bg_pid=newjob->progs[newjob->num_progs - 1].pid; - } else { - newjob->job_list->fg = thejob; - - /* move the new process group into the foreground */ - /* suppress messages when run from /linuxrc mag@sysgo.de */ - if (tcsetpgrp(shell_terminal, newjob->pgrp) && errno != ENOTTY) - perror_msg("tcsetpgrp"); - } -} - -static int run_command(struct job *newjob, int inbg, int outpipe[2]) -{ - /* struct job *thejob; */ - int i; - int nextin, nextout; - int pipefds[2]; /* pipefd[0] is for reading */ - struct built_in_command *x; - struct child_prog *child; - - nextin = 0, nextout = 1; - for (i = 0; i < newjob->num_progs; i++) { - child = & (newjob->progs[i]); - - if ((i + 1) < newjob->num_progs) { - if (pipe(pipefds)<0) perror_msg_and_die("pipe"); - nextout = pipefds[1]; - } else { - if (outpipe[1]!=-1) { - nextout = outpipe[1]; - } else { - nextout = 1; - } - } - - - /* Check if the command matches any non-forking builtins, - * but only if this is a simple command. - * Non-forking builtins within pipes have to fork anyway, - * and are handled in pseudo_exec. "echo foo | read bar" - * is doomed to failure, and doesn't work on bash, either. - */ - if (newjob->num_progs == 1) { - for (x = bltins; x->cmd; x++) { - if (strcmp(child->argv[0], x->cmd) == 0 ) { - int squirrel[] = {-1, -1, -1}; - int rcode; - setup_redirects(child, squirrel); - rcode = x->function(child); - restore_redirects(squirrel); - return rcode; - } - } - } - - if (!(child->pid = fork())) { - /* Set the handling for job control signals back to the default. */ - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGTSTP, SIG_DFL); - signal(SIGTTIN, SIG_DFL); - signal(SIGTTOU, SIG_DFL); - signal(SIGCHLD, SIG_DFL); - - close_all(); - - if (outpipe[1]!=-1) { - close(outpipe[0]); - } - if (nextin != 0) { - dup2(nextin, 0); - close(nextin); - } - - if (nextout != 1) { - dup2(nextout, 1); - dup2(nextout, 2); /* Really? */ - close(nextout); - close(pipefds[0]); - } - - /* explicit redirects override pipes */ - setup_redirects(child,NULL); - - pseudo_exec(child); - } - if (outpipe[1]!=-1) { - close(outpipe[1]); - } - - /* put our child in the process group whose leader is the - first process in this pipe */ - setpgid(child->pid, newjob->progs[0].pid); - if (nextin != 0) - close(nextin); - if (nextout != 1) - close(nextout); - - /* If there isn't another process, nextin is garbage - but it doesn't matter */ - nextin = pipefds[0]; - } - - newjob->pgrp = newjob->progs[0].pid; - - insert_job(newjob, inbg); - - return 0; -} - -static int busy_loop(FILE * input) -{ - char *command; - char *next_command = NULL; - struct job newjob; - pid_t parent_pgrp; - int i; - int inbg; - int status; - newjob.job_list = &job_list; - newjob.job_context = DEFAULT_CONTEXT; - - /* save current owner of TTY so we can restore it on exit */ - parent_pgrp = tcgetpgrp(shell_terminal); - - command = (char *) xcalloc(BUFSIZ, sizeof(char)); - - while (1) { - if (!job_list.fg) { - /* no job is in the foreground */ - - /* see if any background processes have exited */ - checkjobs(&job_list); - - if (!next_command) { - if (get_command(input, command)) - break; - next_command = command; - } - - if (expand_arguments(next_command) == FALSE) { - free(command); - command = (char *) xcalloc(BUFSIZ, sizeof(char)); - next_command = NULL; - continue; - } - - if (!parse_command(&next_command, &newjob, &inbg) && - newjob.num_progs) { - int pipefds[2] = {-1,-1}; - debug_printf( "job=%p fed to run_command by busy_loop()'\n", - &newjob); - run_command(&newjob, inbg, pipefds); - } - else { - free(command); - command = (char *) xcalloc(BUFSIZ, sizeof(char)); - next_command = NULL; - } - } else { - /* a job is running in the foreground; wait for it */ - i = 0; - while (!job_list.fg->progs[i].pid || - job_list.fg->progs[i].is_stopped == 1) i++; - - if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED)<0) - perror_msg_and_die("waitpid(%d)",job_list.fg->progs[i].pid); - - if (WIFEXITED(status) || WIFSIGNALED(status)) { - /* the child exited */ - job_list.fg->running_progs--; - job_list.fg->progs[i].pid = 0; - - last_return_code=WEXITSTATUS(status); - - if (!job_list.fg->running_progs) { - /* child exited */ - remove_job(&job_list, job_list.fg); - job_list.fg = NULL; - } - } else { - /* the child was stopped */ - job_list.fg->stopped_progs++; - job_list.fg->progs[i].is_stopped = 1; - - if (job_list.fg->stopped_progs == job_list.fg->running_progs) { - printf("\n" JOB_STATUS_FORMAT, job_list.fg->jobid, - "Stopped", job_list.fg->text); - job_list.fg = NULL; - } - } - - if (!job_list.fg) { - /* move the shell to the foreground */ - /* suppress messages when run from /linuxrc mag@sysgo.de */ - if (tcsetpgrp(shell_terminal, getpgrp()) && errno != ENOTTY) - perror_msg("tcsetpgrp"); - } - } - } - free(command); - - /* return controlling TTY back to parent process group before exiting */ - if (tcsetpgrp(shell_terminal, parent_pgrp)) - perror_msg("tcsetpgrp"); - - /* return exit status if called with "-c" */ - if (input == NULL && WIFEXITED(status)) - return WEXITSTATUS(status); - - return 0; -} - - -#ifdef BB_FEATURE_CLEAN_UP -void free_memory(void) -{ - if (cwd && cwd!=unknown) { - free((char*)cwd); - } - if (local_pending_command) - free(local_pending_command); - - if (job_list.fg && !job_list.fg->running_progs) { - remove_job(&job_list, job_list.fg); - } -} -#endif - -/* Make sure we have a controlling tty. If we get started under a job - * aware app (like bash for example), make sure we are now in charge so - * we don't fight over who gets the foreground */ -static void setup_job_control() -{ - int status; - - /* Loop until we are in the foreground. */ - while ((status = tcgetpgrp (shell_terminal)) >= 0) { - if (status == (shell_pgrp = getpgrp ())) { - break; - } - kill (- shell_pgrp, SIGTTIN); - } - - /* Ignore interactive and job-control signals. */ - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - signal(SIGTSTP, SIG_IGN); - signal(SIGTTIN, SIG_IGN); - signal(SIGTTOU, SIG_IGN); - signal(SIGCHLD, SIG_IGN); - - /* Put ourselves in our own process group. */ - setsid(); - shell_pgrp = getpid (); - setpgid (shell_pgrp, shell_pgrp); - - /* Grab control of the terminal. */ - tcsetpgrp(shell_terminal, shell_pgrp); -} - -int lash_main(int argc_l, char **argv_l) -{ - int opt, interactive=FALSE; - FILE *input = stdin; - argc = argc_l; - argv = argv_l; - - /* These variables need re-initializing when recursing */ - last_jobid = 0; - local_pending_command = NULL; - close_me_head = NULL; - job_list.head = NULL; - job_list.fg = NULL; - last_return_code=1; - - if (argv[0] && argv[0][0] == '-') { - FILE *prof_input; - prof_input = fopen("/etc/profile", "r"); - if (prof_input) { - int tmp_fd = fileno(prof_input); - mark_open(tmp_fd); - /* Now run the file */ - busy_loop(prof_input); - fclose(prof_input); - mark_closed(tmp_fd); - } - } - - while ((opt = getopt(argc_l, argv_l, "cxi")) > 0) { - switch (opt) { - case 'c': - input = NULL; - if (local_pending_command != 0) - error_msg_and_die("multiple -c arguments"); - local_pending_command = xstrdup(argv[optind]); - optind++; - argv = argv+optind; - break; - case 'i': - interactive = TRUE; - break; - default: - show_usage(); - } - } - /* A shell is interactive if the `-i' flag was given, or if all of - * the following conditions are met: - * no -c command - * no arguments remaining or the -s flag given - * standard input is a terminal - * standard output is a terminal - * Refer to Posix.2, the description of the `sh' utility. */ - if (argv[optind]==NULL && input==stdin && - isatty(fileno(stdin)) && isatty(fileno(stdout))) { - interactive=TRUE; - } - setup_job_control(); - if (interactive==TRUE) { - //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]); - /* Looks like they want an interactive shell */ - printf( "\n\n" BB_BANNER " Built-in shell (lash)\n"); - printf( "Enter 'help' for a list of built-in commands.\n\n"); - } else if (local_pending_command==NULL) { - //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]); - input = xfopen(argv[optind], "r"); - mark_open(fileno(input)); /* be lazy, never mark this closed */ - } - - /* initialize the cwd -- this is never freed...*/ - cwd = xgetcwd(0); - if (!cwd) - cwd = unknown; - -#ifdef BB_FEATURE_CLEAN_UP - atexit(free_memory); -#endif - -#ifdef BB_FEATURE_COMMAND_EDITING - cmdedit_set_initial_prompt(); -#else - PS1 = NULL; -#endif - - return (busy_loop(input)); -} diff --git a/busybox/length.c b/busybox/length.c deleted file mode 100644 index 73becd28a..000000000 --- a/busybox/length.c +++ /dev/null @@ -1,13 +0,0 @@ -/* vi: set sw=4 ts=4: */ -#include -#include -#include -#include "busybox.h" - -extern int length_main(int argc, char **argv) -{ - if (argc != 2 || **(argv + 1) == '-') - show_usage(); - printf("%lu\n", (long)strlen(argv[1])); - return EXIT_SUCCESS; -} diff --git a/busybox/libbb/.cvsignore b/busybox/libbb/.cvsignore deleted file mode 100644 index 2bbe016f5..000000000 --- a/busybox/libbb/.cvsignore +++ /dev/null @@ -1 +0,0 @@ -loop.h diff --git a/busybox/libbb/Makefile b/busybox/libbb/Makefile deleted file mode 100644 index a9ea76947..000000000 --- a/busybox/libbb/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# Silly wrapper makefile. This Makefile is _not_ used by the build system for -# busybox, it is just to make working on libbb more conveinient. -# -Erik Andersen - -all: - make -C .. libbb.a - -clean: - - rm -rf libbb.a - - find -name \*.o -exec rm -f {} \; - diff --git a/busybox/libbb/README b/busybox/libbb/README deleted file mode 100644 index 0e36f84b6..000000000 --- a/busybox/libbb/README +++ /dev/null @@ -1,15 +0,0 @@ -Please see the LICENSE file for copyright information. - -libbb is BusyBox's utility library. This all used to be in a single file -(utility.c to be specific). When I split utility.c up to create libbb, I did -not carefully fix up the copyright and licensing information. I'll do that for -the next release. - -For now, justtrust me that a bunch of people have worked on this stuff, -and it is all GPL'ed. - - Erik Andersen - - - - diff --git a/busybox/libbb/arith.c b/busybox/libbb/arith.c deleted file mode 100644 index 04c45ec3d..000000000 --- a/busybox/libbb/arith.c +++ /dev/null @@ -1,263 +0,0 @@ -/* Copyright (c) 2001 Aaron Lehmann - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* This is my infix parser/evaluator. It is optimized for size, intended - * as a replacement for yacc-based parsers. However, it may well be faster - * than a comparable parser writen in yacc. The supported operators are - * listed in #defines below. Parens, order of operations, and error handling - * are supported. This code is threadsafe. */ - -/* To use the routine, call it with an expression string. It returns an - * integer result. You will also need to define an "error" function - * that takes printf arguments and _does not return_, or modify the code - * to use another error mechanism. */ - -#include -#include -#include "libbb.h" - -typedef char operator; - -#define tok_decl(prec,id) (((id)<<5)|(prec)) -#define PREC(op) ((op)&0x1F) - -#define TOK_LPAREN tok_decl(0,0) - -#define TOK_OR tok_decl(1,0) - -#define TOK_AND tok_decl(2,0) - -#define TOK_BOR tok_decl(3,0) - -#define TOK_BXOR tok_decl(4,0) - -#define TOK_BAND tok_decl(5,0) - -#define TOK_EQ tok_decl(6,0) -#define TOK_NE tok_decl(6,1) - -#define TOK_LT tok_decl(7,0) -#define TOK_GT tok_decl(7,1) -#define TOK_GE tok_decl(7,2) -#define TOK_LE tok_decl(7,3) - -#define TOK_LSHIFT tok_decl(8,0) -#define TOK_RSHIFT tok_decl(8,1) - -#define TOK_ADD tok_decl(9,0) -#define TOK_SUB tok_decl(9,1) - -#define TOK_MUL tok_decl(10,0) -#define TOK_DIV tok_decl(10,1) -#define TOK_REM tok_decl(10,2) - -#define UNARYPREC 14 -#define TOK_BNOT tok_decl(UNARYPREC,0) -#define TOK_NOT tok_decl(UNARYPREC,1) -#define TOK_UMINUS tok_decl(UNARYPREC,2) - -#define TOK_NUM tok_decl(15,0) - -#define ARITH_APPLY(op) arith_apply(op, numstack, &numstackptr) -#define NUMPTR (*numstackptr) -static short arith_apply(operator op, long *numstack, long **numstackptr) -{ - if (NUMPTR == numstack) goto err; - if (op == TOK_UMINUS) - NUMPTR[-1] *= -1; - else if (op == TOK_NOT) - NUMPTR[-1] = !(NUMPTR[-1]); - else if (op == TOK_BNOT) - NUMPTR[-1] = ~(NUMPTR[-1]); - - /* Binary operators */ - else { - if (NUMPTR-1 == numstack) goto err; - --NUMPTR; - if (op == TOK_BOR) - NUMPTR[-1] |= *NUMPTR; - else if (op == TOK_OR) - NUMPTR[-1] = *NUMPTR || NUMPTR[-1]; - else if (op == TOK_BAND) - NUMPTR[-1] &= *NUMPTR; - else if (op == TOK_AND) - NUMPTR[-1] = NUMPTR[-1] && *NUMPTR; - else if (op == TOK_EQ) - NUMPTR[-1] = (NUMPTR[-1] == *NUMPTR); - else if (op == TOK_NE) - NUMPTR[-1] = (NUMPTR[-1] != *NUMPTR); - else if (op == TOK_GE) - NUMPTR[-1] = (NUMPTR[-1] >= *NUMPTR); - else if (op == TOK_RSHIFT) - NUMPTR[-1] >>= *NUMPTR; - else if (op == TOK_LSHIFT) - NUMPTR[-1] <<= *NUMPTR; - else if (op == TOK_GT) - NUMPTR[-1] = (NUMPTR[-1] > *NUMPTR); - else if (op == TOK_LT) - NUMPTR[-1] = (NUMPTR[-1] < *NUMPTR); - else if (op == TOK_LE) - NUMPTR[-1] = (NUMPTR[-1] <= *NUMPTR); - else if (op == TOK_MUL) - NUMPTR[-1] *= *NUMPTR; - else if (op == TOK_DIV) { - if(*NUMPTR==0) - return -2; - NUMPTR[-1] /= *NUMPTR; - } - else if (op == TOK_REM) { - if(*NUMPTR==0) - return -2; - NUMPTR[-1] %= *NUMPTR; - } - else if (op == TOK_ADD) - NUMPTR[-1] += *NUMPTR; - else if (op == TOK_SUB) - NUMPTR[-1] -= *NUMPTR; - } - return 0; -err: return(-1); -} - -extern long arith (const char *startbuf, int *errcode) -{ - register char arithval; - const char *expr = startbuf; - - operator lasttok = TOK_MUL, op; - size_t datasizes = strlen(startbuf); - unsigned char prec; - - long *numstack, *numstackptr; - operator *stack = alloca(datasizes * sizeof(operator)), *stackptr = stack; - - *errcode = 0; - numstack = alloca((datasizes/2+1)*sizeof(long)), numstackptr = numstack; - - while ((arithval = *expr)) { - if (arithval == ' ' || arithval == '\n' || arithval == '\t') - goto prologue; - if ((unsigned)arithval-'0' <= 9) /* isdigit */ { - *numstackptr++ = strtol(expr, (char **) &expr, 10); - lasttok = TOK_NUM; - continue; - } if (arithval == '(') { - *stackptr++ = TOK_LPAREN; - lasttok = TOK_LPAREN; - goto prologue; - } if (arithval == ')') { - lasttok = TOK_NUM; - while (stackptr != stack) { - op = *--stackptr; - if (op == TOK_LPAREN) - goto prologue; - *errcode = ARITH_APPLY(op); - if(*errcode) return *errcode; - } - goto err; /* Mismatched parens */ - } if (arithval == '|') { - if (*++expr == '|') - op = TOK_OR; - else { - --expr; - op = TOK_BOR; - } - } else if (arithval == '&') { - if (*++expr == '&') - op = TOK_AND; - else { - --expr; - op = TOK_BAND; - } - } else if (arithval == '=') { - if (*++expr != '=') goto err; /* Unknown token */ - op = TOK_EQ; - } else if (arithval == '!') { - if (*++expr == '=') - op = TOK_NE; - else { - --expr; - op = TOK_NOT; - } - } else if (arithval == '>') { - switch (*++expr) { - case '=': - op = TOK_GE; - break; - case '>': - op = TOK_RSHIFT; - break; - default: - --expr; - op = TOK_GT; - } - } else if (arithval == '<') { - switch (*++expr) { - case '=': - op = TOK_LE; - break; - case '<': - op = TOK_LSHIFT; - break; - default: - --expr; - op = TOK_LT; - } - } else if (arithval == '*') - op = TOK_MUL; - else if (arithval == '/') - op = TOK_DIV; - else if (arithval == '%') - op = TOK_REM; - else if (arithval == '+') { - if (lasttok != TOK_NUM) goto prologue; /* Unary plus */ - op = TOK_ADD; - } else if (arithval == '-') - op = (lasttok == TOK_NUM) ? TOK_SUB : TOK_UMINUS; - else if (arithval == '~') - op = TOK_BNOT; - else goto err; /* Unknown token */ - - prec = PREC(op); - if (prec != UNARYPREC) - while (stackptr != stack && PREC(stackptr[-1]) >= prec) { - *errcode = ARITH_APPLY(*--stackptr); - if(*errcode) return *errcode; - } - *stackptr++ = op; - lasttok = op; -prologue: ++expr; - } /* yay */ - - while (stackptr != stack) { - *errcode = ARITH_APPLY(*--stackptr); - if(*errcode) return *errcode; - } - if (numstackptr != numstack+1) { -err: - *errcode = -1; - return -1; - /* NOTREACHED */ - } - - return *numstack; -} diff --git a/busybox/libbb/ask_confirmation.c b/busybox/libbb/ask_confirmation.c deleted file mode 100644 index f2922379c..000000000 --- a/busybox/libbb/ask_confirmation.c +++ /dev/null @@ -1,53 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include "libbb.h" - - -int ask_confirmation() -{ - int c = '\0'; - int ret = 0; - - while (c != '\n') { - c = getchar(); - if ( c != '\n' ) { - ret = ((c=='y')||(c=='Y')) ? 1 : 0; - } - } - return ret; -} - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/chomp.c b/busybox/libbb/chomp.c deleted file mode 100644 index 111d4cf77..000000000 --- a/busybox/libbb/chomp.c +++ /dev/null @@ -1,49 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "libbb.h" - - -void chomp(char *s) -{ - char *lc = last_char_is(s, '\n'); - - if(lc) - *lc = 0; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/concat_path_file.c b/busybox/libbb/concat_path_file.c deleted file mode 100644 index 86dd2fbbf..000000000 --- a/busybox/libbb/concat_path_file.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * busybox library eXtendet funcion - * - * concatenate path and file name to new allocation buffer, - * not addition '/' if path name already have '/' - * -*/ - -#include -#include "libbb.h" - -extern char *concat_path_file(const char *path, const char *filename) -{ - char *outbuf; - char *lc; - - if (!path) - path=""; - lc = last_char_is(path, '/'); - while (*filename == '/') - filename++; - outbuf = xmalloc(strlen(path)+strlen(filename)+1+(lc==NULL)); - sprintf(outbuf, "%s%s%s", path, (lc==NULL)? "/" : "", filename); - - return outbuf; -} diff --git a/busybox/libbb/copy_file.c b/busybox/libbb/copy_file.c deleted file mode 100644 index c79fbeb14..000000000 --- a/busybox/libbb/copy_file.c +++ /dev/null @@ -1,237 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini copy_file implementation for busybox - * - * - * 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libbb.h" - -int copy_file(const char *source, const char *dest, int flags) -{ - struct stat source_stat; - struct stat dest_stat; - int dest_exists = 1; - int status = 0; - - if (((flags & FILEUTILS_PRESERVE_SYMLINKS) && - lstat(source, &source_stat) < 0) || - (!(flags & FILEUTILS_PRESERVE_SYMLINKS) && - stat(source, &source_stat) < 0)) { - perror_msg("%s", source); - return -1; - } - - if (stat(dest, &dest_stat) < 0) { - if (errno != ENOENT) { - perror_msg("unable to stat `%s'", dest); - return -1; - } - dest_exists = 0; - } - - if (dest_exists && source_stat.st_rdev == dest_stat.st_rdev && - source_stat.st_ino == dest_stat.st_ino) { - error_msg("`%s' and `%s' are the same file", source, dest); - return -1; - } - - if (S_ISDIR(source_stat.st_mode)) { - DIR *dp; - struct dirent *d; - mode_t saved_umask = 0; - - if (!(flags & FILEUTILS_RECUR)) { - error_msg("%s: omitting directory", source); - return -1; - } - - /* Create DEST. */ - if (dest_exists) { - if (!S_ISDIR(dest_stat.st_mode)) { - error_msg("`%s' is not a directory", dest); - return -1; - } - } else { - mode_t mode; - saved_umask = umask(0); - - mode = source_stat.st_mode; - if (!(flags & FILEUTILS_PRESERVE_STATUS)) - mode = source_stat.st_mode & ~saved_umask; - mode |= S_IRWXU; - - if (mkdir(dest, mode) < 0) { - umask(saved_umask); - perror_msg("cannot create directory `%s'", dest); - return -1; - } - - umask(saved_umask); - } - - /* Recursively copy files in SOURCE. */ - if ((dp = opendir(source)) == NULL) { - perror_msg("unable to open directory `%s'", source); - status = -1; - goto end; - } - - while ((d = readdir(dp)) != NULL) { - char *new_source, *new_dest; - - if (strcmp(d->d_name, ".") == 0 || - strcmp(d->d_name, "..") == 0) - continue; - - new_source = concat_path_file(source, d->d_name); - new_dest = concat_path_file(dest, d->d_name); - if (copy_file(new_source, new_dest, flags) < 0) - status = -1; - free(new_source); - free(new_dest); - } - - /* ??? What if an error occurs in readdir? */ - - if (closedir(dp) < 0) { - perror_msg("unable to close directory `%s'", source); - status = -1; - } - - if (!dest_exists && - chmod(dest, source_stat.st_mode & ~saved_umask) < 0) { - perror_msg("unable to change permissions of `%s'", dest); - status = -1; - } - } else if (S_ISREG(source_stat.st_mode)) { - FILE *sfp, *dfp; - - if (dest_exists) { - if (flags & FILEUTILS_INTERACTIVE) { - fprintf(stderr, "%s: overwrite `%s'? ", applet_name, dest); - if (!ask_confirmation()) - return 0; - } - - if ((dfp = fopen(dest, "w")) == NULL) { - if (!(flags & FILEUTILS_FORCE)) { - perror_msg("unable to open `%s'", dest); - return -1; - } - - if (unlink(dest) < 0) { - perror_msg("unable to remove `%s'", dest); - return -1; - } - - dest_exists = 0; - } - } - - if (!dest_exists) { - int fd; - - if ((fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode)) < 0 || - (dfp = fdopen(fd, "w")) == NULL) { - if (fd >= 0) - close(fd); - perror_msg("unable to open `%s'", dest); - return -1; - } - } - - if ((sfp = fopen(source, "r")) == NULL) { - fclose(dfp); - perror_msg("unable to open `%s'", source); - status = -1; - goto end; - } - - if (copy_file_chunk(sfp, dfp, -1) < 0) - status = -1; - - if (fclose(dfp) < 0) { - perror_msg("unable to close `%s'", dest); - status = -1; - } - - if (fclose(sfp) < 0) { - perror_msg("unable to close `%s'", source); - status = -1; - } - } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) || - S_ISSOCK(source_stat.st_mode)) { - if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { - perror_msg("unable to create `%s'", dest); - return -1; - } - } else if (S_ISFIFO(source_stat.st_mode)) { - if (mkfifo(dest, source_stat.st_mode) < 0) { - perror_msg("cannot create fifo `%s'", dest); - return -1; - } - } else if (S_ISLNK(source_stat.st_mode)) { - char *lpath = xreadlink(source); - if (symlink(lpath, dest) < 0) { - perror_msg("cannot create symlink `%s'", dest); - return -1; - } - free(lpath); - -#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) - if (flags & FILEUTILS_PRESERVE_STATUS) - if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) - perror_msg("unable to preserve ownership of `%s'", dest); -#endif - return 0; - } else { - error_msg("internal error: unrecognized file type"); - return -1; - } - -end: - - if (flags & FILEUTILS_PRESERVE_STATUS) { - struct utimbuf times; - - times.actime = source_stat.st_atime; - times.modtime = source_stat.st_mtime; - if (utime(dest, ×) < 0) - perror_msg("unable to preserve times of `%s'", dest); - if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { - source_stat.st_mode &= ~(S_ISUID | S_ISGID); - perror_msg("unable to preserve ownership of `%s'", dest); - } - if (chmod(dest, source_stat.st_mode) < 0) - perror_msg("unable to preserve permissions of `%s'", dest); - } - - return status; -} diff --git a/busybox/libbb/copy_file_chunk.c b/busybox/libbb/copy_file_chunk.c deleted file mode 100644 index c440a6102..000000000 --- a/busybox/libbb/copy_file_chunk.c +++ /dev/null @@ -1,74 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "libbb.h" - -/* Copy CHUNKSIZE bytes (or until EOF if CHUNKSIZE equals -1) from SRC_FILE - * to DST_FILE. */ -extern int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize) -{ - size_t nread, nwritten, size; - char buffer[BUFSIZ]; - - while (chunksize != 0) { - if (chunksize > BUFSIZ) - size = BUFSIZ; - else - size = chunksize; - - nread = fread (buffer, 1, size, src_file); - - if (nread != size && ferror (src_file)) { - perror_msg ("read"); - return -1; - } else if (nread == 0) { - if (chunksize != -1) { - error_msg ("Unable to read all data"); - return -1; - } - - return 0; - } - - nwritten = fwrite (buffer, 1, nread, dst_file); - - if (nwritten != nread) { - if (ferror (dst_file)) - perror_msg ("write"); - else - error_msg ("Unable to write all data"); - return -1; - } - - if (chunksize != -1) - chunksize -= nwritten; - } - - return 0; -} diff --git a/busybox/libbb/copyfd.c b/busybox/libbb/copyfd.c deleted file mode 100644 index aa938d105..000000000 --- a/busybox/libbb/copyfd.c +++ /dev/null @@ -1,59 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) 1999-2001 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 "libbb.h" - - -extern int copyfd(int fd1, int fd2) -{ - char buf[8192]; - ssize_t nread, nwrote; - - while (1) { - nread = safe_read(fd1, buf, sizeof(buf)); - if (nread == 0) - break; - if (nread == -1) { - perror_msg("read"); - return -1; - } - - nwrote = full_write(fd2, buf, nread); - if (nwrote == -1) { - perror_msg("write"); - return -1; - } - } - - return 0; -} - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/create_icmp_socket.c b/busybox/libbb/create_icmp_socket.c deleted file mode 100644 index d804b3987..000000000 --- a/busybox/libbb/create_icmp_socket.c +++ /dev/null @@ -1,37 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * create raw socket for icmp protocol test permision - * and drop root privilegies if running setuid - * - */ - -#include -#include -#include -#include -#include -#include "libbb.h" - -int create_icmp_socket(void) -{ - struct protoent *proto; - int sock; - - proto = getprotobyname("icmp"); - /* if getprotobyname failed, just silently force - * proto->p_proto to have the correct value for "icmp" */ - if ((sock = socket(AF_INET, SOCK_RAW, - (proto ? proto->p_proto : 1))) < 0) { /* 1 == ICMP */ - if (errno == EPERM) - error_msg_and_die("permission denied. (are you root?)"); - else - perror_msg_and_die(can_not_create_raw_socket); - } - - /* drop root privs if running setuid */ - setuid(getuid()); - - return sock; -} diff --git a/busybox/libbb/device_open.c b/busybox/libbb/device_open.c deleted file mode 100644 index 8e97ce6c5..000000000 --- a/busybox/libbb/device_open.c +++ /dev/null @@ -1,59 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "libbb.h" - - -/* try to open up the specified device */ -extern int device_open(char *device, int mode) -{ - int m, f, fd = -1; - - m = mode | O_NONBLOCK; - - /* Retry up to 5 times */ - for (f = 0; f < 5; f++) - if ((fd = open(device, m, 0600)) >= 0) - break; - if (fd < 0) - return fd; - /* Reset original flags. */ - if (m != mode) - fcntl(fd, F_SETFL, mode); - return fd; -} - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/dirname.c b/busybox/libbb/dirname.c deleted file mode 100644 index df9a49daa..000000000 --- a/busybox/libbb/dirname.c +++ /dev/null @@ -1,55 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini dirname function. - * - * 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 - */ - -#include -#include "libbb.h" - -#if defined __UCLIBC__ || __GNU_LIBRARY___ < 5 - -/* Return a string containing the path name of the parent - * directory of PATH. */ - -char *dirname(char *path) -{ - char *s; - - /* Go to the end of the string. */ - s = path + strlen(path) - 1; - - /* Strip off trailing /s (unless it is also the leading /). */ - while (path < s && s[0] == '/') - s--; - - /* Strip the last component. */ - while (path <= s && s[0] != '/') - s--; - - while (path < s && s[0] == '/') - s--; - - if (s < path) - return "."; - - s[1] = '\0'; - return path; -} - -#endif diff --git a/busybox/libbb/error_msg.c b/busybox/libbb/error_msg.c deleted file mode 100644 index c7d5fdb98..000000000 --- a/busybox/libbb/error_msg.c +++ /dev/null @@ -1,52 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include -#include "libbb.h" - -extern void error_msg(const char *s, ...) -{ - va_list p; - - va_start(p, s); - verror_msg(s, p); - va_end(p); - putc('\n', stderr); -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/error_msg_and_die.c b/busybox/libbb/error_msg_and_die.c deleted file mode 100644 index b950ee00c..000000000 --- a/busybox/libbb/error_msg_and_die.c +++ /dev/null @@ -1,53 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include -#include "libbb.h" - -extern void error_msg_and_die(const char *s, ...) -{ - va_list p; - - va_start(p, s); - verror_msg(s, p); - va_end(p); - putc('\n', stderr); - exit(EXIT_FAILURE); -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/fgets_str.c b/busybox/libbb/fgets_str.c deleted file mode 100644 index 33d8d00cc..000000000 --- a/busybox/libbb/fgets_str.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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. - */ - - -#include -#include -#include - -/* - * Continue reading from file until the terminating string is encountered. - * Return data as string. - * e.g. fgets_str(file, "\n"); will read till end of file - */ - -char *fgets_str(FILE *file, const char *terminating_string) -{ - char *linebuf = NULL; - const int term_length = strlen(terminating_string); - int end_string_offset; - int linebufsz = 0; - int idx = 0; - int ch; - - while (1) { - ch = fgetc(file); - if (ch == EOF) { - break; - } - - /* grow the line buffer as necessary */ - while (idx > linebufsz - 2) { - linebuf = realloc(linebuf, linebufsz += 1000); /* GROWBY */ - } - - linebuf[idx] = ch; - idx++; - - /* Check for terminating string */ - end_string_offset = idx - term_length; - if ((end_string_offset > 0) && (memcmp(&linebuf[end_string_offset], terminating_string, term_length) == 0)) { - idx -= term_length; - break; - } - } - if (idx == 0) { - return NULL; - } - linebuf[idx] = '\0'; - return(linebuf); -} - diff --git a/busybox/libbb/find_mount_point.c b/busybox/libbb/find_mount_point.c deleted file mode 100644 index 2d9481a69..000000000 --- a/busybox/libbb/find_mount_point.c +++ /dev/null @@ -1,81 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "libbb.h" - - -#include -/* - * Given a block device, find the mount table entry if that block device - * is mounted. - * - * Given any other file (or directory), find the mount table entry for its - * filesystem. - */ -extern struct mntent *find_mount_point(const char *name, const char *table) -{ - struct stat s; - dev_t mountDevice; - FILE *mountTable; - struct mntent *mountEntry; - - if (stat(name, &s) != 0) - return 0; - - if ((s.st_mode & S_IFMT) == S_IFBLK) - mountDevice = s.st_rdev; - else - mountDevice = s.st_dev; - - - if ((mountTable = setmntent(table, "r")) == 0) - return 0; - - while ((mountEntry = getmntent(mountTable)) != 0) { - if (strcmp(name, mountEntry->mnt_dir) == 0 - || strcmp(name, mountEntry->mnt_fsname) == 0) /* String match. */ - break; - if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice) /* Match the device. */ - break; - if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice) /* Match the directory's mount point. */ - break; - } - endmntent(mountTable); - return mountEntry; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/find_pid_by_name.c b/busybox/libbb/find_pid_by_name.c deleted file mode 100644 index 7f39dd41c..000000000 --- a/busybox/libbb/find_pid_by_name.c +++ /dev/null @@ -1,199 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include -#include -#include "libbb.h" - -#define READ_BUF_SIZE 50 - - -/* For Erik's nifty devps device driver */ -#ifdef BB_FEATURE_USE_DEVPS_PATCH -#include - -/* find_pid_by_name() - * - * This finds the pid of the specified process, - * by using the /dev/ps device driver. - * - * Returns a list of all matching PIDs - */ -extern pid_t* find_pid_by_name( char* pidName) -{ - int fd, i, j; - char device[] = "/dev/ps"; - pid_t num_pids; - pid_t* pid_array = NULL; - pid_t* pidList=NULL; - - /* open device */ - fd = open(device, O_RDONLY); - if (fd < 0) - perror_msg_and_die("open failed for `%s'", device); - - /* Find out how many processes there are */ - if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) - perror_msg_and_die("\nDEVPS_GET_PID_LIST"); - - /* Allocate some memory -- grab a few extras just in case - * some new processes start up while we wait. The kernel will - * just ignore any extras if we give it too many, and will trunc. - * the list if we give it too few. */ - pid_array = (pid_t*) xcalloc( num_pids+10, sizeof(pid_t)); - pid_array[0] = num_pids+10; - - /* Now grab the pid list */ - if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) - perror_msg_and_die("\nDEVPS_GET_PID_LIST"); - - /* Now search for a match */ - for (i=1, j=0; id_name, "..") == 0) - continue; - - /* If it isn't a number, we don't want it */ - if (!isdigit(*next->d_name)) - continue; - - sprintf(filename, "/proc/%s/status", next->d_name); - if (! (status = fopen(filename, "r")) ) { - continue; - } - if (fgets(buffer, READ_BUF_SIZE-1, status) == NULL) { - fclose(status); - continue; - } - fclose(status); - - /* Buffer should contain a string like "Name: binary_name" */ - sscanf(buffer, "%*s %s", name); - if (strcmp(name, pidName) == 0) { - pidList=xrealloc( pidList, sizeof(pid_t) * (i+2)); - pidList[i++]=strtol(next->d_name, NULL, 0); - } - } - - if (pidList) - pidList[i]=0; - else if ( strcmp(pidName, "init")==0) { - /* If we found nothing and they were trying to kill "init", - * guess PID 1 and call it good... Perhaps we should simply - * exit if /proc isn't mounted, but this will do for now. */ - pidList=xrealloc( pidList, sizeof(pid_t)); - pidList[0]=1; - } else { - pidList=xrealloc( pidList, sizeof(pid_t)); - pidList[0]=-1; - } - return pidList; -} -#endif /* BB_FEATURE_USE_DEVPS_PATCH */ - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/find_root_device.c b/busybox/libbb/find_root_device.c deleted file mode 100644 index f8f68464d..000000000 --- a/busybox/libbb/find_root_device.c +++ /dev/null @@ -1,84 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Copyright (C) 2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * - * Patched by a bunch of people. Feel free to acknowledge your work. - * - * 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 "libbb.h" - - - -extern char *find_real_root_device_name(const char* name) -{ - DIR *dir; - struct dirent *entry; - struct stat statBuf, rootStat; - char *fileName = NULL; - dev_t dev; - - if (stat("/", &rootStat) != 0) - perror_msg("could not stat '/'"); - else { - if ((dev = rootStat.st_rdev)==0) - dev=rootStat.st_dev; - - dir = opendir("/dev"); - if (!dir) - perror_msg("could not open '/dev'"); - else { - while((entry = readdir(dir)) != NULL) { - - /* Must skip ".." since that is "/", and so we - * would get a false positive on ".." */ - if (strcmp(entry->d_name, "..") == 0) - continue; - - fileName = concat_path_file("/dev", entry->d_name); - - /* Some char devices have the same dev_t as block - * devices, so make sure this is a block device */ - if (stat(fileName, &statBuf) == 0 && - S_ISBLK(statBuf.st_mode)!=0 && - statBuf.st_rdev == dev) - break; - free(fileName); - fileName=NULL; - } - closedir(dir); - } - } - if(fileName==NULL) - fileName=xstrdup("/dev/root"); - return fileName; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/full_read.c b/busybox/libbb/full_read.c deleted file mode 100644 index e9c4bbfc6..000000000 --- a/busybox/libbb/full_read.c +++ /dev/null @@ -1,70 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "libbb.h" - - -/* - * Read all of the supplied buffer from a file. - * This does multiple reads as necessary. - * Returns the amount read, or -1 on an error. - * A short read is returned on an end of file. - */ -int full_read(int fd, char *buf, int len) -{ - int cc; - int total; - - total = 0; - - while (len > 0) { - cc = read(fd, buf, len); - - if (cc < 0) - return -1; - - if (cc == 0) - break; - - buf += cc; - total += cc; - len -= cc; - } - - return total; -} - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/full_write.c b/busybox/libbb/full_write.c deleted file mode 100644 index dc9937fa3..000000000 --- a/busybox/libbb/full_write.c +++ /dev/null @@ -1,66 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "libbb.h" - -/* - * Write all of the supplied buffer out to a file. - * This does multiple writes as necessary. - * Returns the amount written, or -1 on an error. - */ -int full_write(int fd, const char *buf, int len) -{ - int cc; - int total; - - total = 0; - - while (len > 0) { - cc = write(fd, buf, len); - - if (cc < 0) - return -1; - - buf += cc; - total += cc; - len -= cc; - } - - return total; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/get_console.c b/busybox/libbb/get_console.c deleted file mode 100644 index 3b36a59e7..000000000 --- a/busybox/libbb/get_console.c +++ /dev/null @@ -1,129 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include -#include -#include "libbb.h" - - - - - -/* From */ -static const int KDGKBTYPE = 0x4B33; /* get keyboard type */ -static const int KB_84 = 0x01; -static const int KB_101 = 0x02; /* this is what we always answer */ - -int is_a_console(int fd) -{ - char arg; - - arg = 0; - return (ioctl(fd, KDGKBTYPE, &arg) == 0 - && ((arg == KB_101) || (arg == KB_84))); -} - -static int open_a_console(char *fnam) -{ - int fd; - - /* try read-only */ - fd = open(fnam, O_RDWR); - - /* if failed, try read-only */ - if (fd < 0 && errno == EACCES) - fd = open(fnam, O_RDONLY); - - /* if failed, try write-only */ - if (fd < 0 && errno == EACCES) - fd = open(fnam, O_WRONLY); - - /* if failed, fail */ - if (fd < 0) - return -1; - - /* if not a console, fail */ - if (!is_a_console(fd)) { - close(fd); - return -1; - } - - /* success */ - return fd; -} - -/* - * Get an fd for use with kbd/console ioctls. - * We try several things because opening /dev/console will fail - * if someone else used X (which does a chown on /dev/console). - * - * if tty_name is non-NULL, try this one instead. - */ - -int get_console_fd(char *tty_name) -{ - int fd; - - if (tty_name) { - if (-1 == (fd = open_a_console(tty_name))) - return -1; - else - return fd; - } - - fd = open_a_console(CURRENT_TTY); - if (fd >= 0) - return fd; - - fd = open_a_console(CURRENT_VC); - if (fd >= 0) - return fd; - - fd = open_a_console(CONSOLE_DEV); - if (fd >= 0) - return fd; - - for (fd = 0; fd < 3; fd++) - if (is_a_console(fd)) - return fd; - - error_msg("Couldn't get a file descriptor referring to the console"); - return -1; /* total failure */ -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/get_last_path_component.c b/busybox/libbb/get_last_path_component.c deleted file mode 100644 index f1ddfbde0..000000000 --- a/busybox/libbb/get_last_path_component.c +++ /dev/null @@ -1,71 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "libbb.h" - - -char *get_last_path_component(char *path) -{ - char *s; - register char *ptr = path; - register char *prev = 0; - - while (*ptr) - ptr++; - s = ptr - 1; - - /* strip trailing slashes */ - while (s != path && *s == '/') { - *s-- = '\0'; - } - - /* find last component */ - ptr = path; - while (*ptr != '\0') { - if (*ptr == '/') - prev = ptr; - ptr++; - } - s = prev; - - if (s == NULL || s[1] == '\0') - return path; - else - return s+1; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/get_line_from_file.c b/busybox/libbb/get_line_from_file.c deleted file mode 100644 index 759481731..000000000 --- a/busybox/libbb/get_line_from_file.c +++ /dev/null @@ -1,72 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include "libbb.h" - - - -/* get_line_from_file() - This function reads an entire line from a text file - * up to a newline. It returns a malloc'ed char * which must be stored and - * free'ed by the caller. */ -extern char *get_line_from_file(FILE *file) -{ - static const int GROWBY = 80; /* how large we will grow strings by */ - - int ch; - int idx = 0; - char *linebuf = NULL; - int linebufsz = 0; - - while (1) { - ch = fgetc(file); - if (ch == EOF) - break; - /* grow the line buffer as necessary */ - while (idx > linebufsz-2) - linebuf = xrealloc(linebuf, linebufsz += GROWBY); - linebuf[idx++] = (char)ch; - if ((char)ch == '\n') - break; - } - - if (idx == 0) - return NULL; - - linebuf[idx] = 0; - return linebuf; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/gz_open.c b/busybox/libbb/gz_open.c deleted file mode 100644 index ef30ff894..000000000 --- a/busybox/libbb/gz_open.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "libbb.h" - -extern FILE *gz_open(FILE *compressed_file, int *pid) -{ - int unzip_pipe[2]; - - if (pipe(unzip_pipe)!=0) { - error_msg("pipe error"); - return(NULL); - } - if ((*pid = fork()) == -1) { - error_msg("fork failed"); - return(NULL); - } - if (*pid==0) { - /* child process */ - close(unzip_pipe[0]); - unzip(compressed_file, fdopen(unzip_pipe[1], "w")); - fflush(NULL); - fclose(compressed_file); - close(unzip_pipe[1]); - exit(EXIT_SUCCESS); - } - close(unzip_pipe[1]); - if (unzip_pipe[0] == -1) { - error_msg("gzip stream init failed"); - } - return(fdopen(unzip_pipe[0], "r")); -} diff --git a/busybox/libbb/herror_msg.c b/busybox/libbb/herror_msg.c deleted file mode 100644 index f4210edad..000000000 --- a/busybox/libbb/herror_msg.c +++ /dev/null @@ -1,50 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include - -#include "libbb.h" - -extern void herror_msg(const char *s, ...) -{ - va_list p; - - va_start(p, s); - vherror_msg(s, p); - va_end(p); -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/herror_msg_and_die.c b/busybox/libbb/herror_msg_and_die.c deleted file mode 100644 index 0df5ed016..000000000 --- a/busybox/libbb/herror_msg_and_die.c +++ /dev/null @@ -1,51 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include - -#include "libbb.h" - -extern void herror_msg_and_die(const char *s, ...) -{ - va_list p; - - va_start(p, s); - vherror_msg(s, p); - va_end(p); - exit(EXIT_FAILURE); -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/human_readable.c b/busybox/libbb/human_readable.c deleted file mode 100644 index 7bdad36a9..000000000 --- a/busybox/libbb/human_readable.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * June 30, 2001 Manuel Novoa III - * - * All-integer version (hey, not everyone has floating point) of - * make_human_readable_str, modified from similar code I had written - * for busybox several months ago. - * - * Notes: - * 1) I'm using an unsigned long long to hold the product size * block_size, - * as df (which calls this routine) could request a representation of a - * partition size in bytes > max of unsigned long. If long longs aren't - * available, it would be possible to do what's needed using polynomial - * representations (say, powers of 1024) and manipulating coefficients. - * The base ten "bytes" output could be handled similarly. - * - * 2) This routine always outputs a decimal point and a tenths digit when - * display_unit != 0. Hence, it isn't uncommon for the returned string - * to have a length of 5 or 6. - * - * It might be nice to add a flag to indicate no decimal digits in - * that case. This could be either an additional parameter, or a - * special value of display_unit. Such a flag would also be nice for du. - * - * Some code to omit the decimal point and tenths digit is sketched out - * and "#if 0"'d below. - */ - -#include -#include "libbb.h" - -const char *make_human_readable_str(unsigned long size, - unsigned long block_size, - unsigned long display_unit) -{ - /* The code will adjust for additional (appended) units. */ - static const char zero_and_units[] = { '0', 0, 'k', 'M', 'G', 'T' }; - static const char fmt[] = "%Lu"; - static const char fmt_tenths[] = "%Lu.%d%c"; - - static char str[21]; /* Sufficient for 64 bit unsigned integers. */ - - unsigned long long val; - int frac; - const char *u; - const char *f; - - u = zero_and_units; - f = fmt; - frac = 0; - - val = ((unsigned long long) size) * block_size; - if (val == 0) { - return u; - } - - if (display_unit) { - val += display_unit/2; /* Deal with rounding. */ - val /= display_unit; /* Don't combine with the line above!!! */ - } else { - ++u; - while ((val >= KILOBYTE) - && (u < zero_and_units + sizeof(zero_and_units) - 1)) { - f = fmt_tenths; - ++u; - frac = ((((int)(val % KILOBYTE)) * 10) + (KILOBYTE/2)) / KILOBYTE; - val /= KILOBYTE; - } - if (frac >= 10) { /* We need to round up here. */ - ++val; - frac = 0; - } -#if 0 - /* Sample code to omit decimal point and tenths digit. */ - if ( /* no_tenths */ 1 ) { - if ( frac >= 5 ) { - ++val; - } - f = "%Lu%*c" /* fmt_no_tenths */ ; - frac = 1; - } -#endif - } - - /* If f==fmt then 'frac' and 'u' are ignored. */ - snprintf(str, sizeof(str), f, val, frac, *u); - - return str; -} diff --git a/busybox/libbb/inode_hash.c b/busybox/libbb/inode_hash.c deleted file mode 100644 index 790af8f31..000000000 --- a/busybox/libbb/inode_hash.c +++ /dev/null @@ -1,106 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include "libbb.h" - -#define HASH_SIZE 311 /* Should be prime */ -#define hash_inode(i) ((i) % HASH_SIZE) - -static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE]; - -/* - * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in - * `ino_dev_hashtable', else return 0 - * - * If NAME is a non-NULL pointer to a character pointer, and there is - * a match, then set *NAME to the value of the name slot in that - * bucket. - */ -int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name) -{ - ino_dev_hashtable_bucket_t *bucket; - - bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)]; - while (bucket != NULL) { - if ((bucket->ino == statbuf->st_ino) && - (bucket->dev == statbuf->st_dev)) - { - if (name) *name = bucket->name; - return 1; - } - bucket = bucket->next; - } - return 0; -} - -/* Add statbuf to statbuf hash table */ -void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) -{ - int i; - size_t s; - ino_dev_hashtable_bucket_t *bucket; - - i = hash_inode(statbuf->st_ino); - s = name ? strlen(name) : 0; - bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s); - bucket->ino = statbuf->st_ino; - bucket->dev = statbuf->st_dev; - if (name) - strcpy(bucket->name, name); - else - bucket->name[0] = '\0'; - bucket->next = ino_dev_hashtable[i]; - ino_dev_hashtable[i] = bucket; -} - -/* Clear statbuf hash table */ -void reset_ino_dev_hashtable(void) -{ - int i; - ino_dev_hashtable_bucket_t *bucket; - - for (i = 0; i < HASH_SIZE; i++) { - while (ino_dev_hashtable[i] != NULL) { - bucket = ino_dev_hashtable[i]->next; - free(ino_dev_hashtable[i]); - ino_dev_hashtable[i] = bucket; - } - } -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/interface.c b/busybox/libbb/interface.c deleted file mode 100644 index 484597c5f..000000000 --- a/busybox/libbb/interface.c +++ /dev/null @@ -1,2168 +0,0 @@ -/* - * ifconfig This file contains an implementation of the command - * that either displays or sets the characteristics of - * one or more of the system's networking interfaces. - * - * Version: $Id: interface.c,v 1.4 2001/07/19 22:28:02 andersen Exp $ - * - * Author: Fred N. van Kempen, - * and others. Copyright 1993 MicroWalt Corporation - * - * 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. - * - * Patched to support 'add' and 'del' keywords for INET(4) addresses - * by Mrs. Brisby - * - * {1.34} - 19980630 - Arnaldo Carvalho de Melo - * - gettext instead of catgets for i18n - * 10/1998 - Andi Kleen. Use interface list primitives. - * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu - * (default AF was wrong) - * stolen from net-tools-1.59 and stripped down for busybox by - * Erik Andersen - */ - -/* - * Heavily modified by Manuel Novoa III Mar 12, 2001 - * - * Pruned unused code using KEEP_UNUSED define. - * Added print_bytes_scaled function to reduce code size. - * Added some (potentially) missing defines. - * Improved display support for -a and for a named interface. - */ - -/* #define KEEP_UNUSED */ - -/* - * - * Protocol Families. - * - */ -#define HAVE_AFINET 1 -#undef HAVE_AFINET6 -#undef HAVE_AFIPX -#undef HAVE_AFATALK -#undef HAVE_AFNETROM -#undef HAVE_AFX25 -#undef HAVE_AFECONET -#undef HAVE_AFASH - -/* - * - * Device Hardware types. - * - */ -#define HAVE_HWETHER 1 -#define HAVE_HWPPP 1 -#undef HAVE_HWSLIP - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if 0 -#include -#endif -#include "libbb.h" - -#define _(x) x -#define _PATH_PROCNET_DEV "/proc/net/dev" -#define new(p) ((p) = xcalloc(1,sizeof(*(p)))) -#define KRELEASE(maj,min,patch) ((maj) * 65536 + (min)*256 + (patch)) - -static int procnetdev_vsn = 1; - - -/* Ugh. But libc5 doesn't provide POSIX types. */ -#include - - -#ifdef HAVE_HWSLIP -#include -#endif - -#if HAVE_AFINET6 - -#ifndef _LINUX_IN6_H -/* - * This is in linux/include/net/ipv6.h. - */ - -struct in6_ifreq { - struct in6_addr ifr6_addr; - __u32 ifr6_prefixlen; - unsigned int ifr6_ifindex; -}; - -#endif - -#endif /* HAVE_AFINET6 */ - -#if HAVE_AFIPX -#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) -#include -#else -#include "ipx.h" -#endif -#endif -#if 0 -#include "net-support.h" -#include "pathnames.h" -#include "version.h" -#include "../intl.h" -#include "interface.h" -#include "sockets.h" -#include "util.h" -#endif - -/* Defines for glibc2.0 users. */ -#ifndef SIOCSIFTXQLEN -#define SIOCSIFTXQLEN 0x8943 -#define SIOCGIFTXQLEN 0x8942 -#endif - -/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */ -#ifndef ifr_qlen -#define ifr_qlen ifr_ifru.ifru_mtu -#endif - -#ifndef HAVE_TXQUEUELEN -#define HAVE_TXQUEUELEN 1 -#endif - -#ifndef IFF_DYNAMIC -#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */ -#endif - -/* This structure defines protocol families and their handlers. */ -struct aftype { - const char *name; - const char *title; - int af; - int alen; - char *(*print) (unsigned char *); - char *(*sprint) (struct sockaddr *, int numeric); - int (*input) (int type, char *bufp, struct sockaddr *); - void (*herror) (char *text); - int (*rprint) (int options); - int (*rinput) (int typ, int ext, char **argv); - - /* may modify src */ - int (*getmask) (char *src, struct sockaddr * mask, char *name); - - int fd; - char *flag_file; -}; - -static struct aftype *aftypes[]; - -#ifdef KEEP_UNUSED - -static int flag_unx; -#ifdef HAVE_AFIPX -static int flag_ipx; -#endif -#ifdef HAVE_AFX25 -static int flag_ax25; -#endif -#ifdef HAVE_AFATALK -static int flag_ddp; -#endif -#ifdef HAVE_AFNETROM -static int flag_netrom; -#endif -static int flag_inet; -#ifdef HAVE_AFINET6 -static int flag_inet6; -#endif -#ifdef HAVE_AFECONET -static int flag_econet; -#endif -#ifdef HAVE_AFX25 -static int flag_x25 = 0; -#endif -#ifdef HAVE_AFASH -static int flag_ash; -#endif - - -static struct aftrans_t { - char *alias; - char *name; - int *flag; -} aftrans[] = { - -#ifdef HAVE_AFX25 - { - "ax25", "ax25", &flag_ax25 - }, -#endif - { - "ip", "inet", &flag_inet - }, -#ifdef HAVE_AFINET6 - { - "ip6", "inet6", &flag_inet6 - }, -#endif -#ifdef HAVE_AFIPX - { - "ipx", "ipx", &flag_ipx - }, -#endif -#ifdef HAVE_AFATALK - { - "appletalk", "ddp", &flag_ddp - }, -#endif -#ifdef HAVE_AFNETROM - { - "netrom", "netrom", &flag_netrom - }, -#endif - { - "inet", "inet", &flag_inet - }, -#ifdef HAVE_AFINET6 - { - "inet6", "inet6", &flag_inet6 - }, -#endif -#ifdef HAVE_AFATALK - { - "ddp", "ddp", &flag_ddp - }, -#endif - { - "unix", "unix", &flag_unx - }, - { - "tcpip", "inet", &flag_inet - }, -#ifdef HAVE_AFECONET - { - "econet", "ec", &flag_econet - }, -#endif -#ifdef HAVE_AFX25 - { - "x25", "x25", &flag_x25 - }, -#endif -#ifdef HAVE_AFASH - { - "ash", "ash", &flag_ash - }, -#endif - { - 0, 0, 0 - } -}; - -static char afname[256] = ""; -#endif /* KEEP_UNUSED */ - -#if HAVE_AFUNIX - -/* Display a UNIX domain address. */ -static char *UNIX_print(unsigned char *ptr) -{ - return (ptr); -} - - -/* Display a UNIX domain address. */ -static char *UNIX_sprint(struct sockaddr *sap, int numeric) -{ - static char buf[64]; - - if (sap->sa_family == 0xFFFF || sap->sa_family == 0) - return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf)); - return (UNIX_print(sap->sa_data)); -} - - -static struct aftype unix_aftype = -{ - "unix", "UNIX Domain", AF_UNIX, 0, - UNIX_print, UNIX_sprint, NULL, NULL, - NULL, NULL, NULL, - -1, - "/proc/net/unix" -}; -#endif /* HAVE_AFUNIX */ - -#if HAVE_AFINET - -#if 0 -extern int h_errno; /* some netdb.h versions don't export this */ -#endif - -/* cache */ -struct addr { - struct sockaddr_in addr; - char *name; - int host; - struct addr *next; -}; - -static struct addr *INET_nn = NULL; /* addr-to-name cache */ - -#ifdef KEEP_UNUSED -static int INET_resolve(char *name, struct sockaddr_in *sin, int hostfirst) -{ - struct hostent *hp; - struct netent *np; - - /* Grmpf. -FvK */ - sin->sin_family = AF_INET; - sin->sin_port = 0; - - /* Default is special, meaning 0.0.0.0. */ - if (!strcmp(name, "default")) { - sin->sin_addr.s_addr = INADDR_ANY; - return (1); - } - /* Look to see if it's a dotted quad. */ - if (inet_aton(name, &sin->sin_addr)) { - return 0; - } - /* If we expect this to be a hostname, try hostname database first */ -#ifdef DEBUG - if (hostfirst) fprintf (stderr, "gethostbyname (%s)\n", name); -#endif - if (hostfirst && - (hp = gethostbyname(name)) != (struct hostent *) NULL) { - memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], - sizeof(struct in_addr)); - return 0; - } - /* Try the NETWORKS database to see if this is a known network. */ -#ifdef DEBUG - fprintf (stderr, "getnetbyname (%s)\n", name); -#endif - if ((np = getnetbyname(name)) != (struct netent *) NULL) { - sin->sin_addr.s_addr = htonl(np->n_net); - return 1; - } - if (hostfirst) { - /* Don't try again */ - errno = h_errno; - return -1; - } -#ifdef DEBUG - res_init(); - _res.options |= RES_DEBUG; -#endif - -#ifdef DEBUG - fprintf (stderr, "gethostbyname (%s)\n", name); -#endif - if ((hp = gethostbyname(name)) == (struct hostent *) NULL) { - errno = h_errno; - return -1; - } - memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], - sizeof(struct in_addr)); - - return 0; -} -#endif /* KEEP_UNUSED */ - -/* numeric: & 0x8000: default instead of *, - * & 0x4000: host instead of net, - * & 0x0fff: don't resolve - */ -static int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in, - int numeric, unsigned int netmask) -{ - struct hostent *ent; - struct netent *np; - struct addr *pn; - unsigned long ad, host_ad; - int host = 0; - - /* Grmpf. -FvK */ - if (s_in->sin_family != AF_INET) { -#ifdef DEBUG - fprintf(stderr, _("rresolve: unsupport address family %d !\n"), s_in->sin_family); -#endif - errno = EAFNOSUPPORT; - return (-1); - } - ad = (unsigned long) s_in->sin_addr.s_addr; -#ifdef DEBUG - fprintf (stderr, "rresolve: %08lx, mask %08x, num %08x \n", ad, netmask, numeric); -#endif - if (ad == INADDR_ANY) { - if ((numeric & 0x0FFF) == 0) { - if (numeric & 0x8000) - safe_strncpy(name, "default", len); - else - safe_strncpy(name, "*", len); - return (0); - } - } - if (numeric & 0x0FFF) { - safe_strncpy(name, inet_ntoa(s_in->sin_addr), len); - return (0); - } - - if ((ad & (~netmask)) != 0 || (numeric & 0x4000)) - host = 1; -#if 0 - INET_nn = NULL; -#endif - pn = INET_nn; - while (pn != NULL) { - if (pn->addr.sin_addr.s_addr == ad && pn->host == host) { - safe_strncpy(name, pn->name, len); -#ifdef DEBUG - fprintf (stderr, "rresolve: found %s %08lx in cache\n", (host? "host": "net"), ad); -#endif - return (0); - } - pn = pn->next; - } - - host_ad = ntohl(ad); - np = NULL; - ent = NULL; - if (host) { -#ifdef DEBUG - fprintf (stderr, "gethostbyaddr (%08lx)\n", ad); -#endif - ent = gethostbyaddr((char *) &ad, 4, AF_INET); - if (ent != NULL) - safe_strncpy(name, ent->h_name, len); - } else { -#ifdef DEBUG - fprintf (stderr, "getnetbyaddr (%08lx)\n", host_ad); -#endif -#if 0 - np = getnetbyaddr(host_ad, AF_INET); - if (np != NULL) - safe_strncpy(name, np->n_name, len); -#endif - } - if ((ent == NULL) && (np == NULL)) - safe_strncpy(name, inet_ntoa(s_in->sin_addr), len); - pn = (struct addr *) xmalloc(sizeof(struct addr)); - pn->addr = *s_in; - pn->next = INET_nn; - pn->host = host; - pn->name = (char *) xmalloc(strlen(name) + 1); - strcpy(pn->name, name); - INET_nn = pn; - - return (0); -} - -#ifdef KEEP_UNUSED -static void INET_reserror(char *text) -{ - herror(text); -} - -/* Display an Internet socket address. */ -static char *INET_print(unsigned char *ptr) -{ - return (inet_ntoa((*(struct in_addr *) ptr))); -} -#endif /* KEEP_UNUSED */ - -/* Display an Internet socket address. */ -static char *INET_sprint(struct sockaddr *sap, int numeric) -{ - static char buff[128]; - - if (sap->sa_family == 0xFFFF || sap->sa_family == 0) - return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff)); - - if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap, - numeric, 0xffffff00) != 0) - return (NULL); - - return (buff); -} - -#ifdef KEEP_UNUSED -static char *INET_sprintmask(struct sockaddr *sap, int numeric, - unsigned int netmask) -{ - static char buff[128]; - - if (sap->sa_family == 0xFFFF || sap->sa_family == 0) - return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff)); - if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap, - numeric, netmask) != 0) - return (NULL); - return (buff); -} - -static int INET_getsock(char *bufp, struct sockaddr *sap) -{ - char *sp = bufp, *bp; - unsigned int i; - unsigned val; - struct sockaddr_in *sin; - - sin = (struct sockaddr_in *) sap; - sin->sin_family = AF_INET; - sin->sin_port = 0; - - val = 0; - bp = (char *) &val; - for (i = 0; i < sizeof(sin->sin_addr.s_addr); i++) { - *sp = toupper(*sp); - - if ((*sp >= 'A') && (*sp <= 'F')) - bp[i] |= (int) (*sp - 'A') + 10; - else if ((*sp >= '0') && (*sp <= '9')) - bp[i] |= (int) (*sp - '0'); - else - return (-1); - - bp[i] <<= 4; - sp++; - *sp = toupper(*sp); - - if ((*sp >= 'A') && (*sp <= 'F')) - bp[i] |= (int) (*sp - 'A') + 10; - else if ((*sp >= '0') && (*sp <= '9')) - bp[i] |= (int) (*sp - '0'); - else - return (-1); - - sp++; - } - sin->sin_addr.s_addr = htonl(val); - - return (sp - bufp); -} - -static int INET_input(int type, char *bufp, struct sockaddr *sap) -{ - switch (type) { - case 1: - return (INET_getsock(bufp, sap)); - case 256: - return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1)); - default: - return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0)); - } -} - -static int INET_getnetmask(char *adr, struct sockaddr *m, char *name) -{ - struct sockaddr_in *mask = (struct sockaddr_in *) m; - char *slash, *end; - int prefix; - - if ((slash = strchr(adr, '/')) == NULL) - return 0; - - *slash++ = '\0'; - prefix = strtoul(slash, &end, 0); - if (*end != '\0') - return -1; - - if (name) { - sprintf(name, "/%d", prefix); - } - mask->sin_family = AF_INET; - mask->sin_addr.s_addr = htonl(~(0xffffffffU >> prefix)); - return 1; -} -#endif /* KEEP_UNUSED */ - -static struct aftype inet_aftype = -{ - "inet", "DARPA Internet", AF_INET, sizeof(unsigned long), - NULL /* UNUSED INET_print */, INET_sprint, - NULL /* UNUSED INET_input */, NULL /* UNUSED INET_reserror */, - NULL /*INET_rprint */ , NULL /*INET_rinput */ , - NULL /* UNUSED INET_getnetmask */, - -1, - NULL -}; - -#endif /* HAVE_AFINET */ - -/* Display an UNSPEC address. */ -static char *UNSPEC_print(unsigned char *ptr) -{ - static char buff[sizeof(struct sockaddr)*3+1]; - char *pos; - unsigned int i; - - pos = buff; - for (i = 0; i < sizeof(struct sockaddr); i++) { - /* careful -- not every libc's sprintf returns # bytes written */ - sprintf(pos, "%02X-", (*ptr++ & 0377)); - pos += 3; - } - /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */ - *--pos = '\0'; - return (buff); -} - -/* Display an UNSPEC socket address. */ -static char *UNSPEC_sprint(struct sockaddr *sap, int numeric) -{ - static char buf[64]; - - if (sap->sa_family == 0xFFFF || sap->sa_family == 0) - return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf)); - return (UNSPEC_print(sap->sa_data)); -} - -static struct aftype unspec_aftype = -{ - "unspec", "UNSPEC", AF_UNSPEC, 0, - UNSPEC_print, UNSPEC_sprint, NULL, NULL, - NULL, -}; - -static struct aftype *aftypes[] = -{ -#if HAVE_AFUNIX - &unix_aftype, -#endif -#if HAVE_AFINET - &inet_aftype, -#endif -#if HAVE_AFINET6 - &inet6_aftype, -#endif -#if HAVE_AFAX25 - &ax25_aftype, -#endif -#if HAVE_AFNETROM - &netrom_aftype, -#endif -#if HAVE_AFROSE - &rose_aftype, -#endif -#if HAVE_AFIPX - &ipx_aftype, -#endif -#if HAVE_AFATALK - &ddp_aftype, -#endif -#if HAVE_AFECONET - &ec_aftype, -#endif -#if HAVE_AFASH - &ash_aftype, -#endif -#if HAVE_AFX25 - &x25_aftype, -#endif - &unspec_aftype, - NULL -}; - -#ifdef KEEP_UNUSED -static short sVafinit = 0; - -static void afinit() -{ - unspec_aftype.title = _("UNSPEC"); -#if HAVE_AFUNIX - unix_aftype.title = _("UNIX Domain"); -#endif -#if HAVE_AFINET - inet_aftype.title = _("DARPA Internet"); -#endif -#if HAVE_AFINET6 - inet6_aftype.title = _("IPv6"); -#endif -#if HAVE_AFAX25 - ax25_aftype.title = _("AMPR AX.25"); -#endif -#if HAVE_AFNETROM - netrom_aftype.title = _("AMPR NET/ROM"); -#endif -#if HAVE_AFIPX - ipx_aftype.title = _("Novell IPX"); -#endif -#if HAVE_AFATALK - ddp_aftype.title = _("Appletalk DDP"); -#endif -#if HAVE_AFECONET - ec_aftype.title = _("Econet"); -#endif -#if HAVE_AFX25 - x25_aftype.title = _("CCITT X.25"); -#endif -#if HAVE_AFROSE - rose_aftype.title = _("AMPR ROSE"); -#endif -#if HAVE_AFASH - ash_aftype.title = _("Ash"); -#endif - sVafinit = 1; -} - -static int aftrans_opt(const char *arg) -{ - struct aftrans_t *paft; - char *tmp1, *tmp2; - char buf[256]; - - safe_strncpy(buf, arg, sizeof(buf)); - - tmp1 = buf; - - while (tmp1) { - - tmp2 = strchr(tmp1, ','); - - if (tmp2) - *(tmp2++) = '\0'; - - paft = aftrans; - for (paft = aftrans; paft->alias; paft++) { - if (strcmp(tmp1, paft->alias)) - continue; - if (strlen(paft->name) + strlen(afname) + 1 >= sizeof(afname)) { - fprintf(stderr, _("Too much address family arguments.\n")); - return (0); - } - if (paft->flag) - (*paft->flag)++; - if (afname[0]) - strcat(afname, ","); - strcat(afname, paft->name); - break; - } - if (!paft->alias) { - fprintf(stderr, _("Unknown address family `%s'.\n"), tmp1); - return (1); - } - tmp1 = tmp2; - } - - return (0); -} - -/* set the default AF list from the program name or a constant value */ -static void aftrans_def(char *tool, char *argv0, char *dflt) -{ - char *tmp; - char *buf; - - strcpy(afname, dflt); - - if (!(tmp = strrchr(argv0, '/'))) - tmp = argv0; /* no slash?! */ - else - tmp++; - - if (!(buf = strdup(tmp))) - return; - - if (strlen(tool) >= strlen(tmp)) { - free(buf); - return; - } - tmp = buf + (strlen(tmp) - strlen(tool)); - - if (strcmp(tmp, tool) != 0) { - free(buf); - return; - } - *tmp = '\0'; - if ((tmp = strchr(buf, '_'))) - *tmp = '\0'; - - afname[0] = '\0'; - if (aftrans_opt(buf)) - strcpy(afname, buf); - - free(buf); -} - -/* Check our protocol family table for this family. */ -static struct aftype *get_aftype(const char *name) -{ - struct aftype **afp; - -#ifdef KEEP_UNUSED - if (!sVafinit) - afinit(); -#endif /* KEEP_UNUSED */ - - afp = aftypes; - while (*afp != NULL) { - if (!strcmp((*afp)->name, name)) - return (*afp); - afp++; - } - if (strchr(name, ',')) - fprintf(stderr, _("Please don't supply more than one address family.\n")); - return (NULL); -} -#endif /* KEEP_UNUSED */ - -/* Check our protocol family table for this family. */ -static struct aftype *get_afntype(int af) -{ - struct aftype **afp; - -#ifdef KEEP_UNUSED - if (!sVafinit) - afinit(); -#endif /* KEEP_UNUSED */ - - afp = aftypes; - while (*afp != NULL) { - if ((*afp)->af == af) - return (*afp); - afp++; - } - return (NULL); -} - -/* Check our protocol family table for this family and return its socket */ -static int get_socket_for_af(int af) -{ - struct aftype **afp; - -#ifdef KEEP_UNUSED - if (!sVafinit) - afinit(); -#endif /* KEEP_UNUSED */ - - afp = aftypes; - while (*afp != NULL) { - if ((*afp)->af == af) - return (*afp)->fd; - afp++; - } - return -1; -} - -#ifdef KEEP_UNUSED -/* type: 0=all, 1=getroute */ -static void print_aflist(int type) { - int count = 0; - char * txt; - struct aftype **afp; - -#ifdef KEEP_UNUSED - if (!sVafinit) - afinit(); -#endif /* KEEP_UNUSED */ - - afp = aftypes; - while (*afp != NULL) { - if ((type == 1 && ((*afp)->rprint == NULL)) || ((*afp)->af == 0)) { - afp++; continue; - } - if ((count % 3) == 0) fprintf(stderr,count?"\n ":" "); - txt = (*afp)->name; if (!txt) txt = ".."; - fprintf(stderr,"%s (%s) ",txt,_((*afp)->title)); - count++; - afp++; - } - fprintf(stderr,"\n"); -} -#endif /* KEEP_UNUSED */ - -struct user_net_device_stats { - unsigned long long rx_packets; /* total packets received */ - unsigned long long tx_packets; /* total packets transmitted */ - unsigned long long rx_bytes; /* total bytes received */ - unsigned long long tx_bytes; /* total bytes transmitted */ - unsigned long rx_errors; /* bad packets received */ - unsigned long tx_errors; /* packet transmit problems */ - unsigned long rx_dropped; /* no space in linux buffers */ - unsigned long tx_dropped; /* no space available in linux */ - unsigned long rx_multicast; /* multicast packets received */ - unsigned long rx_compressed; - unsigned long tx_compressed; - unsigned long collisions; - - /* detailed rx_errors: */ - unsigned long rx_length_errors; - unsigned long rx_over_errors; /* receiver ring buff overflow */ - unsigned long rx_crc_errors; /* recved pkt with crc error */ - unsigned long rx_frame_errors; /* recv'd frame alignment error */ - unsigned long rx_fifo_errors; /* recv'r fifo overrun */ - unsigned long rx_missed_errors; /* receiver missed packet */ - /* detailed tx_errors */ - unsigned long tx_aborted_errors; - unsigned long tx_carrier_errors; - unsigned long tx_fifo_errors; - unsigned long tx_heartbeat_errors; - unsigned long tx_window_errors; -}; - -struct interface { - struct interface *next, *prev; - char name[IFNAMSIZ]; /* interface name */ - short type; /* if type */ - short flags; /* various flags */ - int metric; /* routing metric */ - int mtu; /* MTU value */ - int tx_queue_len; /* transmit queue length */ - struct ifmap map; /* hardware setup */ - struct sockaddr addr; /* IP address */ - struct sockaddr dstaddr; /* P-P IP address */ - struct sockaddr broadaddr; /* IP broadcast address */ - struct sockaddr netmask; /* IP network mask */ - struct sockaddr ipxaddr_bb; /* IPX network address */ - struct sockaddr ipxaddr_sn; /* IPX network address */ - struct sockaddr ipxaddr_e3; /* IPX network address */ - struct sockaddr ipxaddr_e2; /* IPX network address */ - struct sockaddr ddpaddr; /* Appletalk DDP address */ - struct sockaddr ecaddr; /* Econet address */ - int has_ip; - int has_ipx_bb; - int has_ipx_sn; - int has_ipx_e3; - int has_ipx_e2; - int has_ax25; - int has_ddp; - int has_econet; - char hwaddr[32]; /* HW address */ - int statistics_valid; - struct user_net_device_stats stats; /* statistics */ - int keepalive; /* keepalive value for SLIP */ - int outfill; /* outfill value for SLIP */ -}; - - -int interface_opt_a = 0; /* show all interfaces */ - -#ifdef KEEP_UNUSED -static int opt_i = 0; /* show the statistics */ -static int opt_v = 0; /* debugging output flag */ - -static int addr_family = 0; /* currently selected AF */ -#endif /* KEEP_UNUSED */ - -static struct interface *int_list, *int_last; -static int skfd = -1; /* generic raw socket desc. */ - - -static int sockets_open(int family) -{ - struct aftype **aft; - int sfd = -1; - static int force = -1; - - if (force < 0) { - force = 0; - if (get_kernel_revision() < KRELEASE(2, 1, 0)) - force = 1; - if (access("/proc/net", R_OK)) - force = 1; - } - for (aft = aftypes; *aft; aft++) { - struct aftype *af = *aft; - int type = SOCK_DGRAM; - if (af->af == AF_UNSPEC) - continue; - if (family && family != af->af) - continue; - if (af->fd != -1) { - sfd = af->fd; - continue; - } - /* Check some /proc file first to not stress kmod */ - if (!family && !force && af->flag_file) { - if (access(af->flag_file, R_OK)) - continue; - } -#if HAVE_AFNETROM - if (af->af == AF_NETROM) - type = SOCK_SEQPACKET; -#endif -#if HAVE_AFX25 - if (af->af == AF_X25) - type = SOCK_SEQPACKET; -#endif - af->fd = socket(af->af, type, 0); - if (af->fd >= 0) - sfd = af->fd; - } - if (sfd < 0) - fprintf(stderr, _("No usable address families found.\n")); - return sfd; -} - -/* like strcmp(), but knows about numbers */ -static int nstrcmp(const char *astr, const char *b) -{ - const char *a = astr; - - while (*a == *b) { - if (*a == '\0') - return 0; - a++; - b++; - } - if (isdigit(*a)) { - if (!isdigit(*b)) - return -1; - while (a > astr) { - a--; - if (!isdigit(*a)) { - a++; - break; - } - if (!isdigit(*b)) - return -1; - b--; - } - return atoi(a) > atoi(b) ? 1 : -1; - } - return *a - *b; -} - -static struct interface *add_interface(char *name) -{ - struct interface *ife, **nextp, *new; - - for (ife = int_last; ife; ife = ife->prev) { - int n = nstrcmp(ife->name, name); - if (n == 0) - return ife; - if (n < 0) - break; - } - new(new); - safe_strncpy(new->name, name, IFNAMSIZ); - nextp = ife ? &ife->next : &int_list; - new->prev = ife; - new->next = *nextp; - if (new->next) - new->next->prev = new; - else - int_last = new; - *nextp = new; - return new; -} - - -static int if_readconf(void) -{ - int numreqs = 30; - struct ifconf ifc; - struct ifreq *ifr; - int n, err = -1; - int skfd2; - - /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets - (as of 2.1.128) */ - skfd2 = get_socket_for_af(AF_INET); - if (skfd2 < 0) { - fprintf(stderr, _("warning: no inet socket available: %s\n"), - strerror(errno)); - /* Try to soldier on with whatever socket we can get hold of. */ - skfd2 = sockets_open(0); - if (skfd2 < 0) - return -1; - } - - ifc.ifc_buf = NULL; - for (;;) { - ifc.ifc_len = sizeof(struct ifreq) * numreqs; - ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len); - - if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) { - perror("SIOCGIFCONF"); - goto out; - } - if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) { - /* assume it overflowed and try again */ - numreqs += 10; - continue; - } - break; - } - - ifr = ifc.ifc_req; - for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) { - add_interface(ifr->ifr_name); - ifr++; - } - err = 0; - -out: - free(ifc.ifc_buf); - return err; -} - -static char *get_name(char *name, char *p) -{ - while (isspace(*p)) - p++; - while (*p) { - if (isspace(*p)) - break; - if (*p == ':') { /* could be an alias */ - char *dot = p, *dotname = name; - *name++ = *p++; - while (isdigit(*p)) - *name++ = *p++; - if (*p != ':') { /* it wasn't, backup */ - p = dot; - name = dotname; - } - if (*p == '\0') - return NULL; - p++; - break; - } - *name++ = *p++; - } - *name++ = '\0'; - return p; -} - -static int get_dev_fields(char *bp, struct interface *ife) -{ - switch (procnetdev_vsn) { - case 3: - sscanf(bp, - "%Lu %Lu %lu %lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu %lu", - &ife->stats.rx_bytes, - &ife->stats.rx_packets, - &ife->stats.rx_errors, - &ife->stats.rx_dropped, - &ife->stats.rx_fifo_errors, - &ife->stats.rx_frame_errors, - &ife->stats.rx_compressed, - &ife->stats.rx_multicast, - - &ife->stats.tx_bytes, - &ife->stats.tx_packets, - &ife->stats.tx_errors, - &ife->stats.tx_dropped, - &ife->stats.tx_fifo_errors, - &ife->stats.collisions, - &ife->stats.tx_carrier_errors, - &ife->stats.tx_compressed); - break; - case 2: - sscanf(bp, "%Lu %Lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu", - &ife->stats.rx_bytes, - &ife->stats.rx_packets, - &ife->stats.rx_errors, - &ife->stats.rx_dropped, - &ife->stats.rx_fifo_errors, - &ife->stats.rx_frame_errors, - - &ife->stats.tx_bytes, - &ife->stats.tx_packets, - &ife->stats.tx_errors, - &ife->stats.tx_dropped, - &ife->stats.tx_fifo_errors, - &ife->stats.collisions, - &ife->stats.tx_carrier_errors); - ife->stats.rx_multicast = 0; - break; - case 1: - sscanf(bp, "%Lu %lu %lu %lu %lu %Lu %lu %lu %lu %lu %lu", - &ife->stats.rx_packets, - &ife->stats.rx_errors, - &ife->stats.rx_dropped, - &ife->stats.rx_fifo_errors, - &ife->stats.rx_frame_errors, - - &ife->stats.tx_packets, - &ife->stats.tx_errors, - &ife->stats.tx_dropped, - &ife->stats.tx_fifo_errors, - &ife->stats.collisions, - &ife->stats.tx_carrier_errors); - ife->stats.rx_bytes = 0; - ife->stats.tx_bytes = 0; - ife->stats.rx_multicast = 0; - break; - } - return 0; -} - -static inline int procnetdev_version(char *buf) -{ - if (strstr(buf, "compressed")) - return 3; - if (strstr(buf, "bytes")) - return 2; - return 1; -} - -static int if_readlist_proc(char *target) -{ - static int proc_read; - FILE *fh; - char buf[512]; - struct interface *ife; - int err; - - if (proc_read) - return 0; - if (!target) - proc_read = 1; - - fh = fopen(_PATH_PROCNET_DEV, "r"); - if (!fh) { - fprintf(stderr, _("Warning: cannot open %s (%s). Limited output.\n"), - _PATH_PROCNET_DEV, strerror(errno)); - return if_readconf(); - } - fgets(buf, sizeof buf, fh); /* eat line */ - fgets(buf, sizeof buf, fh); - -#if 0 /* pretty, but can't cope with missing fields */ - fmt = proc_gen_fmt(_PATH_PROCNET_DEV, 1, fh, - "face", "", /* parsed separately */ - "bytes", "%lu", - "packets", "%lu", - "errs", "%lu", - "drop", "%lu", - "fifo", "%lu", - "frame", "%lu", - "compressed", "%lu", - "multicast", "%lu", - "bytes", "%lu", - "packets", "%lu", - "errs", "%lu", - "drop", "%lu", - "fifo", "%lu", - "colls", "%lu", - "carrier", "%lu", - "compressed", "%lu", - NULL); - if (!fmt) - return -1; -#else - procnetdev_vsn = procnetdev_version(buf); -#endif - - err = 0; - while (fgets(buf, sizeof buf, fh)) { - char *s, name[IFNAMSIZ]; - s = get_name(name, buf); - ife = add_interface(name); - get_dev_fields(s, ife); - ife->statistics_valid = 1; - if (target && !strcmp(target,name)) - break; - } - if (ferror(fh)) { - perror(_PATH_PROCNET_DEV); - err = -1; - proc_read = 0; - } - -#if 0 - free(fmt); -#endif - fclose(fh); - return err; -} - -static int if_readlist(void) -{ - int err = if_readlist_proc(NULL); - if (!err) - err = if_readconf(); - return err; -} - -static int for_all_interfaces(int (*doit) (struct interface *, void *), void *cookie) -{ - struct interface *ife; - - if (!int_list && (if_readlist() < 0)) - return -1; - for (ife = int_list; ife; ife = ife->next) { - int err = doit(ife, cookie); - if (err) - return err; - } - return 0; -} - -/* Support for fetching an IPX address */ - -#if HAVE_AFIPX -static int ipx_getaddr(int sock, int ft, struct ifreq *ifr) -{ - ((struct sockaddr_ipx *) &ifr->ifr_addr)->sipx_type = ft; - return ioctl(sock, SIOCGIFADDR, ifr); -} -#endif - - -/* Fetch the interface configuration from the kernel. */ -static int if_fetch(struct interface *ife) -{ - struct ifreq ifr; - int fd; - char *ifname = ife->name; - - strcpy(ifr.ifr_name, ifname); - if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) - return (-1); - ife->flags = ifr.ifr_flags; - - strcpy(ifr.ifr_name, ifname); - if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) - memset(ife->hwaddr, 0, 32); - else - memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8); - - ife->type = ifr.ifr_hwaddr.sa_family; - - strcpy(ifr.ifr_name, ifname); - if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) - ife->metric = 0; - else - ife->metric = ifr.ifr_metric; - - strcpy(ifr.ifr_name, ifname); - if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0) - ife->mtu = 0; - else - ife->mtu = ifr.ifr_mtu; - -#ifdef HAVE_HWSLIP - if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP || - ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 || - ife->type == ARPHRD_ADAPT) { -#ifdef SIOCGOUTFILL - strcpy(ifr.ifr_name, ifname); - if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0) - ife->outfill = 0; - else - ife->outfill = (unsigned int) ifr.ifr_data; -#endif -#ifdef SIOCGKEEPALIVE - strcpy(ifr.ifr_name, ifname); - if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0) - ife->keepalive = 0; - else - ife->keepalive = (unsigned int) ifr.ifr_data; -#endif - } -#endif - - strcpy(ifr.ifr_name, ifname); - if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) - memset(&ife->map, 0, sizeof(struct ifmap)); - else - memcpy(&ife->map, &ifr.ifr_map, sizeof(struct ifmap)); - - strcpy(ifr.ifr_name, ifname); - if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) - memset(&ife->map, 0, sizeof(struct ifmap)); - else - ife->map = ifr.ifr_map; - -#ifdef HAVE_TXQUEUELEN - strcpy(ifr.ifr_name, ifname); - if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0) - ife->tx_queue_len = -1; /* unknown value */ - else - ife->tx_queue_len = ifr.ifr_qlen; -#else - ife->tx_queue_len = -1; /* unknown value */ -#endif - -#if HAVE_AFINET - /* IPv4 address? */ - fd = get_socket_for_af(AF_INET); - if (fd >= 0) { - strcpy(ifr.ifr_name, ifname); - ifr.ifr_addr.sa_family = AF_INET; - if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) { - ife->has_ip = 1; - ife->addr = ifr.ifr_addr; - strcpy(ifr.ifr_name, ifname); - if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0) - memset(&ife->dstaddr, 0, sizeof(struct sockaddr)); - else - ife->dstaddr = ifr.ifr_dstaddr; - - strcpy(ifr.ifr_name, ifname); - if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0) - memset(&ife->broadaddr, 0, sizeof(struct sockaddr)); - else - ife->broadaddr = ifr.ifr_broadaddr; - - strcpy(ifr.ifr_name, ifname); - if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0) - memset(&ife->netmask, 0, sizeof(struct sockaddr)); - else - ife->netmask = ifr.ifr_netmask; - } else - memset(&ife->addr, 0, sizeof(struct sockaddr)); - } -#endif - -#if HAVE_AFATALK - /* DDP address maybe ? */ - fd = get_socket_for_af(AF_APPLETALK); - if (fd >= 0) { - strcpy(ifr.ifr_name, ifname); - if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) { - ife->ddpaddr = ifr.ifr_addr; - ife->has_ddp = 1; - } - } -#endif - -#if HAVE_AFIPX - /* Look for IPX addresses with all framing types */ - fd = get_socket_for_af(AF_IPX); - if (fd >= 0) { - strcpy(ifr.ifr_name, ifname); - if (!ipx_getaddr(fd, IPX_FRAME_ETHERII, &ifr)) { - ife->has_ipx_bb = 1; - ife->ipxaddr_bb = ifr.ifr_addr; - } - strcpy(ifr.ifr_name, ifname); - if (!ipx_getaddr(fd, IPX_FRAME_SNAP, &ifr)) { - ife->has_ipx_sn = 1; - ife->ipxaddr_sn = ifr.ifr_addr; - } - strcpy(ifr.ifr_name, ifname); - if (!ipx_getaddr(fd, IPX_FRAME_8023, &ifr)) { - ife->has_ipx_e3 = 1; - ife->ipxaddr_e3 = ifr.ifr_addr; - } - strcpy(ifr.ifr_name, ifname); - if (!ipx_getaddr(fd, IPX_FRAME_8022, &ifr)) { - ife->has_ipx_e2 = 1; - ife->ipxaddr_e2 = ifr.ifr_addr; - } - } -#endif - -#if HAVE_AFECONET - /* Econet address maybe? */ - fd = get_socket_for_af(AF_ECONET); - if (fd >= 0) { - strcpy(ifr.ifr_name, ifname); - if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) { - ife->ecaddr = ifr.ifr_addr; - ife->has_econet = 1; - } - } -#endif - - return 0; -} - - -static int do_if_fetch(struct interface *ife) -{ - if (if_fetch(ife) < 0) { - char *errmsg; - if (errno == ENODEV) { - /* Give better error message for this case. */ - errmsg = _("Device not found"); - } else { - errmsg = strerror(errno); - } - fprintf(stderr, _("%s: error fetching interface information: %s\n"), - ife->name, errmsg); - return -1; - } - return 0; -} - -/* This structure defines hardware protocols and their handlers. */ -struct hwtype { - const char *name; - const char *title; - int type; - int alen; - char *(*print) (unsigned char *); - int (*input) (char *, struct sockaddr *); - int (*activate) (int fd); - int suppress_null_addr; -}; - -static struct hwtype unspec_hwtype = -{ - "unspec", "UNSPEC", -1, 0, - UNSPEC_print, NULL, NULL -}; - -static struct hwtype loop_hwtype = -{ - "loop", "Local Loopback", ARPHRD_LOOPBACK, 0, - NULL, NULL, NULL -}; - -#if HAVE_HWETHER -#include -#include - -static struct hwtype ether_hwtype; - -/* Display an Ethernet address in readable format. */ -static char *pr_ether(unsigned char *ptr) -{ - static char buff[64]; - - snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X", - (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377), - (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377) - ); - return (buff); -} - -#ifdef KEEP_UNUSED -/* Input an Ethernet address and convert to binary. */ -static int in_ether(char *bufp, struct sockaddr *sap) -{ - unsigned char *ptr; - char c, *orig; - int i; - unsigned val; - - sap->sa_family = ether_hwtype.type; - ptr = sap->sa_data; - - i = 0; - orig = bufp; - while ((*bufp != '\0') && (i < ETH_ALEN)) { - val = 0; - c = *bufp++; - if (isdigit(c)) - val = c - '0'; - else if (c >= 'a' && c <= 'f') - val = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - val = c - 'A' + 10; - else { -#ifdef DEBUG - fprintf(stderr, _("in_ether(%s): invalid ether address!\n"), orig); -#endif - errno = EINVAL; - return (-1); - } - val <<= 4; - c = *bufp; - if (isdigit(c)) - val |= c - '0'; - else if (c >= 'a' && c <= 'f') - val |= c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - val |= c - 'A' + 10; - else if (c == ':' || c == 0) - val >>= 4; - else { -#ifdef DEBUG - fprintf(stderr, _("in_ether(%s): invalid ether address!\n"), orig); -#endif - errno = EINVAL; - return (-1); - } - if (c != 0) - bufp++; - *ptr++ = (unsigned char) (val & 0377); - i++; - - /* We might get a semicolon here - not required. */ - if (*bufp == ':') { - if (i == ETH_ALEN) { -#ifdef DEBUG - fprintf(stderr, _("in_ether(%s): trailing : ignored!\n"), - orig) -#endif - ; /* nothing */ - } - bufp++; - } - } - - /* That's it. Any trailing junk? */ - if ((i == ETH_ALEN) && (*bufp != '\0')) { -#ifdef DEBUG - fprintf(stderr, _("in_ether(%s): trailing junk!\n"), orig); - errno = EINVAL; - return (-1); -#endif - } -#ifdef DEBUG - fprintf(stderr, "in_ether(%s): %s\n", orig, pr_ether(sap->sa_data)); -#endif - - return (0); -} -#endif /* KEEP_UNUSED */ - - -static struct hwtype ether_hwtype = -{ - "ether", "Ethernet", ARPHRD_ETHER, ETH_ALEN, - pr_ether, NULL /* UNUSED in_ether */, NULL -}; - - -#endif /* HAVE_HWETHER */ - - -#if HAVE_HWPPP - -#include - -#ifdef KEEP_UNUSED -/* Start the PPP encapsulation on the file descriptor. */ -static int do_ppp(int fd) -{ - fprintf(stderr, _("You cannot start PPP with this program.\n")); - return -1; -} -#endif /* KEEP_UNUSED */ - -static struct hwtype ppp_hwtype = -{ - "ppp", "Point-Point Protocol", ARPHRD_PPP, 0, - NULL, NULL, NULL /* UNUSED do_ppp */, 0 -}; - - -#endif /* HAVE_PPP */ - -static struct hwtype *hwtypes[] = -{ - - &loop_hwtype, - -#if HAVE_HWSLIP - &slip_hwtype, - &cslip_hwtype, - &slip6_hwtype, - &cslip6_hwtype, - &adaptive_hwtype, -#endif -#if HAVE_HWSTRIP - &strip_hwtype, -#endif -#if HAVE_HWASH - &ash_hwtype, -#endif -#if HAVE_HWETHER - ðer_hwtype, -#endif -#if HAVE_HWTR - &tr_hwtype, -#ifdef ARPHRD_IEEE802_TR - &tr_hwtype1, -#endif -#endif -#if HAVE_HWAX25 - &ax25_hwtype, -#endif -#if HAVE_HWNETROM - &netrom_hwtype, -#endif -#if HAVE_HWROSE - &rose_hwtype, -#endif -#if HAVE_HWTUNNEL - &tunnel_hwtype, -#endif -#if HAVE_HWPPP - &ppp_hwtype, -#endif -#if HAVE_HWHDLCLAPB - &hdlc_hwtype, - &lapb_hwtype, -#endif -#if HAVE_HWARC - &arcnet_hwtype, -#endif -#if HAVE_HWFR - &dlci_hwtype, - &frad_hwtype, -#endif -#if HAVE_HWSIT - &sit_hwtype, -#endif -#if HAVE_HWFDDI - &fddi_hwtype, -#endif -#if HAVE_HWHIPPI - &hippi_hwtype, -#endif -#if HAVE_HWIRDA - &irda_hwtype, -#endif -#if HAVE_HWEC - &ec_hwtype, -#endif -#if HAVE_HWX25 - &x25_hwtype, -#endif - &unspec_hwtype, - NULL -}; - -#ifdef KEEP_UNUSED -static short sVhwinit = 0; - -static void hwinit() -{ - loop_hwtype.title = _("Local Loopback"); - unspec_hwtype.title = _("UNSPEC"); -#if HAVE_HWSLIP - slip_hwtype.title = _("Serial Line IP"); - cslip_hwtype.title = _("VJ Serial Line IP"); - slip6_hwtype.title = _("6-bit Serial Line IP"); - cslip6_hwtype.title = _("VJ 6-bit Serial Line IP"); - adaptive_hwtype.title = _("Adaptive Serial Line IP"); -#endif -#if HAVE_HWETHER - ether_hwtype.title = _("Ethernet"); -#endif -#if HAVE_HWASH - ash_hwtype.title = _("Ash"); -#endif -#if HAVE_HWFDDI - fddi_hwtype.title = _("Fiber Distributed Data Interface"); -#endif -#if HAVE_HWHIPPI - hippi_hwtype.title = _("HIPPI"); -#endif -#if HAVE_HWAX25 - ax25_hwtype.title = _("AMPR AX.25"); -#endif -#if HAVE_HWROSE - rose_hwtype.title = _("AMPR ROSE"); -#endif -#if HAVE_HWNETROM - netrom_hwtype.title = _("AMPR NET/ROM"); -#endif -#if HAVE_HWX25 - x25_hwtype.title = _("generic X.25"); -#endif -#if HAVE_HWTUNNEL - tunnel_hwtype.title = _("IPIP Tunnel"); -#endif -#if HAVE_HWPPP - ppp_hwtype.title = _("Point-to-Point Protocol"); -#endif -#if HAVE_HWHDLCLAPB - hdlc_hwtype.title = _("(Cisco)-HDLC"); - lapb_hwtype.title = _("LAPB"); -#endif -#if HAVE_HWARC - arcnet_hwtype.title = _("ARCnet"); -#endif -#if HAVE_HWFR - dlci_hwtype.title = _("Frame Relay DLCI"); - frad_hwtype.title = _("Frame Relay Access Device"); -#endif -#if HAVE_HWSIT - sit_hwtype.title = _("IPv6-in-IPv4"); -#endif -#if HAVE_HWIRDA - irda_hwtype.title = _("IrLAP"); -#endif -#if HAVE_HWTR - tr_hwtype.title = _("16/4 Mbps Token Ring"); -#ifdef ARPHRD_IEEE802_TR - tr_hwtype1.title = _("16/4 Mbps Token Ring (New)") ; -#endif -#endif -#if HAVE_HWEC - ec_hwtype.title = _("Econet"); -#endif - sVhwinit = 1; -} -#endif /* KEEP_UNUSED */ - -#ifdef IFF_PORTSEL -static const char *if_port_text[][4] = -{ - /* Keep in step with */ - {"unknown", NULL, NULL, NULL}, - {"10base2", "bnc", "coax", NULL}, - {"10baseT", "utp", "tpe", NULL}, - {"AUI", "thick", "db15", NULL}, - {"100baseT", NULL, NULL, NULL}, - {"100baseTX", NULL, NULL, NULL}, - {"100baseFX", NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL}, -}; -#endif - -/* Check our hardware type table for this type. */ -static struct hwtype *get_hwntype(int type) -{ - struct hwtype **hwp; - -#ifdef KEEP_UNUSED - if (!sVhwinit) - hwinit(); -#endif /* KEEP_UNUSED */ - - hwp = hwtypes; - while (*hwp != NULL) { - if ((*hwp)->type == type) - return (*hwp); - hwp++; - } - return (NULL); -} - -/* return 1 if address is all zeros */ -static int hw_null_address(struct hwtype *hw, void *ap) -{ - unsigned int i; - unsigned char *address = (unsigned char *)ap; - for (i = 0; i < hw->alen; i++) - if (address[i]) - return 0; - return 1; -} - -static const char TRext[] = "\0\0k\0M"; - -static void print_bytes_scaled(unsigned long long ull, const char *end) -{ - unsigned long long int_part; - unsigned long frac_part; - const char *ext; - int i; - - frac_part = 0; - ext = TRext; - int_part = ull; - for (i=0 ; i<2 ; i++) { - if (int_part >= 1024) { - frac_part = ((int_part % 1024) * 10) / 1024; - int_part /= 1024; - ext += 2; /* Kb, Mb */ - } - } - - printf("X bytes:%Lu (%Lu.%lu %sb)%s", ull, int_part, frac_part, ext, end); -} - -static void ife_print(struct interface *ptr) -{ - struct aftype *ap; - struct hwtype *hw; - int hf; - int can_compress = 0; - -#if HAVE_AFIPX - static struct aftype *ipxtype = NULL; -#endif -#if HAVE_AFECONET - static struct aftype *ectype = NULL; -#endif -#if HAVE_AFATALK - static struct aftype *ddptype = NULL; -#endif -#if HAVE_AFINET6 - FILE *f; - char addr6[40], devname[20]; - struct sockaddr_in6 sap; - int plen, scope, dad_status, if_idx; - extern struct aftype inet6_aftype; - char addr6p[8][5]; -#endif - - ap = get_afntype(ptr->addr.sa_family); - if (ap == NULL) - ap = get_afntype(0); - - hf = ptr->type; - - if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6) - can_compress = 1; - - hw = get_hwntype(hf); - if (hw == NULL) - hw = get_hwntype(-1); - - printf(_("%-9.9s Link encap:%s "), ptr->name, _(hw->title)); - /* For some hardware types (eg Ash, ATM) we don't print the - hardware address if it's null. */ - if (hw->print != NULL && (! (hw_null_address(hw, ptr->hwaddr) && - hw->suppress_null_addr))) - printf(_("HWaddr %s "), hw->print(ptr->hwaddr)); -#ifdef IFF_PORTSEL - if (ptr->flags & IFF_PORTSEL) { - printf(_("Media:%s"), if_port_text[ptr->map.port][0]); - if (ptr->flags & IFF_AUTOMEDIA) - printf(_("(auto)")); - } -#endif - printf("\n"); - -#if HAVE_AFINET - if (ptr->has_ip) { - printf(_(" %s addr:%s "), ap->name, - ap->sprint(&ptr->addr, 1)); - if (ptr->flags & IFF_POINTOPOINT) { - printf(_(" P-t-P:%s "), ap->sprint(&ptr->dstaddr, 1)); - } - if (ptr->flags & IFF_BROADCAST) { - printf(_(" Bcast:%s "), ap->sprint(&ptr->broadaddr, 1)); - } - printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1)); - } -#endif - -#if HAVE_AFINET6 - /* FIXME: should be integrated into interface.c. */ - - if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) { - while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", - addr6p[0], addr6p[1], addr6p[2], addr6p[3], - addr6p[4], addr6p[5], addr6p[6], addr6p[7], - &if_idx, &plen, &scope, &dad_status, devname) != EOF) { - if (!strcmp(devname, ptr->name)) { - sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", - addr6p[0], addr6p[1], addr6p[2], addr6p[3], - addr6p[4], addr6p[5], addr6p[6], addr6p[7]); - inet6_aftype.input(1, addr6, (struct sockaddr *) &sap); - printf(_(" inet6 addr: %s/%d"), - inet6_aftype.sprint((struct sockaddr *) &sap, 1), plen); - printf(_(" Scope:")); - switch (scope) { - case 0: - printf(_("Global")); - break; - case IPV6_ADDR_LINKLOCAL: - printf(_("Link")); - break; - case IPV6_ADDR_SITELOCAL: - printf(_("Site")); - break; - case IPV6_ADDR_COMPATv4: - printf(_("Compat")); - break; - case IPV6_ADDR_LOOPBACK: - printf(_("Host")); - break; - default: - printf(_("Unknown")); - } - printf("\n"); - } - } - fclose(f); - } -#endif - -#if HAVE_AFIPX - if (ipxtype == NULL) - ipxtype = get_afntype(AF_IPX); - - if (ipxtype != NULL) { - if (ptr->has_ipx_bb) - printf(_(" IPX/Ethernet II addr:%s\n"), - ipxtype->sprint(&ptr->ipxaddr_bb, 1)); - if (ptr->has_ipx_sn) - printf(_(" IPX/Ethernet SNAP addr:%s\n"), - ipxtype->sprint(&ptr->ipxaddr_sn, 1)); - if (ptr->has_ipx_e2) - printf(_(" IPX/Ethernet 802.2 addr:%s\n"), - ipxtype->sprint(&ptr->ipxaddr_e2, 1)); - if (ptr->has_ipx_e3) - printf(_(" IPX/Ethernet 802.3 addr:%s\n"), - ipxtype->sprint(&ptr->ipxaddr_e3, 1)); - } -#endif - -#if HAVE_AFATALK - if (ddptype == NULL) - ddptype = get_afntype(AF_APPLETALK); - if (ddptype != NULL) { - if (ptr->has_ddp) - printf(_(" EtherTalk Phase 2 addr:%s\n"), ddptype->sprint(&ptr->ddpaddr, 1)); - } -#endif - -#if HAVE_AFECONET - if (ectype == NULL) - ectype = get_afntype(AF_ECONET); - if (ectype != NULL) { - if (ptr->has_econet) - printf(_(" econet addr:%s\n"), ectype->sprint(&ptr->ecaddr, 1)); - } -#endif - - printf(" "); - /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */ - if (ptr->flags == 0) - printf(_("[NO FLAGS] ")); - if (ptr->flags & IFF_UP) - printf(_("UP ")); - if (ptr->flags & IFF_BROADCAST) - printf(_("BROADCAST ")); - if (ptr->flags & IFF_DEBUG) - printf(_("DEBUG ")); - if (ptr->flags & IFF_LOOPBACK) - printf(_("LOOPBACK ")); - if (ptr->flags & IFF_POINTOPOINT) - printf(_("POINTOPOINT ")); - if (ptr->flags & IFF_NOTRAILERS) - printf(_("NOTRAILERS ")); - if (ptr->flags & IFF_RUNNING) - printf(_("RUNNING ")); - if (ptr->flags & IFF_NOARP) - printf(_("NOARP ")); - if (ptr->flags & IFF_PROMISC) - printf(_("PROMISC ")); - if (ptr->flags & IFF_ALLMULTI) - printf(_("ALLMULTI ")); - if (ptr->flags & IFF_SLAVE) - printf(_("SLAVE ")); - if (ptr->flags & IFF_MASTER) - printf(_("MASTER ")); - if (ptr->flags & IFF_MULTICAST) - printf(_("MULTICAST ")); -#ifdef HAVE_DYNAMIC - if (ptr->flags & IFF_DYNAMIC) - printf(_("DYNAMIC ")); -#endif - /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */ - printf(_(" MTU:%d Metric:%d"), - ptr->mtu, ptr->metric ? ptr->metric : 1); -#ifdef SIOCSKEEPALIVE - if (ptr->outfill || ptr->keepalive) - printf(_(" Outfill:%d Keepalive:%d"), - ptr->outfill, ptr->keepalive); -#endif - printf("\n"); - - /* If needed, display the interface statistics. */ - - if (ptr->statistics_valid) { - /* XXX: statistics are currently only printed for the primary address, - * not for the aliases, although strictly speaking they're shared - * by all addresses. - */ - printf(" "); - - printf(_("RX packets:%Lu errors:%lu dropped:%lu overruns:%lu frame:%lu\n"), - ptr->stats.rx_packets, ptr->stats.rx_errors, - ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors, - ptr->stats.rx_frame_errors); - if (can_compress) - printf(_(" compressed:%lu\n"), ptr->stats.rx_compressed); - printf(" "); - printf(_("TX packets:%Lu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n"), - ptr->stats.tx_packets, ptr->stats.tx_errors, - ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors, - ptr->stats.tx_carrier_errors); - printf(_(" collisions:%lu "), ptr->stats.collisions); - if (can_compress) - printf(_("compressed:%lu "), ptr->stats.tx_compressed); - if (ptr->tx_queue_len != -1) - printf(_("txqueuelen:%d "), ptr->tx_queue_len); - printf("\n R"); - print_bytes_scaled(ptr->stats.rx_bytes, " T"); - print_bytes_scaled(ptr->stats.tx_bytes, "\n"); - - } - - if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma || - ptr->map.base_addr)) { - printf(" "); - if (ptr->map.irq) - printf(_("Interrupt:%d "), ptr->map.irq); - if (ptr->map.base_addr >= 0x100) /* Only print devices using it for - I/O maps */ - printf(_("Base address:0x%x "), ptr->map.base_addr); - if (ptr->map.mem_start) { - printf(_("Memory:%lx-%lx "), ptr->map.mem_start, ptr->map.mem_end); - } - if (ptr->map.dma) - printf(_("DMA chan:%x "), ptr->map.dma); - printf("\n"); - } - printf("\n"); -} - - -static int do_if_print(struct interface *ife, void *cookie) -{ - int *opt_a = (int *) cookie; - int res; - - res = do_if_fetch(ife); - if (res >= 0) { - if ((ife->flags & IFF_UP) || *opt_a) - ife_print(ife); - } - return res; -} - -static struct interface *lookup_interface(char *name) -{ - struct interface *ife = NULL; - - if (if_readlist_proc(name) < 0) - return NULL; - ife = add_interface(name); - return ife; -} - -/* for ipv4 add/del modes */ -static int if_print(char *ifname) -{ - int res; - - if (!ifname) { - res = for_all_interfaces(do_if_print, &interface_opt_a); - } else { - struct interface *ife; - - ife = lookup_interface(ifname); - res = do_if_fetch(ife); - if (res >= 0) - ife_print(ife); - } - return res; -} - -int display_interfaces(char *ifname) -{ - int status; - - /* Create a channel to the NET kernel. */ - if ((skfd = sockets_open(0)) < 0) { - perror_msg_and_die("socket"); - } - - /* Do we have to show the current setup? */ - status = if_print(ifname); - close(skfd); - exit(status < 0); -} diff --git a/busybox/libbb/isdirectory.c b/busybox/libbb/isdirectory.c deleted file mode 100644 index 65f4fee00..000000000 --- a/busybox/libbb/isdirectory.c +++ /dev/null @@ -1,71 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include "libbb.h" - -/* - * Return TRUE if a fileName is a directory. - * Nonexistant files return FALSE. - */ -int is_directory(const char *fileName, const int followLinks, struct stat *statBuf) -{ - int status; - int didMalloc = 0; - - if (statBuf == NULL) { - statBuf = (struct stat *)xmalloc(sizeof(struct stat)); - ++didMalloc; - } - - if (followLinks == TRUE) - status = stat(fileName, statBuf); - else - status = lstat(fileName, statBuf); - - if (status < 0 || !(S_ISDIR(statBuf->st_mode))) { - status = FALSE; - } - else status = TRUE; - - if (didMalloc) { - free(statBuf); - statBuf = NULL; - } - return status; -} - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/kernel_version.c b/busybox/libbb/kernel_version.c deleted file mode 100644 index 09cd582c4..000000000 --- a/busybox/libbb/kernel_version.c +++ /dev/null @@ -1,66 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include /* for uname(2) */ - -#include "libbb.h" - -/* Returns kernel version encoded as major*65536 + minor*256 + patch, - * so, for example, to check if the kernel is greater than 2.2.11: - * if (get_kernel_revision() <= 2*65536+2*256+11) { } - */ -extern int get_kernel_revision(void) -{ - struct utsname name; - char *s; - int i, r; - - if (uname(&name) == -1) { - perror_msg("cannot get system information"); - return (0); - } - - s = name.release; - r = 0; - for (i=0 ; i<3 ; i++) { - r = r * 256 + atoi(strtok(s, ".")); - s = NULL; - } - return r; -} - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/last_char_is.c b/busybox/libbb/last_char_is.c deleted file mode 100644 index 4e2ee92ed..000000000 --- a/busybox/libbb/last_char_is.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * busybox library eXtended function - * - * Copyright (C) 2001 Larry Doolittle, - * - * 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 "libbb.h" - -/* Find out if the last character of a string matches the one given Don't - * underrun the buffer if the string length is 0. Also avoids a possible - * space-hogging inline of strlen() per usage. - */ -char * last_char_is(const char *s, int c) -{ - char *sret; - if (!s) - return NULL; - sret = (char *)s+strlen(s)-1; - if (sret>=s && *sret == c) { - return sret; - } else { - return NULL; - } -} diff --git a/busybox/libbb/libbb.h b/busybox/libbb/libbb.h deleted file mode 100644 index 30f0bb9a7..000000000 --- a/busybox/libbb/libbb.h +++ /dev/null @@ -1,326 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Busybox main internal header 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ -#ifndef __LIBBB_H__ -#define __LIBBB_H__ 1 - -#include -#include -#include -#include - -#include - -#ifdef DMALLOC -#include "dmalloc.h" -#endif - -#include - -#ifndef _BB_INTERNAL_H_ -#include "../busybox.h" -#endif - -#if (__GNU_LIBRARY__ < 5) && (!defined __dietlibc__) -/* libc5 doesn't define socklen_t */ -typedef unsigned int socklen_t; -/* libc5 doesn't implement BSD 4.4 daemon() */ -extern int daemon (int nochdir, int noclose); -/* libc5 doesn't implement strtok_r */ -char *strtok_r(char *s, const char *delim, char **ptrptr); -#endif - -/* Some useful definitions */ -#define FALSE ((int) 0) -#define TRUE ((int) 1) -#define SKIP ((int) 2) - -/* for mtab.c */ -#define MTAB_GETMOUNTPT '1' -#define MTAB_GETDEVICE '2' - -#define BUF_SIZE 8192 -#define EXPAND_ALLOC 1024 - -static inline int is_decimal(int ch) { return ((ch >= '0') && (ch <= '9')); } -static inline int is_octal(int ch) { return ((ch >= '0') && (ch <= '7')); } - -/* Macros for min/max. */ -#ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) -#endif - -#ifndef MAX -#define MAX(a,b) (((a)>(b))?(a):(b)) -#endif - - - -extern void show_usage(void) __attribute__ ((noreturn)); -extern void error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))); -extern void error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))); -extern void perror_msg(const char *s, ...); -extern void perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn)); -extern void vherror_msg(const char *s, va_list p); -extern void herror_msg(const char *s, ...); -extern void herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn)); - -/* These two are used internally -- you shouldn't need to use them */ -extern void verror_msg(const char *s, va_list p); -extern void vperror_msg(const char *s, va_list p); - -const char *mode_string(int mode); -const char *time_string(time_t timeVal); -int is_directory(const char *name, int followLinks, struct stat *statBuf); -int isDevice(const char *name); - -int remove_file(const char *path, int flags); -int copy_file(const char *source, const char *dest, int flags); -int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize); -char *buildName(const char *dirName, const char *fileName); -int makeString(int argc, const char **argv, char *buf, int bufLen); -char *getChunk(int size); -char *chunkstrdup(const char *str); -void freeChunks(void); -ssize_t safe_read(int fd, void *buf, size_t count); -int full_write(int fd, const char *buf, int len); -int full_read(int fd, char *buf, int len); -int recursive_action(const char *fileName, int recurse, int followLinks, int depthFirst, - int (*fileAction) (const char *fileName, struct stat* statbuf, void* userData), - int (*dirAction) (const char *fileName, struct stat* statbuf, void* userData), - void* userData); - -extern int parse_mode( const char* s, mode_t* theMode); - -extern int get_kernel_revision(void); - -extern int get_console_fd(char* tty_name); -extern struct mntent *find_mount_point(const char *name, const char *table); -extern void write_mtab(char* blockDevice, char* directory, - char* filesystemType, long flags, char* string_flags); -extern void erase_mtab(const char * name); -extern long atoi_w_units (const char *cp); -extern pid_t* find_pid_by_name( char* pidName); -extern char *find_real_root_device_name(const char* name); -extern char *get_line_from_file(FILE *file); -extern void print_file(FILE *file); -extern int copyfd(int fd1, int fd2); -extern int print_file_by_name(char *filename); -extern char process_escape_sequence(const char **ptr); -extern char *get_last_path_component(char *path); -extern FILE *wfopen(const char *path, const char *mode); -extern FILE *xfopen(const char *path, const char *mode); -extern void chomp(char *s); -extern void trim(char *s); -extern struct BB_applet *find_applet_by_name(const char *name); -void run_applet_by_name(const char *name, int argc, char **argv); - -#ifndef DMALLOC -extern void *xmalloc (size_t size); -extern void *xrealloc(void *old, size_t size); -extern void *xcalloc(size_t nmemb, size_t size); -extern char *xstrdup (const char *s); -#endif -extern char *xstrndup (const char *s, int n); -extern char * safe_strncpy(char *dst, const char *src, size_t size); - -struct suffix_mult { - const char *suffix; - int mult; -}; - -extern unsigned long parse_number(const char *numstr, - const struct suffix_mult *suffixes); - - -/* These parse entries in /etc/passwd and /etc/group. This is desirable - * for BusyBox since we want to avoid using the glibc NSS stuff, which - * increases target size and is often not needed embedded systems. */ -extern long my_getpwnam(const char *name); -extern long my_getgrnam(const char *name); -extern void my_getpwuid(char *name, long uid); -extern void my_getgrgid(char *group, long gid); -extern long my_getpwnamegid(const char *name); - -extern int device_open(char *device, int mode); - -extern int del_loop(const char *device); -extern int set_loop(const char *device, const char *file, int offset, int *loopro); -extern char *find_unused_loop_device (void); - - -#if (__GLIBC__ < 2) -extern int vdprintf(int d, const char *format, va_list ap); -#endif - -int nfsmount(const char *spec, const char *node, int *flags, - char **extra_opts, char **mount_opts, int running_bg); - -void syslog_msg_with_name(const char *name, int facility, int pri, const char *msg); -void syslog_msg(int facility, int pri, const char *msg); - -/* Include our own copy of struct sysinfo to avoid binary compatability - * problems with Linux 2.4, which changed things. Grumble, grumble. */ -struct sysinfo { - long uptime; /* Seconds since boot */ - unsigned long loads[3]; /* 1, 5, and 15 minute load averages */ - unsigned long totalram; /* Total usable main memory size */ - unsigned long freeram; /* Available memory size */ - unsigned long sharedram; /* Amount of shared memory */ - unsigned long bufferram; /* Memory used by buffers */ - unsigned long totalswap; /* Total swap space size */ - unsigned long freeswap; /* swap space still available */ - unsigned short procs; /* Number of current processes */ - unsigned short pad; /* Padding needed for m68k */ - unsigned long totalhigh; /* Total high memory size */ - unsigned long freehigh; /* Available high memory size */ - unsigned int mem_unit; /* Memory unit size in bytes */ - char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */ -}; -extern int sysinfo (struct sysinfo* info); - -enum { - KILOBYTE = 1024, - MEGABYTE = (KILOBYTE*1024), - GIGABYTE = (MEGABYTE*1024) -}; -const char *make_human_readable_str(unsigned long size, unsigned long block_size, unsigned long display_unit); - -int ask_confirmation(void); -int klogctl(int type, char * b, int len); - -char *xgetcwd(char *cwd); -char *xreadlink(const char *path); -char *concat_path_file(const char *path, const char *filename); -char *last_char_is(const char *s, int c); - -extern long arith (const char *startbuf, int *errcode); - -typedef struct file_headers_s { - char *name; - char *link_name; - off_t size; - uid_t uid; - gid_t gid; - mode_t mode; - time_t mtime; - dev_t device; -} file_header_t; -file_header_t *get_header_ar(FILE *in_file); -file_header_t *get_header_cpio(FILE *src_stream); -file_header_t *get_header_tar(FILE *tar_stream); - -enum extract_functions_e { - extract_verbose_list = 1, - extract_list = 2, - extract_one_to_buffer = 4, - extract_to_stdout = 8, - extract_all_to_fs = 16, - extract_preserve_date = 32, - extract_data_tar_gz = 64, - extract_control_tar_gz = 128, - extract_unzip_only = 256, - extract_unconditional = 512, - extract_create_leading_dirs = 1024, - extract_quiet = 2048, - extract_exclude_list = 4096 -}; -char *unarchive(FILE *src_stream, FILE *out_stream, file_header_t *(*get_header)(FILE *), - const int extract_function, const char *prefix, char **extract_names); -char *deb_extract(const char *package_filename, FILE *out_stream, const int extract_function, - const char *prefix, const char *filename); -int read_package_field(const char *package_buffer, char **field_name, char **field_value); -char *fgets_str(FILE *file, const char *terminating_string); - -extern int unzip(FILE *l_in_file, FILE *l_out_file); -extern void gz_close(int gunzip_pid); -extern FILE *gz_open(FILE *compressed_file, int *pid); - -extern struct hostent *xgethostbyname(const char *name); -extern int create_icmp_socket(void); - -char *dirname (char *path); - -int make_directory (char *path, long mode, int flags); - -const char *u_signal_names(const char *str_sig, int *signo, int startnum); -char *simplify_path(const char *path); - -#define CT_AUTO 0 -#define CT_UNIX2DOS 1 -#define CT_DOS2UNIX 2 -/* extern int convert(char *fn, int ConvType); */ - -enum { - FILEUTILS_PRESERVE_STATUS = 1, - FILEUTILS_PRESERVE_SYMLINKS = 2, - FILEUTILS_RECUR = 4, - FILEUTILS_FORCE = 8, - FILEUTILS_INTERACTIVE = 16 -}; - -extern const char *applet_name; -extern const char * const full_version; -extern const char * const name_too_long; -extern const char * const omitting_directory; -extern const char * const not_a_directory; -extern const char * const memory_exhausted; -extern const char * const invalid_date; -extern const char * const invalid_option; -extern const char * const io_error; -extern const char * const dash_dash_help; -extern const char * const write_error; -extern const char * const too_few_args; -extern const char * const name_longer_than_foo; -extern const char * const unknown; -extern const char * const can_not_create_raw_socket; - -#ifdef BB_FEATURE_DEVFS -# define CURRENT_VC "/dev/vc/0" -# define VC_1 "/dev/vc/1" -# define VC_2 "/dev/vc/2" -# define VC_3 "/dev/vc/3" -# define VC_4 "/dev/vc/4" -# define VC_5 "/dev/vc/5" -# define SC_0 "/dev/tts/0" -# define SC_1 "/dev/tts/1" -# define VC_FORMAT "/dev/vc/%d" -# define SC_FORMAT "/dev/tts/%d" -#else -# define CURRENT_VC "/dev/tty0" -# define VC_1 "/dev/tty1" -# define VC_2 "/dev/tty2" -# define VC_3 "/dev/tty3" -# define VC_4 "/dev/tty4" -# define VC_5 "/dev/tty5" -# define SC_0 "/dev/ttyS0" -# define SC_1 "/dev/ttyS1" -# define VC_FORMAT "/dev/tty%d" -# define SC_FORMAT "/dev/ttyS%d" -#endif - -/* The following devices are the same on devfs and non-devfs systems. */ -#define CURRENT_TTY "/dev/tty" -#define CONSOLE_DEV "/dev/console" - -#endif /* __LIBBB_H__ */ diff --git a/busybox/libbb/libc5.c b/busybox/libbb/libc5.c deleted file mode 100644 index 20295fd4b..000000000 --- a/busybox/libbb/libc5.c +++ /dev/null @@ -1,167 +0,0 @@ -/* vi: set sw=4 ts=4: */ - - -#include -#include -#include -#include -#include -#include - - -#if __GNU_LIBRARY__ < 5 - - -/* Copyright (C) 1991 Free Software Foundation, Inc. -This file is part of the GNU C Library. - -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -The GNU C Library 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 Library General Public -License along with the GNU C Library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - -/* - * Modified by Manuel Novoa III Mar 1, 2001 - * - * Converted original strtok.c code of strtok to __strtok_r. - * Cleaned up logic and reduced code size. - */ - - -char *strtok_r(char *s, const char *delim, char **save_ptr) -{ - char *token; - - token = 0; /* Initialize to no token. */ - - if (s == 0) { /* If not first time called... */ - s = *save_ptr; /* restart from where we left off. */ - } - - if (s != 0) { /* If not finished... */ - *save_ptr = 0; - - s += strspn(s, delim); /* Skip past any leading delimiters. */ - if (*s != '\0') { /* We have a token. */ - token = s; - *save_ptr = strpbrk(token, delim); /* Find token's end. */ - if (*save_ptr != 0) { - /* Terminate the token and make SAVE_PTR point past it. */ - *(*save_ptr)++ = '\0'; - } - } - } - - return token; -} - -/* Basically getdelim() with the delimiter hard wired to '\n' */ -ssize_t getline(char **linebuf, size_t *n, FILE *file) -{ - return (getdelim (linebuf, n, '\n', file)); -} - - -/* - * daemon implementation for uClibc - * - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Modified for uClibc by Erik Andersen - * , - * - * The uClibc Library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * The GNU C Library 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 Library General Public - * License along with the GNU C Library; see the file COPYING.LIB. 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. - */ - -int daemon( int nochdir, int noclose ) -{ - int fd; - - switch (fork()) { - case -1: - return(-1); - case 0: - break; - default: - _exit(0); - } - - if (setsid() == -1) - return(-1); - - if (!nochdir) - chdir("/"); - - if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - if (fd > 2) - close(fd); - } - return(0); -} - - -/*- - * Copyright (c) 1990, 1993 - * The 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. - */ - - -#endif - diff --git a/busybox/libbb/loop.c b/busybox/libbb/loop.c deleted file mode 100644 index 4754b8da1..000000000 --- a/busybox/libbb/loop.c +++ /dev/null @@ -1,128 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include -#include -#include -#include "libbb.h" -#include "loop.h" /* Pull in loop device support */ - -extern int del_loop(const char *device) -{ - int fd; - - if ((fd = open(device, O_RDONLY)) < 0) { - perror_msg("%s", device); - return (FALSE); - } - if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { - perror_msg("ioctl: LOOP_CLR_FD"); - return (FALSE); - } - close(fd); - return (TRUE); -} - -extern int set_loop(const char *device, const char *file, int offset, - int *loopro) -{ - struct loop_info loopinfo; - int fd, ffd, mode; - - mode = *loopro ? O_RDONLY : O_RDWR; - if ((ffd = open(file, mode)) < 0 && !*loopro - && (errno != EROFS || (ffd = open(file, mode = O_RDONLY)) < 0)) { - perror_msg("%s", file); - return 1; - } - if ((fd = open(device, mode)) < 0) { - close(ffd); - perror_msg("%s", device); - return 1; - } - *loopro = (mode == O_RDONLY); - - memset(&loopinfo, 0, sizeof(loopinfo)); - safe_strncpy(loopinfo.lo_name, file, LO_NAME_SIZE); - - loopinfo.lo_offset = offset; - - loopinfo.lo_encrypt_key_size = 0; - if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { - perror_msg("ioctl: LOOP_SET_FD"); - close(fd); - close(ffd); - return 1; - } - if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) { - (void) ioctl(fd, LOOP_CLR_FD, 0); - perror_msg("ioctl: LOOP_SET_STATUS"); - close(fd); - close(ffd); - return 1; - } - close(fd); - close(ffd); - return 0; -} - -extern char *find_unused_loop_device(void) -{ - char dev[20]; - int i, fd; - struct stat statbuf; - struct loop_info loopinfo; - - for (i = 0; i <= 7; i++) { - sprintf(dev, "/dev/loop%d", i); - if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { - if ((fd = open(dev, O_RDONLY)) >= 0) { - if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) != 0) { - if (errno == ENXIO) { /* probably free */ - close(fd); - return strdup(dev); - } - } - close(fd); - } - } - } - return NULL; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/make_directory.c b/busybox/libbb/make_directory.c deleted file mode 100644 index a06a410d2..000000000 --- a/busybox/libbb/make_directory.c +++ /dev/null @@ -1,71 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini make_directory implementation for busybox - * - * 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 - * - */ - -#include -#include -#include -#include -#include -#include - -#include "libbb.h" - -/* Create the directory PATH with mode MODE, or the default if MODE is -1. - * Also create parent directories as necessary if flags contains - * FILEUTILS_RECUR. */ - -int make_directory (char *path, long mode, int flags) -{ - if (!(flags & FILEUTILS_RECUR)) { - if (mkdir (path, 0777) < 0) { - perror_msg ("Cannot create directory `%s'", path); - return -1; - } - - if (mode != -1 && chmod (path, mode) < 0) { - perror_msg ("Cannot set permissions of directory `%s'", path); - return -1; - } - } else { - struct stat st; - - if (stat (path, &st) < 0 && errno == ENOENT) { - int status; - char *buf, *parent; - mode_t mask; - - mask = umask (0); - umask (mask); - - buf = xstrdup (path); - parent = dirname (buf); - status = make_directory (parent, (0777 & ~mask) | 0300, - FILEUTILS_RECUR); - free (buf); - - if (status < 0 || make_directory (path, mode, 0) < 0) - return -1; - } - } - - return 0; -} diff --git a/busybox/libbb/messages.c b/busybox/libbb/messages.c deleted file mode 100644 index 552c3ab5b..000000000 --- a/busybox/libbb/messages.c +++ /dev/null @@ -1,67 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Copyright (C) 2001 by Lineo, inc. - * Written 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 - * - */ - -#include "libbb.h" - -#ifdef L_full_version - const char * const full_version = BB_BANNER " multi-call binary"; -#endif -#ifdef L_name_too_long - const char * const name_too_long = "file name too long"; -#endif - -#ifdef L_omitting_directory - const char * const omitting_directory = "%s: omitting directory"; -#endif -#ifdef L_not_a_directory - const char * const not_a_directory = "%s: not a directory"; -#endif -#ifdef L_memory_exhausted - const char * const memory_exhausted = "memory exhausted"; -#endif -#ifdef L_invalid_date - const char * const invalid_date = "invalid date `%s'"; -#endif -#ifdef L_invalid_option - const char * const invalid_option = "invalid option -- %c"; -#endif -#ifdef L_io_error - const char * const io_error = "%s: input/output error -- %s"; -#endif -#ifdef L_dash_dash_help - const char * const dash_dash_help = "--help"; -#endif -#ifdef L_write_error - const char * const write_error = "Write Error"; -#endif -#ifdef L_too_few_args - const char * const too_few_args = "too few arguments"; -#endif -#ifdef L_name_longer_than_foo - const char * const name_longer_than_foo = "Names longer than %d chars not supported."; -#endif -#ifdef L_unknown - const char * const unknown = "(unknown)"; -#endif - -#ifdef L_can_not_create_raw_socket - const char * const can_not_create_raw_socket = "can`t create raw socket"; -#endif diff --git a/busybox/libbb/mk_loop_h.sh b/busybox/libbb/mk_loop_h.sh deleted file mode 100755 index 71c987376..000000000 --- a/busybox/libbb/mk_loop_h.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh -# -# Figure out (i) the type of dev_t (ii) the defines for loop stuff -# -# Output of this script is normally redirected to "loop.h". - -# Since 1.3.79 there is an include file -# that defines __kernel_dev_t. -# (The file itself appeared in 1.3.78, but there it defined __dev_t.) -# If it exists, we use it, or, rather, which -# avoids namespace pollution. Otherwise we guess that __kernel_dev_t -# is an unsigned short (which is true on i386, but false on alpha). - -# BUG: This test is actually broken if your gcc is not configured to -# search /usr/include, as may well happen with cross-compilers. -# It would be better to ask $(CC) if these files can be found. - -if [ -f /usr/include/linux/posix_types.h ]; then - echo '#include ' - echo '#undef dev_t' - echo '#define dev_t __kernel_dev_t' -else - echo '#undef dev_t' - echo '#define dev_t unsigned short' -fi - -# Next we have to find the loop stuff itself. -# First try kernel source, then a private version. - -if [ -f /usr/include/linux/loop.h ]; then - echo '#include ' -else - echo '#include "real_loop.h"' -fi - -echo '#undef dev_t' - diff --git a/busybox/libbb/mode_string.c b/busybox/libbb/mode_string.c deleted file mode 100644 index 0a3d6e6f0..000000000 --- a/busybox/libbb/mode_string.c +++ /dev/null @@ -1,82 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include "libbb.h" - - - -#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f) -#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)]) - -/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */ -static const mode_t SBIT[] = { - 0, 0, S_ISUID, - 0, 0, S_ISGID, - 0, 0, S_ISVTX -}; - -/* The 9 mode bits to test */ -static const mode_t MBIT[] = { - S_IRUSR, S_IWUSR, S_IXUSR, - S_IRGRP, S_IWGRP, S_IXGRP, - S_IROTH, S_IWOTH, S_IXOTH -}; - -static const char MODE1[] = "rwxrwxrwx"; -static const char MODE0[] = "---------"; -static const char SMODE1[] = "..s..s..t"; -static const char SMODE0[] = "..S..S..T"; - -/* - * Return the standard ls-like mode string from a file mode. - * This is static and so is overwritten on each call. - */ -const char *mode_string(int mode) -{ - static char buf[12]; - - int i; - - buf[0] = TYPECHAR(mode); - for (i = 0; i < 9; i++) { - if (mode & SBIT[i]) - buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i]; - else - buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i]; - } - return buf; -} - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/module_syscalls.c b/busybox/libbb/module_syscalls.c deleted file mode 100644 index 8326f15ad..000000000 --- a/busybox/libbb/module_syscalls.c +++ /dev/null @@ -1,88 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * some system calls possibly missing from libc - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -/* Kernel headers before 2.1.mumble need this on the Alpha to get - _syscall* defined. */ -#define __LIBRARY__ -#include -#ifndef __UCLIBC__ -#include -#endif -#include "libbb.h" - - -#if __GNU_LIBRARY__ < 5 || ((__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)) -/* These syscalls are not included as part of libc5 */ -_syscall1(int, delete_module, const char *, name); -_syscall1(int, get_kernel_syms, __ptr_t, ks); - -/* This may have 5 arguments (for old 2.0 kernels) or 2 arguments - * (for 2.2 and 2.4 kernels). Use the greatest common denominator, - * and let the kernel cope with whatever it gets. Its good at that. */ -_syscall5(int, init_module, void *, first, void *, second, void *, third, - void *, fourth, void *, fifth); - -#ifndef __NR_query_module -#warning This kernel does not support the query_module syscall -#warning -> The query_module system call is being stubbed out... -int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret) -{ - fprintf(stderr, "\n\nTo make this application work, you will need to recompile\n"); - fprintf(stderr, "with a kernel supporting the query_module system call. -Erik\n\n"); - errno=ENOSYS; - return -1; -} -#else -_syscall5(int, query_module, const char *, name, int, which, - void *, buf, size_t, bufsize, size_t*, ret); -#endif - -/* Jump through hoops to fixup error return codes */ -#define __NR___create_module __NR_create_module -static inline _syscall2(long, __create_module, const char *, name, size_t, size) -unsigned long create_module(const char *name, size_t size) -{ - long ret = __create_module(name, size); - - if (ret == -1 && errno > 125) { - ret = -errno; - errno = 0; - } - return ret; -} - -#endif /* __GNU_LIBRARY__ < 5 */ - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ - diff --git a/busybox/libbb/mtab.c b/busybox/libbb/mtab.c deleted file mode 100644 index 28c9978ef..000000000 --- a/busybox/libbb/mtab.c +++ /dev/null @@ -1,95 +0,0 @@ -/* vi: set sw=4 ts=4: */ -#include -#include -#include -#include -#include -#include -#include "libbb.h" - -extern const char mtab_file[]; /* Defined in utility.c */ -static const int MS_RDONLY = 1; /* Mount read-only. */ - -void erase_mtab(const char *name) -{ - struct mntent entries[20]; - int count = 0; - FILE *mountTable = setmntent(mtab_file, "r"); - struct mntent *m; - - /* Check if reading the mtab file failed */ - if (mountTable == 0 - /* Bummer. fall back on trying the /proc filesystem */ - && (mountTable = setmntent("/proc/mounts", "r")) == 0) { - perror_msg("%s", mtab_file); - return; - } - - while ((m = getmntent(mountTable)) != 0) { - entries[count].mnt_fsname = strdup(m->mnt_fsname); - entries[count].mnt_dir = strdup(m->mnt_dir); - entries[count].mnt_type = strdup(m->mnt_type); - entries[count].mnt_opts = strdup(m->mnt_opts); - entries[count].mnt_freq = m->mnt_freq; - entries[count].mnt_passno = m->mnt_passno; - count++; - } - endmntent(mountTable); - if ((mountTable = setmntent(mtab_file, "w"))) { - int i; - - for (i = 0; i < count; i++) { - int result = (strcmp(entries[i].mnt_fsname, name) == 0 - || strcmp(entries[i].mnt_dir, name) == 0); - - if (result) - continue; - else - addmntent(mountTable, &entries[i]); - } - endmntent(mountTable); - } else if (errno != EROFS) - perror_msg("%s", mtab_file); -} - -void write_mtab(char *blockDevice, char *directory, - char *filesystemType, long flags, char *string_flags) -{ - FILE *mountTable = setmntent(mtab_file, "a+"); - struct mntent m; - - if (mountTable == 0) { - perror_msg("%s", mtab_file); - return; - } - if (mountTable) { - int length = strlen(directory); - - if (length > 1 && directory[length - 1] == '/') - directory[length - 1] = '\0'; - - if (filesystemType == 0) { - struct mntent *p = find_mount_point(blockDevice, "/proc/mounts"); - - if (p && p->mnt_type) - filesystemType = p->mnt_type; - } - m.mnt_fsname = blockDevice; - m.mnt_dir = directory; - m.mnt_type = filesystemType ? filesystemType : "default"; - - if (*string_flags) { - m.mnt_opts = string_flags; - } else { - if ((flags | MS_RDONLY) == flags) - m.mnt_opts = "ro"; - else - m.mnt_opts = "rw"; - } - - m.mnt_freq = 0; - m.mnt_passno = 0; - addmntent(mountTable, &m); - endmntent(mountTable); - } -} diff --git a/busybox/libbb/mtab_file.c b/busybox/libbb/mtab_file.c deleted file mode 100644 index 56f8e06ab..000000000 --- a/busybox/libbb/mtab_file.c +++ /dev/null @@ -1,52 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include "libbb.h" - - -/* Busybox mount uses either /proc/mounts or /dev/mtab to - * get the list of currently mounted filesystems */ -#if defined BB_FEATURE_MTAB_SUPPORT -const char mtab_file[] = "/etc/mtab"; -#else -# if defined BB_FEATURE_USE_DEVPS_PATCH - const char mtab_file[] = "/dev/mtab"; -# else - const char mtab_file[] = "/proc/mounts"; -# endif -#endif - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/my_getgrgid.c b/busybox/libbb/my_getgrgid.c deleted file mode 100644 index fabd4776c..000000000 --- a/busybox/libbb/my_getgrgid.c +++ /dev/null @@ -1,55 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "../pwd_grp/pwd.h" -#include "../pwd_grp/grp.h" -#include "libbb.h" - - -/* gets a groupname given a gid */ -void my_getgrgid(char *group, long gid) -{ - struct group *mygroup; - - mygroup = getgrgid(gid); - if (mygroup==NULL) - sprintf(group, "%-8ld ", (long)gid); - else - strcpy(group, mygroup->gr_name); -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/my_getgrnam.c b/busybox/libbb/my_getgrnam.c deleted file mode 100644 index e3226a275..000000000 --- a/busybox/libbb/my_getgrnam.c +++ /dev/null @@ -1,56 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "../pwd_grp/pwd.h" -#include "../pwd_grp/grp.h" -#include "libbb.h" - - - -/* returns a gid given a group name */ -long my_getgrnam(const char *name) -{ - struct group *mygroup; - - mygroup = getgrnam(name); - if (mygroup==NULL) - error_msg_and_die("unknown group name: %s", name); - - return (mygroup->gr_gid); -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/my_getpwnam.c b/busybox/libbb/my_getpwnam.c deleted file mode 100644 index ae73ae7f1..000000000 --- a/busybox/libbb/my_getpwnam.c +++ /dev/null @@ -1,56 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "../pwd_grp/pwd.h" -#include "../pwd_grp/grp.h" -#include "libbb.h" - - - -/* returns a uid given a username */ -long my_getpwnam(const char *name) -{ - struct passwd *myuser; - - myuser = getpwnam(name); - if (myuser==NULL) - error_msg_and_die("unknown user name: %s", name); - - return myuser->pw_uid; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/my_getpwnamegid.c b/busybox/libbb/my_getpwnamegid.c deleted file mode 100644 index fb3d148ce..000000000 --- a/busybox/libbb/my_getpwnamegid.c +++ /dev/null @@ -1,61 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "../pwd_grp/pwd.h" -#include "../pwd_grp/grp.h" -#include "libbb.h" - - - -/* gets a gid given a user name */ -long my_getpwnamegid(const char *name) -{ - struct group *mygroup; - struct passwd *myuser; - - myuser=getpwnam(name); - if (myuser==NULL) - error_msg_and_die("unknown user name: %s", name); - - mygroup = getgrgid(myuser->pw_gid); - if (mygroup==NULL) - error_msg_and_die("unknown gid %ld", (long)myuser->pw_gid); - - return mygroup->gr_gid; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/my_getpwuid.c b/busybox/libbb/my_getpwuid.c deleted file mode 100644 index 46c7a884a..000000000 --- a/busybox/libbb/my_getpwuid.c +++ /dev/null @@ -1,55 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "../pwd_grp/pwd.h" -#include "../pwd_grp/grp.h" -#include "libbb.h" - - - -/* gets a username given a uid */ -void my_getpwuid(char *name, long uid) -{ - struct passwd *myuser; - - myuser = getpwuid(uid); - if (myuser==NULL) - sprintf(name, "%-8ld ", (long)uid); - else - strcpy(name, myuser->pw_name); -} - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/parse_mode.c b/busybox/libbb/parse_mode.c deleted file mode 100644 index 30d2f21cf..000000000 --- a/busybox/libbb/parse_mode.c +++ /dev/null @@ -1,138 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "libbb.h" - - -/* This function parses the sort of string you might pass - * to chmod (i.e., [ugoa]{+|-|=}[rwxst] ) and returns the - * correct mode described by the string. */ -extern int parse_mode(const char *s, mode_t * theMode) -{ - static const mode_t group_set[] = { - S_ISUID | S_IRWXU, /* u */ - S_ISGID | S_IRWXG, /* g */ - S_IRWXO, /* o */ - S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO /* a */ - }; - - static const mode_t mode_set[] = { - S_IRUSR | S_IRGRP | S_IROTH, /* r */ - S_IWUSR | S_IWGRP | S_IWOTH, /* w */ - S_IXUSR | S_IXGRP | S_IXOTH, /* x */ - S_ISUID | S_ISGID, /* s */ - S_ISVTX /* t */ - }; - - static const char group_chars[] = "ugoa"; - static const char mode_chars[] = "rwxst"; - - const char *p; - - mode_t andMode = - S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; - mode_t orMode = 0; - mode_t mode; - mode_t groups; - char type; - char c; - - if (s==NULL) { - return (FALSE); - } - - do { - mode = 0; - groups = 0; - NEXT_GROUP: - if ((c = *s++) == '\0') { - return -1; - } - for (p=group_chars ; *p ; p++) { - if (*p == c) { - groups |= group_set[(int)(p-group_chars)]; - goto NEXT_GROUP; - } - } - switch (c) { - case '=': - case '+': - case '-': - type = c; - if (groups == 0) { /* The default is "all" */ - groups |= S_ISUID | S_ISGID | S_ISVTX - | S_IRWXU | S_IRWXG | S_IRWXO; - } - break; - default: - if ((c < '0') || (c > '7') || (mode | groups)) { - return (FALSE); - } else { - *theMode = strtol(--s, NULL, 8); - return (TRUE); - } - } - - NEXT_MODE: - if (((c = *s++) != '\0') && (c != ',')) { - for (p=mode_chars ; *p ; p++) { - if (*p == c) { - mode |= mode_set[(int)(p-mode_chars)]; - goto NEXT_MODE; - } - } - break; /* We're done so break out of loop.*/ - } - switch (type) { - case '=': - andMode &= ~(groups); /* Now fall through. */ - case '+': - orMode |= mode & groups; - break; - case '-': - andMode &= ~(mode & groups); - orMode &= ~(mode & groups); - break; - } - } while (c == ','); - - *theMode &= andMode; - *theMode |= orMode; - - return TRUE; -} - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/parse_number.c b/busybox/libbb/parse_number.c deleted file mode 100644 index c90511dca..000000000 --- a/busybox/libbb/parse_number.c +++ /dev/null @@ -1,74 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include "libbb.h" - - -unsigned long parse_number(const char *numstr, - const struct suffix_mult *suffixes) -{ - const struct suffix_mult *sm; - unsigned long int ret; - int len; - char *end; - - ret = strtoul(numstr, &end, 10); - if (numstr == end) - error_msg_and_die("invalid number `%s'", numstr); - while (end[0] != '\0') { - sm = suffixes; - while ( sm != 0 ) { - if(sm->suffix) { - len = strlen(sm->suffix); - if (strncmp(sm->suffix, end, len) == 0) { - ret *= sm->mult; - end += len; - break; - } - sm++; - - } else - sm = 0; - } - if (sm == 0) - error_msg_and_die("invalid number `%s'", numstr); - } - return ret; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/perror_msg.c b/busybox/libbb/perror_msg.c deleted file mode 100644 index 18c71ab1c..000000000 --- a/busybox/libbb/perror_msg.c +++ /dev/null @@ -1,51 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include -#include "libbb.h" - -extern void perror_msg(const char *s, ...) -{ - va_list p; - - va_start(p, s); - vperror_msg(s, p); - va_end(p); -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/perror_msg_and_die.c b/busybox/libbb/perror_msg_and_die.c deleted file mode 100644 index 9d304a26b..000000000 --- a/busybox/libbb/perror_msg_and_die.c +++ /dev/null @@ -1,52 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include -#include "libbb.h" - -extern void perror_msg_and_die(const char *s, ...) -{ - va_list p; - - va_start(p, s); - vperror_msg(s, p); - va_end(p); - exit(EXIT_FAILURE); -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/print_file.c b/busybox/libbb/print_file.c deleted file mode 100644 index bfedc5eff..000000000 --- a/busybox/libbb/print_file.c +++ /dev/null @@ -1,61 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) 1999-2001 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 "libbb.h" - - -extern void print_file(FILE *file) -{ - fflush(stdout); - copyfd(fileno(file), fileno(stdout)); - fclose(file); -} - -extern int print_file_by_name(char *filename) -{ - struct stat statBuf; - int status = TRUE; - - if(is_directory(filename, TRUE, &statBuf)==TRUE) { - error_msg("%s: Is directory", filename); - status = FALSE; - } else { - FILE *f = wfopen(filename, "r"); - if(f!=NULL) - print_file(f); - else - status = FALSE; - } - - return status; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/process_escape_sequence.c b/busybox/libbb/process_escape_sequence.c deleted file mode 100644 index 67b0490ce..000000000 --- a/busybox/libbb/process_escape_sequence.c +++ /dev/null @@ -1,80 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) Manuel Nova III - * and Vladimir Oleynik - * - * 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" - - - -char process_escape_sequence(const char **ptr) -{ - static const char charmap[] = { - 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', 0, - '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' }; - - const char *p; - const char *q; - int num_digits; - unsigned int n; - - n = 0; - q = *ptr; - - for ( num_digits = 0 ; num_digits < 3 ; ++num_digits) { - if ((*q < '0') || (*q > '7')) { /* not a digit? */ - break; - } - n = n * 8 + (*q++ - '0'); - } - - if (num_digits == 0) { /* mnemonic escape sequence? */ - for (p=charmap ; *p ; p++) { - if (*p == *q) { - q++; - break; - } - } - n = *(p+(sizeof(charmap)/2)); - } - - /* doesn't hurt to fall through to here from mnemonic case */ - if (n > UCHAR_MAX) { /* is octal code too big for a char? */ - n /= 8; /* adjust value and */ - --q; /* back up one char */ - } - - *ptr = q; - return (char) n; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/read_package_field.c b/busybox/libbb/read_package_field.c deleted file mode 100644 index f561df831..000000000 --- a/busybox/libbb/read_package_field.c +++ /dev/null @@ -1,91 +0,0 @@ -#include -#include -#include "libbb.h" - -/* - * Gets the next package field from package_buffer, seperated into the field name - * and field value, it returns the int offset to the first character of the next field - */ -int read_package_field(const char *package_buffer, char **field_name, char **field_value) -{ - int offset_name_start = 0; - int offset_name_end = 0; - int offset_value_start = 0; - int offset_value_end = 0; - int offset = 0; - int next_offset; - int name_length; - int value_length; - int exit_flag = FALSE; - - if (package_buffer == NULL) { - *field_name = NULL; - *field_value = NULL; - return(-1); - } - while (1) { - next_offset = offset + 1; - switch (package_buffer[offset]) { - case('\0'): - exit_flag = TRUE; - break; - case(':'): - if (offset_name_end == 0) { - offset_name_end = offset; - offset_value_start = next_offset; - } - /* TODO: Name might still have trailing spaces if ':' isnt - * immediately after name */ - break; - case('\n'): - /* TODO: The char next_offset may be out of bounds */ - if (package_buffer[next_offset] != ' ') { - exit_flag = TRUE; - break; - } - case('\t'): - case(' '): - /* increment the value start point if its a just filler */ - if (offset_name_start == offset) { - offset_name_start++; - } - if (offset_value_start == offset) { - offset_value_start++; - } - break; - } - if (exit_flag == TRUE) { - /* Check that the names are valid */ - offset_value_end = offset; - name_length = offset_name_end - offset_name_start; - value_length = offset_value_end - offset_value_start; - if (name_length == 0) { - break; - } - if ((name_length > 0) && (value_length > 0)) { - break; - } - - /* If not valid, start fresh with next field */ - exit_flag = FALSE; - offset_name_start = offset + 1; - offset_name_end = 0; - offset_value_start = offset + 1; - offset_value_end = offset + 1; - offset++; - } - offset++; - } - if (name_length == 0) { - *field_name = NULL; - } else { - *field_name = xstrndup(&package_buffer[offset_name_start], name_length); - } - if (value_length > 0) { - *field_value = xstrndup(&package_buffer[offset_value_start], value_length); - } else { - *field_value = NULL; - } - return(next_offset); -} - diff --git a/busybox/libbb/real_loop.h b/busybox/libbb/real_loop.h deleted file mode 100644 index 1bd7fa87a..000000000 --- a/busybox/libbb/real_loop.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * include/linux/loop.h - * - * Written by Theodore Ts'o, 3/29/93. - * - * Copyright 1993 by Theodore Ts'o. Redistribution of this file is - * permitted under the GNU Public License. - */ - -#define LO_NAME_SIZE 64 -#define LO_KEY_SIZE 32 - -struct loop_info { - int lo_number; /* ioctl r/o */ - dev_t lo_device; /* ioctl r/o */ - unsigned long lo_inode; /* ioctl r/o */ - dev_t lo_rdevice; /* ioctl r/o */ - int lo_offset; - int lo_encrypt_type; - int lo_encrypt_key_size; /* ioctl w/o */ - int lo_flags; /* ioctl r/o */ - char lo_name[LO_NAME_SIZE]; - unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ - unsigned long lo_init[2]; - char reserved[4]; -}; - -#define LO_CRYPT_NONE 0 -#define LO_CRYPT_XOR 1 -#define LO_CRYPT_DES 2 -#define LO_CRYPT_IDEA 3 -#define MAX_LO_CRYPT 4 - -#define LOOP_SET_FD 0x4C00 -#define LOOP_CLR_FD 0x4C01 -#define LOOP_SET_STATUS 0x4C02 -#define LOOP_GET_STATUS 0x4C03 diff --git a/busybox/libbb/recursive_action.c b/busybox/libbb/recursive_action.c deleted file mode 100644 index 6672db17f..000000000 --- a/busybox/libbb/recursive_action.c +++ /dev/null @@ -1,150 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include -#include /* free() */ -#include "libbb.h" - -#undef DEBUG_RECURS_ACTION - - -/* - * Walk down all the directories under the specified - * location, and do something (something specified - * by the fileAction and dirAction function pointers). - * - * Unfortunately, while nftw(3) could replace this and reduce - * code size a bit, nftw() wasn't supported before GNU libc 2.1, - * and so isn't sufficiently portable to take over since glibc2.1 - * is so stinking huge. - */ -int recursive_action(const char *fileName, - int recurse, int followLinks, int depthFirst, - int (*fileAction) (const char *fileName, - struct stat * statbuf, - void* userData), - int (*dirAction) (const char *fileName, - struct stat * statbuf, - void* userData), - void* userData) -{ - int status; - struct stat statbuf; - struct dirent *next; - - if (followLinks == TRUE) - status = stat(fileName, &statbuf); - else - status = lstat(fileName, &statbuf); - - if (status < 0) { -#ifdef DEBUG_RECURS_ACTION - fprintf(stderr, - "status=%d followLinks=%d TRUE=%d\n", - status, followLinks, TRUE); -#endif - perror_msg("%s", fileName); - return FALSE; - } - - if ((followLinks == FALSE) && (S_ISLNK(statbuf.st_mode))) { - if (fileAction == NULL) - return TRUE; - else - return fileAction(fileName, &statbuf, userData); - } - - if (recurse == FALSE) { - if (S_ISDIR(statbuf.st_mode)) { - if (dirAction != NULL) - return (dirAction(fileName, &statbuf, userData)); - else - return TRUE; - } - } - - if (S_ISDIR(statbuf.st_mode)) { - DIR *dir; - - if (dirAction != NULL && depthFirst == FALSE) { - status = dirAction(fileName, &statbuf, userData); - if (status == FALSE) { - perror_msg("%s", fileName); - return FALSE; - } else if (status == SKIP) - return TRUE; - } - dir = opendir(fileName); - if (!dir) { - perror_msg("%s", fileName); - return FALSE; - } - status = TRUE; - while ((next = readdir(dir)) != NULL) { - char *nextFile; - - if ((strcmp(next->d_name, "..") == 0) - || (strcmp(next->d_name, ".") == 0)) { - continue; - } - nextFile = concat_path_file(fileName, next->d_name); - if (recursive_action(nextFile, TRUE, followLinks, depthFirst, - fileAction, dirAction, userData) == FALSE) { - status = FALSE; - } - free(nextFile); - } - closedir(dir); - if (dirAction != NULL && depthFirst == TRUE) { - if (dirAction(fileName, &statbuf, userData) == FALSE) { - perror_msg("%s", fileName); - return FALSE; - } - } - if (status == FALSE) - return FALSE; - } else { - if (fileAction == NULL) - return TRUE; - else - return fileAction(fileName, &statbuf, userData); - } - return TRUE; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/remove_file.c b/busybox/libbb/remove_file.c deleted file mode 100644 index 3b84680c4..000000000 --- a/busybox/libbb/remove_file.c +++ /dev/null @@ -1,129 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini remove_file implementation for busybox - * - * - * 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "libbb.h" - -extern int remove_file(const char *path, int flags) -{ - struct stat path_stat; - int path_exists = 1; - - if (lstat(path, &path_stat) < 0) { - if (errno != ENOENT) { - perror_msg("unable to stat `%s'", path); - return -1; - } - - path_exists = 0; - } - - if (!path_exists) { - if (!(flags & FILEUTILS_FORCE)) { - perror_msg("cannot remove `%s'", path); - return -1; - } - return 0; - } - - if (S_ISDIR(path_stat.st_mode)) { - DIR *dp; - struct dirent *d; - int status = 0; - - if (!(flags & FILEUTILS_RECUR)) { - error_msg("%s: is a directory", path); - return -1; - } - - if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 && - isatty(0)) || - (flags & FILEUTILS_INTERACTIVE)) { - fprintf(stderr, "%s: descend into directory `%s'? ", applet_name, - path); - if (!ask_confirmation()) - return 0; - } - - if ((dp = opendir(path)) == NULL) { - perror_msg("unable to open `%s'", path); - return -1; - } - - while ((d = readdir(dp)) != NULL) { - char *new_path; - - if (strcmp(d->d_name, ".") == 0 || - strcmp(d->d_name, "..") == 0) - continue; - - new_path = concat_path_file(path, d->d_name); - if (remove_file(new_path, flags) < 0) - status = -1; - free(new_path); - } - - if (closedir(dp) < 0) { - perror_msg("unable to close `%s'", path); - return -1; - } - - if (flags & FILEUTILS_INTERACTIVE) { - fprintf(stderr, "%s: remove directory `%s'? ", applet_name, path); - if (!ask_confirmation()) - return status; - } - - if (rmdir(path) < 0) { - perror_msg("unable to remove `%s'", path); - return -1; - } - - return status; - } else { - if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 && - !S_ISLNK(path_stat.st_mode) && - isatty(0)) || - (flags & FILEUTILS_INTERACTIVE)) { - fprintf(stderr, "%s: remove `%s'? ", applet_name, path); - if (!ask_confirmation()) - return 0; - } - - if (unlink(path) < 0) { - perror_msg("unable to remove `%s'", path); - return -1; - } - - return 0; - } -} diff --git a/busybox/libbb/safe_read.c b/busybox/libbb/safe_read.c deleted file mode 100644 index dbf4aa7e4..000000000 --- a/busybox/libbb/safe_read.c +++ /dev/null @@ -1,54 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include "libbb.h" - - - -ssize_t safe_read(int fd, void *buf, size_t count) -{ - ssize_t n; - - do { - n = read(fd, buf, count); - } while (n < 0 && errno == EINTR); - - return n; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/safe_strncpy.c b/busybox/libbb/safe_strncpy.c deleted file mode 100644 index 55ec79802..000000000 --- a/busybox/libbb/safe_strncpy.c +++ /dev/null @@ -1,48 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include "libbb.h" - - - -/* Like strncpy but make sure the resulting string is always 0 terminated. */ -extern char * safe_strncpy(char *dst, const char *src, size_t size) -{ - dst[size-1] = '\0'; - return strncpy(dst, src, size-1); -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/simplify_path.c b/busybox/libbb/simplify_path.c deleted file mode 100644 index cf5b838a1..000000000 --- a/busybox/libbb/simplify_path.c +++ /dev/null @@ -1,67 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * simplify_path implementation for busybox - * - * - * Copyright (C) 2001 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 "libbb.h" - -char *simplify_path(const char *path) -{ - char *s, *start, *p; - - if (path[0] == '/') - start = xstrdup(path); - else { - s = xgetcwd(NULL); - start = concat_path_file(s, path); - free(s); - } - p = s = start; - - do { - if (*p == '/') { - if (*s == '/') { /* skip duplicate (or initial) slash */ - continue; - } else if (*s == '.') { - if (s[1] == '/' || s[1] == 0) { /* remove extra '.' */ - continue; - } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) { - ++s; - if (p > start) { - while (*--p != '/'); /* omit previous dir */ - } - continue; - } - } - } - *++p = *s; - } while (*++s); - - if ((p == start) || (*p != '/')) { /* not a trailing slash */ - ++p; /* so keep last character */ - } - *p = 0; - - return start; -} diff --git a/busybox/libbb/syscalls.c b/busybox/libbb/syscalls.c deleted file mode 100644 index 426a14aa1..000000000 --- a/busybox/libbb/syscalls.c +++ /dev/null @@ -1,115 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * some system calls possibly missing from libc - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -/* Kernel headers before 2.1.mumble need this on the Alpha to get - _syscall* defined. */ -#define __LIBRARY__ - - -#include -#ifndef __UCLIBC__ -#include -#endif -#include "libbb.h" - -#if defined(__ia64__) -int sysfs( int option, unsigned int fs_index, char * buf) -{ - return(syscall(__NR_sysfs, option, fs_index, buf)); -} -#else -_syscall3(int, sysfs, int, option, unsigned int, fs_index, char *, buf); -#endif - -#ifndef __NR_pivot_root -#warning This kernel does not support the pivot_root syscall -#warning -> The pivot_root system call is being stubbed out... -int pivot_root(const char * new_root,const char * put_old) -{ - /* BusyBox was compiled against a kernel that did not support - * the pivot_root system call. To make this application work, - * you will need to recompile with a kernel supporting the - * pivot_root system call. - */ - fprintf(stderr, "\n\nTo make this application work, you will need to recompile\n"); - fprintf(stderr, "with a kernel supporting the pivot_root system call. -Erik\n\n"); - errno=ENOSYS; - return -1; -} -#else -# if defined(__ia64__) - int pivot_root(const char * new_root,const char * put_old) - { - return(syscall(__NR_pivot_root, new_root, put_old)); - } -# else - _syscall2(int,pivot_root,const char *,new_root,const char *,put_old); -# endif -#endif - - - - -#if __GNU_LIBRARY__ < 5 || ((__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)) -/* These syscalls are not included as part of libc5 */ -_syscall2(int, bdflush, int, func, int, data); - -#ifndef __alpha__ -# define __NR_klogctl __NR_syslog - _syscall3(int, klogctl, int, type, char *, b, int, len); -#endif - -#ifndef __NR_umount2 -# warning This kernel does not support the umount2 syscall -# warning -> The umount2 system call is being stubbed out... -int umount2(const char * special_file, int flags) -{ - /* BusyBox was compiled against a kernel that did not support - * the umount2 system call. To make this application work, - * you will need to recompile with a kernel supporting the - * umount2 system call. - */ - fprintf(stderr, "\n\nTo make this application work, you will need to recompile\n"); - fprintf(stderr, "with a kernel supporting the umount2 system call. -Erik\n\n"); - errno=ENOSYS; - return -1; -} -# else -_syscall2(int, umount2, const char *, special_file, int, flags); -#endif - - -#endif /* __GNU_LIBRARY__ < 5 */ - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/syslog_msg_with_name.c b/busybox/libbb/syslog_msg_with_name.c deleted file mode 100644 index 5dadcc433..000000000 --- a/busybox/libbb/syslog_msg_with_name.c +++ /dev/null @@ -1,51 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "libbb.h" - -void syslog_msg_with_name(const char *name, int facility, int pri, const char *msg) -{ - openlog(name, 0, facility); - syslog(pri, "%s", msg); - closelog(); -} - -void syslog_msg(int facility, int pri, const char *msg) -{ - syslog_msg_with_name(applet_name, facility, pri, msg); -} - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/time_string.c b/busybox/libbb/time_string.c deleted file mode 100644 index 076529006..000000000 --- a/busybox/libbb/time_string.c +++ /dev/null @@ -1,68 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include -#include "libbb.h" - - -/* - * Return the standard ls-like time string from a time_t - * This is static and so is overwritten on each call. - */ -const char *time_string(time_t timeVal) -{ - time_t now; - char *str; - static char buf[26]; - - time(&now); - - str = ctime(&timeVal); - - strcpy(buf, &str[4]); - buf[12] = '\0'; - - if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) { - strcpy(&buf[7], &str[20]); - buf[11] = '\0'; - } - - return buf; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/trim.c b/busybox/libbb/trim.c deleted file mode 100644 index 76b87ca1c..000000000 --- a/busybox/libbb/trim.c +++ /dev/null @@ -1,53 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include "libbb.h" - - -void trim(char *s) -{ - int len = strlen(s); - - /* trim trailing whitespace */ - while ( len > 0 && isspace(s[len-1])) - s[--len]='\0'; - - /* trim leading whitespace */ - memmove(s, &s[strspn(s, " \n\r\t\v")], len); -} - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/u_signal_names.c b/busybox/libbb/u_signal_names.c deleted file mode 100644 index 623b10312..000000000 --- a/busybox/libbb/u_signal_names.c +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include -#include -#include -#include - -struct signal_name { - const char *name; - int number; -}; - -static const struct signal_name signames[] = { - /* POSIX signals */ - { "EXIT", 0 }, /* 0 */ - { "HUP", SIGHUP }, /* 1 */ - { "INT", SIGINT }, /* 2 */ - { "QUIT", SIGQUIT }, /* 3 */ - { "ILL", SIGILL }, /* 4 */ - { "ABRT", SIGABRT }, /* 6 */ - { "FPE", SIGFPE }, /* 8 */ - { "KILL", SIGKILL }, /* 9 */ - { "SEGV", SIGSEGV }, /* 11 */ - { "PIPE", SIGPIPE }, /* 13 */ - { "ALRM", SIGALRM }, /* 14 */ - { "TERM", SIGTERM }, /* 15 */ - { "USR1", SIGUSR1 }, /* 10 (arm,i386,m68k,ppc), 30 (alpha,sparc*), 16 (mips) */ - { "USR2", SIGUSR2 }, /* 12 (arm,i386,m68k,ppc), 31 (alpha,sparc*), 17 (mips) */ - { "CHLD", SIGCHLD }, /* 17 (arm,i386,m68k,ppc), 20 (alpha,sparc*), 18 (mips) */ - { "CONT", SIGCONT }, /* 18 (arm,i386,m68k,ppc), 19 (alpha,sparc*), 25 (mips) */ - { "STOP", SIGSTOP }, /* 19 (arm,i386,m68k,ppc), 17 (alpha,sparc*), 23 (mips) */ - { "TSTP", SIGTSTP }, /* 20 (arm,i386,m68k,ppc), 18 (alpha,sparc*), 24 (mips) */ - { "TTIN", SIGTTIN }, /* 21 (arm,i386,m68k,ppc,alpha,sparc*), 26 (mips) */ - { "TTOU", SIGTTOU }, /* 22 (arm,i386,m68k,ppc,alpha,sparc*), 27 (mips) */ - /* Miscellaneous other signals */ -#ifdef SIGTRAP - { "TRAP", SIGTRAP }, /* 5 */ -#endif -#ifdef SIGIOT - { "IOT", SIGIOT }, /* 6, same as SIGABRT */ -#endif -#ifdef SIGEMT - { "EMT", SIGEMT }, /* 7 (mips,alpha,sparc*) */ -#endif -#ifdef SIGBUS - { "BUS", SIGBUS }, /* 7 (arm,i386,m68k,ppc), 10 (mips,alpha,sparc*) */ -#endif -#ifdef SIGSYS - { "SYS", SIGSYS }, /* 12 (mips,alpha,sparc*) */ -#endif -#ifdef SIGSTKFLT - { "STKFLT", SIGSTKFLT }, /* 16 (arm,i386,m68k,ppc) */ -#endif -#ifdef SIGURG - { "URG", SIGURG }, /* 23 (arm,i386,m68k,ppc), 16 (alpha,sparc*), 21 (mips) */ -#endif -#ifdef SIGIO - { "IO", SIGIO }, /* 29 (arm,i386,m68k,ppc), 23 (alpha,sparc*), 22 (mips) */ -#endif -#ifdef SIGPOLL - { "POLL", SIGPOLL }, /* same as SIGIO */ -#endif -#ifdef SIGCLD - { "CLD", SIGCLD }, /* same as SIGCHLD (mips) */ -#endif -#ifdef SIGXCPU - { "XCPU", SIGXCPU }, /* 24 (arm,i386,m68k,ppc,alpha,sparc*), 30 (mips) */ -#endif -#ifdef SIGXFSZ - { "XFSZ", SIGXFSZ }, /* 25 (arm,i386,m68k,ppc,alpha,sparc*), 31 (mips) */ -#endif -#ifdef SIGVTALRM - { "VTALRM", SIGVTALRM }, /* 26 (arm,i386,m68k,ppc,alpha,sparc*), 28 (mips) */ -#endif -#ifdef SIGPROF - { "PROF", SIGPROF }, /* 27 (arm,i386,m68k,ppc,alpha,sparc*), 29 (mips) */ -#endif -#ifdef SIGPWR - { "PWR", SIGPWR }, /* 30 (arm,i386,m68k,ppc), 29 (alpha,sparc*), 19 (mips) */ -#endif -#ifdef SIGINFO - { "INFO", SIGINFO }, /* 29 (alpha) */ -#endif -#ifdef SIGLOST - { "LOST", SIGLOST }, /* 29 (arm,i386,m68k,ppc,sparc*) */ -#endif -#ifdef SIGWINCH - { "WINCH", SIGWINCH }, /* 28 (arm,i386,m68k,ppc,alpha,sparc*), 20 (mips) */ -#endif -#ifdef SIGUNUSED - { "UNUSED", SIGUNUSED }, /* 31 (arm,i386,m68k,ppc) */ -#endif - {0, 0} -}; - -/* - if str_sig == NULL returned signal name [*signo], - if str_sig != NULL - set *signo from signal_name, - findings with digit number or with or without SIG-prefix name - - if startnum=0 flag for support finding zero signal, - but str_sig="0" always found, (hmm - standart or realize?) - if startnum<0 returned reverse signal_number <-> signal_name - if found error - returned NULL - -*/ - -const char * -u_signal_names(const char *str_sig, int *signo, int startnum) -{ - static char retstr[16]; - const struct signal_name *s = signames; - static const char prefix[] = "SIG"; - const char *sptr; - - if(startnum) - s++; - if(str_sig==NULL) { - while (s->name != 0) { - if(s->number == *signo) - break; - s++; - } - } else { - if (isdigit(((unsigned char)*str_sig))) { - char *endp; - long int sn = strtol(str_sig, &endp, 10); - /* test correct and overflow */ - if(*endp == 0 && sn >= 0 && sn < NSIG) { - *signo = (int)sn; - /* test for unnamed */ - sptr = u_signal_names(0, signo, 0); - if(sptr==NULL) - return NULL; - if(sn!=0) - sptr += 3; - return sptr; - } - } else { - sptr = str_sig; - while (s->name != 0) { - if (strcasecmp(s->name, sptr) == 0) { - *signo = s->number; - if(startnum<0) { - sprintf(retstr, "%d", *signo); - return retstr; - } - break; - } - if(s!=signames && sptr == str_sig && - strncasecmp(sptr, prefix, 3) == 0) { - sptr += 3; /* strlen(prefix) */ - continue; - } - sptr = str_sig; - s++; - } - } - } - if(s->name==0) - return NULL; - if(s!=signames) - strcpy(retstr, prefix); - else - retstr[0] = 0; - return strcat(retstr, s->name); -} diff --git a/busybox/libbb/unarchive.c b/busybox/libbb/unarchive.c deleted file mode 100644 index 4d47eff0e..000000000 --- a/busybox/libbb/unarchive.c +++ /dev/null @@ -1,617 +0,0 @@ -/* - * Copyright (C) 2000 by Glenn McGrath - * Copyright (C) 2001 by Laurence Anderson - * - * Based on previous work by busybox developers and others. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include "libbb.h" - -extern void seek_sub_file(FILE *src_stream, const int count); -extern char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *file_entry, - const int function, const char *prefix); - - -#ifdef L_archive_offset -off_t archive_offset; -#else -extern off_t archive_offset; -#endif - -#ifdef L_seek_sub_file -void seek_sub_file(FILE *src_stream, const int count) -{ - int i; - /* Try to fseek as faster */ - archive_offset += count; - if (fseek(src_stream, count, SEEK_CUR) != 0 && errno == ESPIPE) { - for (i = 0; i < count; i++) { - fgetc(src_stream); - } - } - return; -} -#endif - - - -#ifdef L_extract_archive -/* Extract the data postioned at src_stream to either filesystem, stdout or - * buffer depending on the value of 'function' which is defined in libbb.h - * - * prefix doesnt have to be just a directory, it may prefix the filename as well. - * - * e.g. '/var/lib/dpkg/info/dpkg.' will extract all files to the base bath - * '/var/lib/dpkg/info/' and all files/dirs created in that dir will have - * 'dpkg.' as their prefix - * - * For this reason if prefix does point to a dir then it must end with a - * trailing '/' or else the last dir will be assumed to be the file prefix - */ -char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *file_entry, - const int function, const char *prefix) -{ - FILE *dst_stream = NULL; - char *full_name = NULL; - char *buffer = NULL; - struct utimbuf t; - - /* prefix doesnt have to be a proper path it may prepend - * the filename as well */ - if (prefix != NULL) { - /* strip leading '/' in filename to extract as prefix may not be dir */ - /* Cant use concat_path_file here as prefix might not be a directory */ - char *path = file_entry->name; - if (strncmp("./", path, 2) == 0) { - path += 2; - if (strlen(path) == 0) { - return(NULL); - } - } - full_name = xmalloc(strlen(prefix) + strlen(path) + 1); - strcpy(full_name, prefix); - strcat(full_name, path); - } else { - full_name = file_entry->name; - } - if (function & extract_to_stdout) { - if (S_ISREG(file_entry->mode)) { - copy_file_chunk(src_stream, out_stream, file_entry->size); - archive_offset += file_entry->size; - } - } - else if (function & extract_one_to_buffer) { - if (S_ISREG(file_entry->mode)) { - buffer = (char *) xmalloc(file_entry->size + 1); - fread(buffer, 1, file_entry->size, src_stream); - buffer[file_entry->size] = '\0'; - archive_offset += file_entry->size; - return(buffer); - } - } - else if (function & extract_all_to_fs) { - struct stat oldfile; - int stat_res; - stat_res = lstat (full_name, &oldfile); - if (stat_res == 0) { /* The file already exists */ - if ((function & extract_unconditional) || (oldfile.st_mtime < file_entry->mtime)) { - if (!S_ISDIR(oldfile.st_mode)) { - unlink(full_name); /* Directories might not be empty etc */ - } - } else { - if ((function & extract_quiet) != extract_quiet) { - error_msg("%s not created: newer or same age file exists", file_entry->name); - } - seek_sub_file(src_stream, file_entry->size); - return (NULL); - } - } - if (function & extract_create_leading_dirs) { /* Create leading directories with default umask */ - char *buf, *parent; - buf = xstrdup(full_name); - parent = dirname(buf); - if (make_directory (parent, -1, FILEUTILS_RECUR) != 0) { - if ((function & extract_quiet) != extract_quiet) { - error_msg("couldn't create leading directories"); - } - } - free (buf); - } - switch(file_entry->mode & S_IFMT) { - case S_IFREG: - if (file_entry->link_name) { /* Found a cpio hard link */ - if (link(file_entry->link_name, full_name) != 0) { - if ((function & extract_quiet) != extract_quiet) { - perror_msg("Cannot link from %s to '%s'", - file_entry->name, file_entry->link_name); - } - } - } else { - if ((dst_stream = wfopen(full_name, "w")) == NULL) { - seek_sub_file(src_stream, file_entry->size); - return NULL; - } - archive_offset += file_entry->size; - copy_file_chunk(src_stream, dst_stream, file_entry->size); - fclose(dst_stream); - } - break; - case S_IFDIR: - if (stat_res != 0) { - if (mkdir(full_name, file_entry->mode) < 0) { - if ((function & extract_quiet) != extract_quiet) { - perror_msg("extract_archive: %s", full_name); - } - } - } - break; - case S_IFLNK: - if (symlink(file_entry->link_name, full_name) < 0) { - if ((function & extract_quiet) != extract_quiet) { - perror_msg("Cannot create symlink from %s to '%s'", file_entry->name, file_entry->link_name); - } - return NULL; - } - break; - case S_IFSOCK: - case S_IFBLK: - case S_IFCHR: - case S_IFIFO: - if (mknod(full_name, file_entry->mode, file_entry->device) == -1) { - if ((function & extract_quiet) != extract_quiet) { - perror_msg("Cannot create node %s", file_entry->name); - } - return NULL; - } - break; - } - - /* Changing a symlink's properties normally changes the properties of the - * file pointed to, so dont try and change the date or mode, lchown does - * does the right thing, but isnt available in older versions of libc */ - if (S_ISLNK(file_entry->mode)) { -#if (__GLIBC__ > 2) && (__GLIBC_MINOR__ > 1) - lchown(full_name, file_entry->uid, file_entry->gid); -#endif - } else { - if (function & extract_preserve_date) { - t.actime = file_entry->mtime; - t.modtime = file_entry->mtime; - utime(full_name, &t); - } - chmod(full_name, file_entry->mode); - chown(full_name, file_entry->uid, file_entry->gid); - } - } else { - /* If we arent extracting data we have to skip it, - * if data size is 0 then then just do it anyway - * (saves testing for it) */ - seek_sub_file(src_stream, file_entry->size); - } - - /* extract_list and extract_verbose_list can be used in conjunction - * with one of the above four extraction functions, so do this seperately */ - if (function & extract_verbose_list) { - fprintf(out_stream, "%s %d/%d %8d %s ", mode_string(file_entry->mode), - file_entry->uid, file_entry->gid, - (int) file_entry->size, time_string(file_entry->mtime)); - } - if ((function & extract_list) || (function & extract_verbose_list)){ - /* fputs doesnt add a trailing \n, so use fprintf */ - fprintf(out_stream, "%s\n", file_entry->name); - } - - free(full_name); - - return(NULL); /* Maybe we should say if failed */ -} -#endif - -#ifdef L_unarchive -char *unarchive(FILE *src_stream, FILE *out_stream, file_header_t *(*get_headers)(FILE *), - const int extract_function, const char *prefix, char **extract_names) -{ - file_header_t *file_entry; - int extract_flag; - int i; - char *buffer = NULL; - - archive_offset = 0; - while ((file_entry = get_headers(src_stream)) != NULL) { - extract_flag = TRUE; - if (extract_names != NULL) { - int found_flag = FALSE; - for(i = 0; extract_names[i] != 0; i++) { - if (strcmp(extract_names[i], file_entry->name) == 0) { - found_flag = TRUE; - break; - } - } - if (extract_function & extract_exclude_list) { - if (found_flag == TRUE) { - extract_flag = FALSE; - } - } else { - /* If its not found in the include list dont extract it */ - if (found_flag == FALSE) { - extract_flag = FALSE; - } - } - - } - - if (extract_flag == TRUE) { - buffer = extract_archive(src_stream, out_stream, file_entry, extract_function, prefix); - } else { - /* seek past the data entry */ - seek_sub_file(src_stream, file_entry->size); - } - free(file_entry->name); /* may be null, but doesn't matter */ - free(file_entry->link_name); - free(file_entry); - } - return(buffer); -} -#endif - -#ifdef L_get_header_ar -file_header_t *get_header_ar(FILE *src_stream) -{ - file_header_t *typed; - union { - char raw[60]; - struct { - char name[16]; - char date[12]; - char uid[6]; - char gid[6]; - char mode[8]; - char size[10]; - char magic[2]; - } formated; - } ar; - static char *ar_long_names; - - if (fread(ar.raw, 1, 60, src_stream) != 60) { - return(NULL); - } - archive_offset += 60; - /* align the headers based on the header magic */ - if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) { - /* some version of ar, have an extra '\n' after each data entry, - * this puts the next header out by 1 */ - if (ar.formated.magic[1] != '`') { - error_msg("Invalid magic"); - return(NULL); - } - /* read the next char out of what would be the data section, - * if its a '\n' then it is a valid header offset by 1*/ - archive_offset++; - if (fgetc(src_stream) != '\n') { - error_msg("Invalid magic"); - return(NULL); - } - /* fix up the header, we started reading 1 byte too early */ - /* raw_header[60] wont be '\n' as it should, but it doesnt matter */ - memmove(ar.raw, &ar.raw[1], 59); - } - - typed = (file_header_t *) xcalloc(1, sizeof(file_header_t)); - - typed->size = (size_t) atoi(ar.formated.size); - /* long filenames have '/' as the first character */ - if (ar.formated.name[0] == '/') { - if (ar.formated.name[1] == '/') { - /* If the second char is a '/' then this entries data section - * stores long filename for multiple entries, they are stored - * in static variable long_names for use in future entries */ - ar_long_names = (char *) xrealloc(ar_long_names, typed->size); - fread(ar_long_names, 1, typed->size, src_stream); - archive_offset += typed->size; - /* This ar entries data section only contained filenames for other records - * they are stored in the static ar_long_names for future reference */ - return (get_header_ar(src_stream)); /* Return next header */ - } else if (ar.formated.name[1] == ' ') { - /* This is the index of symbols in the file for compilers */ - seek_sub_file(src_stream, typed->size); - return (get_header_ar(src_stream)); /* Return next header */ - } else { - /* The number after the '/' indicates the offset in the ar data section - (saved in variable long_name) that conatains the real filename */ - if (!ar_long_names) { - error_msg("Cannot resolve long file name"); - return (NULL); - } - typed->name = xstrdup(ar_long_names + atoi(&ar.formated.name[1])); - } - } else { - /* short filenames */ - typed->name = xcalloc(1, 16); - strncpy(typed->name, ar.formated.name, 16); - } - typed->name[strcspn(typed->name, " /")]='\0'; - - /* convert the rest of the now valid char header to its typed struct */ - parse_mode(ar.formated.mode, &typed->mode); - typed->mtime = atoi(ar.formated.date); - typed->uid = atoi(ar.formated.uid); - typed->gid = atoi(ar.formated.gid); - - return(typed); -} -#endif - -#ifdef L_get_header_cpio -struct hardlinks { - file_header_t *entry; - int inode; - struct hardlinks *next; -}; - -file_header_t *get_header_cpio(FILE *src_stream) -{ - file_header_t *cpio_entry = NULL; - char cpio_header[110]; - int namesize; - char dummy[16]; - int major, minor, nlink, inode; - static struct hardlinks *saved_hardlinks = NULL; - static int pending_hardlinks = 0; - - if (pending_hardlinks) { /* Deal with any pending hardlinks */ - struct hardlinks *tmp = saved_hardlinks, *oldtmp = NULL; - while (tmp) { - if (tmp->entry->link_name) { /* Found a hardlink ready to be extracted */ - cpio_entry = tmp->entry; - if (oldtmp) oldtmp->next = tmp->next; /* Remove item from linked list */ - else saved_hardlinks = tmp->next; - free(tmp); - return (cpio_entry); - } - oldtmp = tmp; - tmp = tmp->next; - } - pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */ - } - - /* There can be padding before archive header */ - seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4); - if (fread(cpio_header, 1, 110, src_stream) == 110) { - archive_offset += 110; - if (strncmp(cpio_header, "07070", 5) != 0) { - error_msg("Unsupported format or invalid magic"); - return(NULL); - } - switch (cpio_header[5]) { - case '2': /* "crc" header format */ - /* Doesnt do the crc check yet */ - case '1': /* "newc" header format */ - cpio_entry = (file_header_t *) xcalloc(1, sizeof(file_header_t)); - sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c", - dummy, &inode, (unsigned int*)&cpio_entry->mode, - (unsigned int*)&cpio_entry->uid, (unsigned int*)&cpio_entry->gid, - &nlink, &cpio_entry->mtime, &cpio_entry->size, - dummy, &major, &minor, &namesize, dummy); - - cpio_entry->name = (char *) xcalloc(1, namesize); - fread(cpio_entry->name, 1, namesize, src_stream); /* Read in filename */ - archive_offset += namesize; - /* Skip padding before file contents */ - seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4); - if (strcmp(cpio_entry->name, "TRAILER!!!") == 0) { - printf("%d blocks\n", (int) (archive_offset % 512 ? (archive_offset / 512) + 1 : archive_offset / 512)); /* Always round up */ - if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */ - struct hardlinks *tmp = saved_hardlinks, *oldtmp = NULL; - while (tmp) { - error_msg("%s not created: cannot resolve hardlink", tmp->entry->name); - oldtmp = tmp; - tmp = tmp->next; - free (oldtmp->entry->name); - free (oldtmp->entry); - free (oldtmp); - } - saved_hardlinks = NULL; - pending_hardlinks = 0; - } - return(NULL); - } - - if (S_ISLNK(cpio_entry->mode)) { - cpio_entry->link_name = (char *) xcalloc(1, cpio_entry->size + 1); - fread(cpio_entry->link_name, 1, cpio_entry->size, src_stream); - archive_offset += cpio_entry->size; - cpio_entry->size = 0; /* Stop possiable seeks in future */ - } - if (nlink > 1 && !S_ISDIR(cpio_entry->mode)) { - if (cpio_entry->size == 0) { /* Put file on a linked list for later */ - struct hardlinks *new = xmalloc(sizeof(struct hardlinks)); - new->next = saved_hardlinks; - new->inode = inode; - new->entry = cpio_entry; - saved_hardlinks = new; - return(get_header_cpio(src_stream)); /* Recurse to next file */ - } else { /* Found the file with data in */ - struct hardlinks *tmp = saved_hardlinks; - pending_hardlinks = 1; - while (tmp) { - if (tmp->inode == inode) { - tmp->entry->link_name = xstrdup(cpio_entry->name); - nlink--; - } - tmp = tmp->next; - } - if (nlink > 1) error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?"); - } - } - cpio_entry->device = (major << 8) | minor; - break; - default: - error_msg("Unsupported format"); - return(NULL); - } - if (ferror(src_stream) || feof(src_stream)) { - perror_msg("Stream error"); - return(NULL); - } - } - return(cpio_entry); -} -#endif - -#ifdef L_get_header_tar -file_header_t *get_header_tar(FILE *tar_stream) -{ - union { - unsigned char raw[512]; - struct { - char name[100]; /* 0-99 */ - char mode[8]; /* 100-107 */ - char uid[8]; /* 108-115 */ - char gid[8]; /* 116-123 */ - char size[12]; /* 124-135 */ - char mtime[12]; /* 136-147 */ - char chksum[8]; /* 148-155 */ - char typeflag; /* 156-156 */ - char linkname[100]; /* 157-256 */ - char magic[6]; /* 257-262 */ - char version[2]; /* 263-264 */ - char uname[32]; /* 265-296 */ - char gname[32]; /* 297-328 */ - char devmajor[8]; /* 329-336 */ - char devminor[8]; /* 337-344 */ - char prefix[155]; /* 345-499 */ - char padding[12]; /* 500-512 */ - } formated; - } tar; - file_header_t *tar_entry = NULL; - long i; - long sum = 0; - - if (archive_offset % 512 != 0) { - seek_sub_file(tar_stream, 512 - (archive_offset % 512)); - } - - if (fread(tar.raw, 1, 512, tar_stream) != 512) { - /* Unfortunatly its common for tar files to have all sorts of - * trailing garbage, fail silently */ -// error_msg("Couldnt read header"); - return(NULL); - } - archive_offset += 512; - - /* Check header has valid magic, unfortunately some tar files - * have empty (0'ed) tar entries at the end, which will - * cause this to fail, so fail silently for now - */ - if (strncmp(tar.formated.magic, "ustar", 5) != 0) { - return(NULL); - } - - /* Do checksum on headers */ - for (i = 0; i < 148 ; i++) { - sum += tar.raw[i]; - } - sum += ' ' * 8; - for (i = 156; i < 512 ; i++) { - sum += tar.raw[i]; - } - if (sum != strtol(tar.formated.chksum, NULL, 8)) { - error_msg("Invalid tar header checksum"); - return(NULL); - } - - /* convert to type'ed variables */ - tar_entry = xcalloc(1, sizeof(file_header_t)); - tar_entry->name = xstrdup(tar.formated.name); - - parse_mode(tar.formated.mode, &tar_entry->mode); - tar_entry->uid = strtol(tar.formated.uid, NULL, 8); - tar_entry->gid = strtol(tar.formated.gid, NULL, 8); - tar_entry->size = strtol(tar.formated.size, NULL, 8); - tar_entry->mtime = strtol(tar.formated.mtime, NULL, 8); - tar_entry->link_name = strlen(tar.formated.linkname) ? - xstrdup(tar.formated.linkname) : NULL; - tar_entry->device = (strtol(tar.formated.devmajor, NULL, 8) << 8) + - strtol(tar.formated.devminor, NULL, 8); - - return(tar_entry); -} -#endif - -#ifdef L_deb_extract -char *deb_extract(const char *package_filename, FILE *out_stream, - const int extract_function, const char *prefix, const char *filename) -{ - FILE *deb_stream; - FILE *uncompressed_stream = NULL; - file_header_t *ar_header = NULL; - char **file_list = NULL; - char *output_buffer = NULL; - char *ared_file = NULL; - char ar_magic[8]; - int gunzip_pid; - - if (filename != NULL) { - file_list = xmalloc(sizeof(char *) * 2); - file_list[0] = xstrdup(filename); - file_list[1] = NULL; - } - - if (extract_function & extract_control_tar_gz) { - ared_file = xstrdup("control.tar.gz"); - } - else if (extract_function & extract_data_tar_gz) { - ared_file = xstrdup("data.tar.gz"); - } - - /* open the debian package to be worked on */ - deb_stream = wfopen(package_filename, "r"); - if (deb_stream == NULL) { - return(NULL); - } - /* set the buffer size */ - setvbuf(deb_stream, NULL, _IOFBF, 0x8000); - - /* check ar magic */ - fread(ar_magic, 1, 8, deb_stream); - if (strncmp(ar_magic,"!",7) != 0) { - error_msg_and_die("invalid magic"); - } - archive_offset = 8; - - while ((ar_header = get_header_ar(deb_stream)) != NULL) { - if (strcmp(ared_file, ar_header->name) == 0) { - /* open a stream of decompressed data */ - uncompressed_stream = gz_open(deb_stream, &gunzip_pid); - archive_offset = 0; - output_buffer = unarchive(uncompressed_stream, out_stream, get_header_tar, extract_function, prefix, file_list); - } - seek_sub_file(deb_stream, ar_header->size); - } - gz_close(gunzip_pid); - fclose(deb_stream); - fclose(uncompressed_stream); - free(ared_file); - return(output_buffer); -} -#endif diff --git a/busybox/libbb/unzip.c b/busybox/libbb/unzip.c deleted file mode 100644 index ee746216d..000000000 --- a/busybox/libbb/unzip.c +++ /dev/null @@ -1,1026 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * gunzip implementation for busybox - * - * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly. - * - * Originally adjusted for busybox by Sven Rudolph - * based on gzip sources - * - * Adjusted further by Erik Andersen , - * to support files as well as stdin/stdout, and to generally behave itself wrt - * command line handling. - * - * General cleanup to better adhere to the style guide and make use of standard - * busybox functions by 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 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 - * - * - * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface - * Copyright (C) 1992-1993 Jean-loup Gailly - * The unzip code was written and put in the public domain by Mark Adler. - * Portions of the lzw code are derived from the public domain 'compress' - * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, - * Ken Turkowski, Dave Mack and Peter Jannesen. - * - * See the license_msg below and the file COPYING for the software license. - * See the file algorithm.doc for the compression algorithms and file formats. - */ - -#if 0 -static char *license_msg[] = { - " Copyright (C) 1992-1993 Jean-loup Gailly", - " 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., 675 Mass Ave, Cambridge, MA 02139, USA.", - 0 -}; -#endif - -#include -#include -#include -#include -#include -#include "libbb.h" - -static FILE *in_file, *out_file; - -/* these are freed by gz_close */ -static unsigned char *window; -static unsigned long *crc_table; - -static unsigned long crc = 0xffffffffL; /* shift register contents */ - -/* Return codes from gzip */ -static const int ERROR = 1; - -/* - * window size--must be a power of two, and - * at least 32K for zip's deflate method - */ -static const int WSIZE = 0x8000; - -/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ -static const int BMAX = 16; /* maximum bit length of any code (16 for explode) */ -static const int N_MAX = 288; /* maximum number of codes in any set */ - -static long bytes_out; /* number of output bytes */ -static unsigned long outcnt; /* bytes in output buffer */ - -static unsigned hufts; /* track memory usage */ -static unsigned long bb; /* bit buffer */ -static unsigned bk; /* bits in bit buffer */ - -typedef struct huft_s { - unsigned char e; /* number of extra bits or operation */ - unsigned char b; /* number of bits in this code or subcode */ - union { - unsigned short n; /* literal, length base, or distance base */ - struct huft_s *t; /* pointer to next level of table */ - } v; -} huft_t; - -static const unsigned short mask_bits[] = { - 0x0000, - 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff -}; - -//static int error_number = 0; -/* ======================================================================== - * Signal and error handler. - */ - -static void abort_gzip() -{ - error_msg("gzip aborted\n"); - exit(ERROR); -} - -static void make_crc_table() -{ - unsigned long table_entry; /* crc shift register */ - unsigned long poly = 0; /* polynomial exclusive-or pattern */ - int i; /* counter for all possible eight bit values */ - int k; /* byte being shifted into crc apparatus */ - - /* terms of polynomial defining this crc (except x^32): */ - static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - crc_table = (unsigned long *) malloc(256 * sizeof(unsigned long)); - - /* Make exclusive-or pattern from polynomial (0xedb88320) */ - for (i = 0; i < sizeof(p)/sizeof(int); i++) - poly |= 1L << (31 - p[i]); - - /* Compute and print table of CRC's, five per line */ - for (i = 0; i < 256; i++) { - table_entry = i; - /* The idea to initialize the register with the byte instead of - * zero was stolen from Haruhiko Okumura's ar002 - */ - for (k = 8; k; k--) { - table_entry = table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> 1; - } - crc_table[i]=table_entry; - } -} - -/* =========================================================================== - * Write the output window window[0..outcnt-1] and update crc and bytes_out. - * (Used for the decompressed data only.) - */ -static void flush_window(void) -{ - int n; - - if (outcnt == 0) - return; - - for (n = 0; n < outcnt; n++) { - crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8); - } - - if (fwrite(window, 1, outcnt, out_file) != outcnt) { - error_msg_and_die("Couldnt write"); - } - bytes_out += (unsigned long) outcnt; - outcnt = 0; -} - -/* - * Free the malloc'ed tables built by huft_build(), which makes a linked - * list of the tables it made, with the links in a dummy first entry of - * each table. - * t: table to free - */ -static int huft_free(huft_t *t) -{ - huft_t *p, *q; - - /* Go through linked list, freeing from the malloced (t[-1]) address. */ - p = t; - while (p != (huft_t *) NULL) { - q = (--p)->v.t; - free((char *) p); - p = q; - } - return 0; -} - -/* Given a list of code lengths and a maximum table size, make a set of - * tables to decode that set of codes. Return zero on success, one if - * the given code set is incomplete (the tables are still built in this - * case), two if the input is invalid (all zero length codes or an - * oversubscribed set of lengths), and three if not enough memory. - * - * b: code lengths in bits (all assumed <= BMAX) - * n: number of codes (assumed <= N_MAX) - * s: number of simple-valued codes (0..s-1) - * d: list of base values for non-simple codes - * e: list of extra bits for non-simple codes - * t: result: starting table - * m: maximum lookup bits, returns actual - */ -static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s, - const unsigned short *d, const unsigned short *e, huft_t **t, int *m) -{ - unsigned a; /* counter for codes of length k */ - unsigned c[BMAX + 1]; /* bit length count table */ - unsigned f; /* i repeats in table every f entries */ - int g; /* maximum code length */ - int h; /* table level */ - register unsigned i; /* counter, current code */ - register unsigned j; /* counter */ - register int k; /* number of bits in current code */ - int l; /* bits per table (returned in m) */ - register unsigned *p; /* pointer into c[], b[], or v[] */ - register huft_t *q; /* points to current table */ - huft_t r; /* table entry for structure assignment */ - huft_t *u[BMAX]; /* table stack */ - unsigned v[N_MAX]; /* values in order of bit length */ - register int w; /* bits before this table == (l * h) */ - unsigned x[BMAX + 1]; /* bit offsets, then code stack */ - unsigned *xp; /* pointer into x */ - int y; /* number of dummy codes added */ - unsigned z; /* number of entries in current table */ - - /* Generate counts for each bit length */ - memset ((void *)(c), 0, sizeof(c)); - p = b; - i = n; - do { - c[*p]++; /* assume all entries <= BMAX */ - p++; /* Can't combine with above line (Solaris bug) */ - } while (--i); - if (c[0] == n) { /* null input--all zero length codes */ - *t = (huft_t *) NULL; - *m = 0; - return 0; - } - - /* Find minimum and maximum length, bound *m by those */ - l = *m; - for (j = 1; j <= BMAX; j++) - if (c[j]) - break; - k = j; /* minimum code length */ - if ((unsigned) l < j) - l = j; - for (i = BMAX; i; i--) - if (c[i]) - break; - g = i; /* maximum code length */ - if ((unsigned) l > i) - l = i; - *m = l; - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= c[j]) < 0) - return 2; /* bad input: more codes than bits */ - if ((y -= c[i]) < 0) - return 2; - c[i] += y; - - /* Generate starting offsets into the value table for each length */ - x[1] = j = 0; - p = c + 1; - xp = x + 2; - while (--i) { /* note that i == g from above */ - *xp++ = (j += *p++); - } - - /* Make a table of values in order of bit lengths */ - p = b; - i = 0; - do { - if ((j = *p++) != 0) - v[x[j]++] = i; - } while (++i < n); - - /* Generate the Huffman codes and for each, make the table entries */ - x[0] = i = 0; /* first Huffman code is zero */ - p = v; /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = -l; /* bits decoded == (l * h) */ - u[0] = (huft_t *) NULL; /* just to keep compilers happy */ - q = (huft_t *) NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) { - a = c[k]; - while (a--) { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l) { - h++; - w += l; /* previous table always l bits */ - - /* compute minimum size table less than or equal to l bits */ - z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */ - if ((f = 1 << (j = k - w)) > a + 1) { /* try a k-w bit table *//* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = c + k; - while (++j < z) { /* try smaller tables up to z bits */ - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } - } - z = 1 << j; /* table entries for j-bit table */ - - /* allocate and link in new table */ - if ((q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t))) == NULL) { - if (h) { - huft_free(u[0]); - } - return 3; /* not enough memory */ - } - hufts += z + 1; /* track memory usage */ - *t = q + 1; /* link to list for huft_free() */ - *(t = &(q->v.t)) = NULL; - u[h] = ++q; /* table starts after link */ - - /* connect to last table, if there is one */ - if (h) { - x[h] = i; /* save pattern for backing up */ - r.b = (unsigned char) l; /* bits to dump before this table */ - r.e = (unsigned char) (16 + j); /* bits in this table */ - r.v.t = q; /* pointer to this table */ - j = i >> (w - l); /* (get around Turbo C bug) */ - u[h - 1][j] = r; /* connect to last table */ - } - } - - /* set up table entry in r */ - r.b = (unsigned char) (k - w); - if (p >= v + n) - r.e = 99; /* out of values--invalid code */ - else if (*p < s) { - r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ - r.v.n = (unsigned short) (*p); /* simple code is just the value */ - p++; /* one compiler does not like *p++ */ - } else { - r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ - r.v.n = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - while ((i & ((1 << w) - 1)) != x[h]) { - h--; /* don't need to update q */ - w -= l; - } - } - } - /* Return true (1) if we were given an incomplete table */ - return y != 0 && g != 1; -} - -/* - * inflate (decompress) the codes in a deflated (compressed) block. - * Return an error code or zero if it all goes ok. - * - * tl, td: literal/length and distance decoder tables - * bl, bd: number of bits decoded by tl[] and td[] - */ -static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd) -{ - register unsigned long e; /* table entry flag/number of extra bits */ - unsigned long n, d; /* length and index for copy */ - unsigned long w; /* current window position */ - huft_t *t; /* pointer to table entry */ - unsigned ml, md; /* masks for bl and bd bits */ - register unsigned long b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ - - /* make local copies of globals */ - b = bb; /* initialize bit buffer */ - k = bk; - w = outcnt; /* initialize window position */ - - /* inflate the coded data */ - ml = mask_bits[bl]; /* precompute masks for speed */ - md = mask_bits[bd]; - for (;;) { /* do until end of block */ - while (k < (unsigned) bl) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) - do { - if (e == 99) { - return 1; - } - b >>= t->b; - k -= t->b; - e -= 16; - while (k < e) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); - b >>= t->b; - k -= t->b; - if (e == 16) { /* then it's a literal */ - window[w++] = (unsigned char) t->v.n; - if (w == WSIZE) { - outcnt=(w), - flush_window(); - w = 0; - } - } else { /* it's an EOB or a length */ - - /* exit if end of block */ - if (e == 15) { - break; - } - - /* get length of block to copy */ - while (k < e) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - n = t->v.n + ((unsigned) b & mask_bits[e]); - b >>= e; - k -= e; - - /* decode distance of block to copy */ - while (k < (unsigned) bd) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - - if ((e = (t = td + ((unsigned) b & md))->e) > 16) - do { - if (e == 99) - return 1; - b >>= t->b; - k -= t->b; - e -= 16; - while (k < e) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); - b >>= t->b; - k -= t->b; - while (k < e) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - d = w - t->v.n - ((unsigned) b & mask_bits[e]); - b >>= e; - k -= e; - - /* do the copy */ - do { - n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e); -#if !defined(NOMEMCPY) && !defined(DEBUG) - if (w - d >= e) { /* (this test assumes unsigned comparison) */ - memcpy(window + w, window + d, e); - w += e; - d += e; - } else /* do it slow to avoid memcpy() overlap */ -#endif /* !NOMEMCPY */ - do { - window[w++] = window[d++]; - } while (--e); - if (w == WSIZE) { - outcnt=(w), - flush_window(); - w = 0; - } - } while (n); - } - } - - /* restore the globals from the locals */ - outcnt = w; /* restore global window pointer */ - bb = b; /* restore global bit buffer */ - bk = k; - - /* done */ - return 0; -} - -/* - * decompress an inflated block - * e: last block flag - * - * GLOBAL VARIABLES: bb, kk, - */ -static int inflate_block(int *e) -{ - unsigned t; /* block type */ - register unsigned long b; /* bit buffer */ - register unsigned k; /* number of bits in bit buffer */ - static unsigned short cplens[] = { /* Copy lengths for literal codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 - }; - /* note: see note #13 above about the 258 in this list. */ - static unsigned short cplext[] = { /* Extra bits for literal codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 - }; /* 99==invalid */ - static unsigned short cpdist[] = { /* Copy offsets for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577 - }; - static unsigned short cpdext[] = { /* Extra bits for distance codes */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13 - }; - - /* make local bit buffer */ - b = bb; - k = bk; - - /* read in last block bit */ - while (k < 1) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - *e = (int) b & 1; - b >>= 1; - k -= 1; - - /* read in block type */ - while (k < 2) { - b |= ((unsigned long)fgetc(in_file)) << k; - k += 8; - } - t = (unsigned) b & 3; - b >>= 2; - k -= 2; - - /* restore the global bit buffer */ - bb = b; - bk = k; - - /* inflate that block type */ - switch (t) { - case 0: /* Inflate stored */ - { - unsigned long n; /* number of bytes in block */ - unsigned long w; /* current window position */ - register unsigned long b_stored; /* bit buffer */ - register unsigned long k_stored; /* number of bits in bit buffer */ - - /* make local copies of globals */ - b_stored = bb; /* initialize bit buffer */ - k_stored = bk; - w = outcnt; /* initialize window position */ - - /* go to byte boundary */ - n = k_stored & 7; - b_stored >>= n; - k_stored -= n; - - /* get the length and its complement */ - while (k_stored < 16) { - b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; - k_stored += 8; - } - n = ((unsigned) b_stored & 0xffff); - b_stored >>= 16; - k_stored -= 16; - while (k_stored < 16) { - b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; - k_stored += 8; - } - if (n != (unsigned) ((~b_stored) & 0xffff)) { - return 1; /* error in compressed data */ - } - b_stored >>= 16; - k_stored -= 16; - - /* read and output the compressed data */ - while (n--) { - while (k_stored < 8) { - b_stored |= ((unsigned long)fgetc(in_file)) << k_stored; - k_stored += 8; - } - window[w++] = (unsigned char) b_stored; - if (w == (unsigned long)WSIZE) { - outcnt=(w), - flush_window(); - w = 0; - } - b_stored >>= 8; - k_stored -= 8; - } - - /* restore the globals from the locals */ - outcnt = w; /* restore global window pointer */ - bb = b_stored; /* restore global bit buffer */ - bk = k_stored; - return 0; - } - case 1: /* Inflate fixed - * decompress an inflated type 1 (fixed Huffman codes) block. We should - * either replace this with a custom decoder, or at least precompute the - * Huffman tables. - */ - { - int i; /* temporary variable */ - huft_t *tl; /* literal/length code table */ - huft_t *td; /* distance code table */ - int bl; /* lookup bits for tl */ - int bd; /* lookup bits for td */ - unsigned int l[288]; /* length list for huft_build */ - - /* set up literal table */ - for (i = 0; i < 144; i++) { - l[i] = 8; - } - for (; i < 256; i++) { - l[i] = 9; - } - for (; i < 280; i++) { - l[i] = 7; - } - for (; i < 288; i++) { /* make a complete, but wrong code set */ - l[i] = 8; - } - bl = 7; - if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) { - return i; - } - - /* set up distance table */ - for (i = 0; i < 30; i++) { /* make an incomplete code set */ - l[i] = 5; - } - bd = 5; - if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) { - huft_free(tl); - return i; - } - - /* decompress until an end-of-block code */ - if (inflate_codes(tl, td, bl, bd)) - return 1; - - /* free the decoding tables, return */ - huft_free(tl); - huft_free(td); - return 0; - } - case 2: /* Inflate dynamic */ - { - /* Tables for deflate from PKZIP's appnote.txt. */ - static unsigned border[] = { /* Order of the bit length code lengths */ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 - }; - int dbits = 6; /* bits in base distance lookup table */ - int lbits = 9; /* bits in base literal/length lookup table */ - - int i; /* temporary variables */ - unsigned j; - unsigned l; /* last length */ - unsigned m; /* mask for bit lengths table */ - unsigned n; /* number of lengths to get */ - huft_t *tl; /* literal/length code table */ - huft_t *td; /* distance code table */ - int bl; /* lookup bits for tl */ - int bd; /* lookup bits for td */ - unsigned nb; /* number of bit length codes */ - unsigned nl; /* number of literal/length codes */ - unsigned nd; /* number of distance codes */ - - unsigned ll[286 + 30]; /* literal/length and distance code lengths */ - register unsigned long b_dynamic; /* bit buffer */ - register unsigned k_dynamic; /* number of bits in bit buffer */ - - /* make local bit buffer */ - b_dynamic = bb; - k_dynamic = bk; - - /* read in table lengths */ - while (k_dynamic < 5) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ - b_dynamic >>= 5; - k_dynamic -= 5; - while (k_dynamic < 5) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ - b_dynamic >>= 5; - k_dynamic -= 5; - while (k_dynamic < 4) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ - b_dynamic >>= 4; - k_dynamic -= 4; - if (nl > 286 || nd > 30) { - return 1; /* bad lengths */ - } - - /* read in bit-length-code lengths */ - for (j = 0; j < nb; j++) { - while (k_dynamic < 3) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - ll[border[j]] = (unsigned) b_dynamic & 7; - b_dynamic >>= 3; - k_dynamic -= 3; - } - for (; j < 19; j++) { - ll[border[j]] = 0; - } - - /* build decoding table for trees--single level, 7 bit lookup */ - bl = 7; - if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) { - if (i == 1) { - huft_free(tl); - } - return i; /* incomplete code set */ - } - - /* read in literal and distance code lengths */ - n = nl + nd; - m = mask_bits[bl]; - i = l = 0; - while ((unsigned) i < n) { - while (k_dynamic < (unsigned) bl) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - j = (td = tl + ((unsigned) b_dynamic & m))->b; - b_dynamic >>= j; - k_dynamic -= j; - j = td->v.n; - if (j < 16) { /* length of code in bits (0..15) */ - ll[i++] = l = j; /* save last length in l */ - } - else if (j == 16) { /* repeat last length 3 to 6 times */ - while (k_dynamic < 2) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - j = 3 + ((unsigned) b_dynamic & 3); - b_dynamic >>= 2; - k_dynamic -= 2; - if ((unsigned) i + j > n) { - return 1; - } - while (j--) { - ll[i++] = l; - } - } else if (j == 17) { /* 3 to 10 zero length codes */ - while (k_dynamic < 3) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - j = 3 + ((unsigned) b_dynamic & 7); - b_dynamic >>= 3; - k_dynamic -= 3; - if ((unsigned) i + j > n) { - return 1; - } - while (j--) { - ll[i++] = 0; - } - l = 0; - } else { /* j == 18: 11 to 138 zero length codes */ - while (k_dynamic < 7) { - b_dynamic |= ((unsigned long)fgetc(in_file)) << k_dynamic; - k_dynamic += 8; - } - j = 11 + ((unsigned) b_dynamic & 0x7f); - b_dynamic >>= 7; - k_dynamic -= 7; - if ((unsigned) i + j > n) { - return 1; - } - while (j--) { - ll[i++] = 0; - } - l = 0; - } - } - - /* free decoding table for trees */ - huft_free(tl); - - /* restore the global bit buffer */ - bb = b_dynamic; - bk = k_dynamic; - - /* build the decoding tables for literal/length and distance codes */ - bl = lbits; - if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) { - if (i == 1) { - error_msg("Incomplete literal tree"); - huft_free(tl); - } - return i; /* incomplete code set */ - } - bd = dbits; - if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { - if (i == 1) { - error_msg("incomplete distance tree"); - huft_free(td); - } - huft_free(tl); - return i; /* incomplete code set */ - } - - /* decompress until an end-of-block code */ - if (inflate_codes(tl, td, bl, bd)) - return 1; - - /* free the decoding tables, return */ - huft_free(tl); - huft_free(td); - return 0; - } - default: - /* bad block type */ - return 2; - } -} - -/* - * decompress an inflated entry - * - * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr - */ -static int inflate() -{ - int e; /* last block flag */ - int r; /* result code */ - unsigned h = 0; /* maximum struct huft's malloc'ed */ - - /* initialize window, bit buffer */ - outcnt = 0; - bk = 0; - bb = 0; - - /* decompress until the last block */ - do { - hufts = 0; - if ((r = inflate_block(&e)) != 0) { - return r; - } - if (hufts > h) { - h = hufts; - } - } while (!e); - - /* flush out window */ - flush_window(); - - /* return success */ - return 0; -} - -/* =========================================================================== - * Unzip in to out. This routine works on both gzip and pkzip files. - * - * IN assertions: the buffer inbuf contains already the beginning of - * the compressed data, from offsets inptr to insize-1 included. - * The magic header has already been checked. The output buffer is cleared. - * in, out: input and output file descriptors - */ -extern int unzip(FILE *l_in_file, FILE *l_out_file) -{ - const int extra_field = 0x04; /* bit 2 set: extra field present */ - const int orig_name = 0x08; /* bit 3 set: original file name present */ - const int comment = 0x10; /* bit 4 set: file comment present */ - unsigned char buf[8]; /* extended local header */ - unsigned char flags; /* compression flags */ - char magic[2]; /* magic header */ - int method; - typedef void (*sig_type) (int); - int exit_code=0; /* program exit code */ - int i; - - in_file = l_in_file; - out_file = l_out_file; - - if (signal(SIGINT, SIG_IGN) != SIG_IGN) { - (void) signal(SIGINT, (sig_type) abort_gzip); - } -#ifdef SIGTERM -// if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { -// (void) signal(SIGTERM, (sig_type) abort_gzip); -// } -#endif -#ifdef SIGHUP - if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { - (void) signal(SIGHUP, (sig_type) abort_gzip); - } -#endif - - /* Allocate all global buffers (for DYN_ALLOC option) */ - window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char))); - outcnt = 0; - bytes_out = 0L; - - magic[0] = fgetc(in_file); - magic[1] = fgetc(in_file); - - /* Magic header for gzip files, 1F 8B = \037\213 */ - if (memcmp(magic, "\037\213", 2) != 0) { - error_msg("Invalid gzip magic"); - return EXIT_FAILURE; - } - - method = (int) fgetc(in_file); - if (method != 8) { - error_msg("unknown method %d -- get newer version of gzip", method); - exit_code = 1; - return -1; - } - - flags = (unsigned char) fgetc(in_file); - - /* Ignore time stamp(4), extra flags(1), OS type(1) */ - for (i = 0; i < 6; i++) - fgetc(in_file); - - if ((flags & extra_field) != 0) { - size_t extra; - extra = fgetc(in_file); - extra += fgetc(in_file) << 8; - - for (i = 0; i < extra; i++) - fgetc(in_file); - } - - /* Discard original name if any */ - if ((flags & orig_name) != 0) { - while (fgetc(in_file) != 0); /* null */ - } - - /* Discard file comment if any */ - if ((flags & comment) != 0) { - while (fgetc(in_file) != 0); /* null */ - } - - if (method < 0) { - printf("it failed\n"); - return(exit_code); /* error message already emitted */ - } - - make_crc_table(); - - /* Decompress */ - if (method == 8) { - - int res = inflate(); - - if (res == 3) { - error_msg(memory_exhausted); - } else if (res != 0) { - error_msg("invalid compressed data--format violated"); - } - - } else { - error_msg("internal error, invalid method"); - } - - /* Get the crc and original length - * crc32 (see algorithm.doc) - * uncompressed input size modulo 2^32 - */ - fread(buf, 1, 8, in_file); - - /* Validate decompression - crc */ - if ((unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) { - error_msg("invalid compressed data--crc error"); - } - /* Validate decompression - size */ - if (((buf[4] | (buf[5] << 8)) |((buf[6] | (buf[7] << 8)) << 16)) != (unsigned long) bytes_out) { - error_msg("invalid compressed data--length error"); - } - - free(window); - free(crc_table); - - return 0; -} - -/* - * This needs access to global variables wondow and crc_table, so its not in its own file. - */ -extern void gz_close(int gunzip_pid) -{ - if (kill(gunzip_pid, SIGTERM) == -1) { - error_msg_and_die("*** Couldnt kill old gunzip process *** aborting"); - } - - if (waitpid(gunzip_pid, NULL, 0) == -1) { - printf("Couldnt wait ?"); - } - free(window); - free(crc_table); -} diff --git a/busybox/libbb/vdprintf.c b/busybox/libbb/vdprintf.c deleted file mode 100644 index 8c3e32a7a..000000000 --- a/busybox/libbb/vdprintf.c +++ /dev/null @@ -1,53 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "libbb.h" - - - -#if (__GLIBC__ < 2) -extern int vdprintf(int d, const char *format, va_list ap) -{ - char buf[BUF_SIZE]; - int len; - - len = vsprintf(buf, format, ap); - return write(d, buf, len); -} -#endif - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/verror_msg.c b/busybox/libbb/verror_msg.c deleted file mode 100644 index b34821561..000000000 --- a/busybox/libbb/verror_msg.c +++ /dev/null @@ -1,49 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include -#include "libbb.h" - -extern void verror_msg(const char *s, va_list p) -{ - fflush(stdout); - fprintf(stderr, "%s: ", applet_name); - vfprintf(stderr, s, p); -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/vherror_msg.c b/busybox/libbb/vherror_msg.c deleted file mode 100644 index ee0bb5009..000000000 --- a/busybox/libbb/vherror_msg.c +++ /dev/null @@ -1,44 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -extern int h_errno; - -#include - -#include "libbb.h" - -extern void vherror_msg(const char *s, va_list p) -{ - if(s == 0) - s = ""; - verror_msg(s, p); - if (*s) - fputs(": ", stderr); - herror(""); -} diff --git a/busybox/libbb/vperror_msg.c b/busybox/libbb/vperror_msg.c deleted file mode 100644 index ca9361e45..000000000 --- a/busybox/libbb/vperror_msg.c +++ /dev/null @@ -1,51 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include -#include "libbb.h" - -extern void vperror_msg(const char *s, va_list p) -{ - int err=errno; - if(s == 0) s = ""; - verror_msg(s, p); - if (*s) s = ": "; - fprintf(stderr, "%s%s\n", s, strerror(err)); -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/wfopen.c b/busybox/libbb/wfopen.c deleted file mode 100644 index 8b074d2f7..000000000 --- a/busybox/libbb/wfopen.c +++ /dev/null @@ -1,50 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include "libbb.h" - -FILE *wfopen(const char *path, const char *mode) -{ - FILE *fp; - if ((fp = fopen(path, mode)) == NULL) { - perror_msg("%s", path); - errno = 0; - } - return fp; -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/xfuncs.c b/busybox/libbb/xfuncs.c deleted file mode 100644 index eb93bf139..000000000 --- a/busybox/libbb/xfuncs.c +++ /dev/null @@ -1,112 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include -#include -#include -#include "libbb.h" - - -#ifndef DMALLOC -extern void *xmalloc(size_t size) -{ - void *ptr = malloc(size); - - if (!ptr) - error_msg_and_die(memory_exhausted); - return ptr; -} - -extern void *xrealloc(void *old, size_t size) -{ - void *ptr; - - /* SuS2 says "If size is 0 and ptr is not a null pointer, the - * object pointed to is freed." Do that here, in case realloc - * returns a NULL, since we don't want to choke in that case. */ - if (size==0 && old) { - free(old); - return NULL; - } - - ptr = realloc(old, size); - if (!ptr) - error_msg_and_die(memory_exhausted); - return ptr; -} - -extern void *xcalloc(size_t nmemb, size_t size) -{ - void *ptr = calloc(nmemb, size); - if (!ptr) - error_msg_and_die(memory_exhausted); - return ptr; -} - -extern char * xstrdup (const char *s) { - char *t; - - if (s == NULL) - return NULL; - - t = strdup (s); - - if (t == NULL) - error_msg_and_die(memory_exhausted); - - return t; -} -#endif - -extern char * xstrndup (const char *s, int n) { - char *t; - - if (s == NULL) - error_msg_and_die("xstrndup bug"); - - t = xmalloc(++n); - - return safe_strncpy(t,s,n); -} - -FILE *xfopen(const char *path, const char *mode) -{ - FILE *fp; - if ((fp = fopen(path, mode)) == NULL) - perror_msg_and_die("%s", path); - return fp; -} - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/libbb/xgetcwd.c b/busybox/libbb/xgetcwd.c deleted file mode 100644 index 4f7748123..000000000 --- a/busybox/libbb/xgetcwd.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * xgetcwd.c -- return current directory with unlimited length - * Copyright (C) 1992, 1996 Free Software Foundation, Inc. - * Written by David MacKenzie . - * - * Special function for busybox written by Vladimir Oleynik -*/ - -#include -#include -#include -#include -#include -#include "libbb.h" - -/* Amount to increase buffer size by in each try. */ -#define PATH_INCR 32 - -/* Return the current directory, newly allocated, arbitrarily long. - Return NULL and set errno on error. - If argument is not NULL (previous usage allocate memory), call free() -*/ - -char * -xgetcwd (char *cwd) -{ - char *ret; - unsigned path_max; - - errno = 0; - path_max = (unsigned) PATH_MAX; - path_max += 2; /* The getcwd docs say to do this. */ - - if(cwd==0) - cwd = xmalloc (path_max); - - errno = 0; - while ((ret = getcwd (cwd, path_max)) == NULL && errno == ERANGE) { - path_max += PATH_INCR; - cwd = xrealloc (cwd, path_max); - errno = 0; - } - - if (ret == NULL) { - int save_errno = errno; - free (cwd); - errno = save_errno; - perror_msg("getcwd()"); - return NULL; - } - - return cwd; -} diff --git a/busybox/libbb/xgethostbyname.c b/busybox/libbb/xgethostbyname.c deleted file mode 100644 index 258510332..000000000 --- a/busybox/libbb/xgethostbyname.c +++ /dev/null @@ -1,37 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini xgethostbyname implementation. - * - * - * 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 - * - */ - -#include -extern int h_errno; - -#include "libbb.h" - -struct hostent *xgethostbyname(const char *name) -{ - struct hostent *retval; - - if ((retval = gethostbyname(name)) == NULL) - herror_msg_and_die("%s", name); - - return retval; -} diff --git a/busybox/libbb/xreadlink.c b/busybox/libbb/xreadlink.c deleted file mode 100644 index 932e487a5..000000000 --- a/busybox/libbb/xreadlink.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * xreadlink.c - safe implementation of readlink. - * Returns a NULL on failure... - */ - -#include - -/* - * NOTE: This function returns a malloced char* that you will have to free - * yourself. You have been warned. - */ - -#include -#include "libbb.h" - -extern char *xreadlink(const char *path) -{ - static const int GROWBY = 80; /* how large we will grow strings by */ - - char *buf = NULL; - int bufsize = 0, readsize = 0; - - do { - buf = xrealloc(buf, bufsize += GROWBY); - readsize = readlink(path, buf, bufsize); /* 1st try */ - if (readsize == -1) { - perror_msg("%s:%s", applet_name, path); - return NULL; - } - } - while (bufsize < readsize + 1); - - buf[readsize] = '\0'; - - return buf; -} - diff --git a/busybox/libbb/xregcomp.c b/busybox/libbb/xregcomp.c deleted file mode 100644 index 6f5e2f0cb..000000000 --- a/busybox/libbb/xregcomp.c +++ /dev/null @@ -1,53 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) tons of folks. Tracking down who wrote what - * isn't something I'm going to worry about... If you wrote something - * here, please feel free to acknowledge your work. - * - * 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 - * - * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. - * - */ - -#include -#include "libbb.h" -#include - - - -void xregcomp(regex_t *preg, const char *regex, int cflags) -{ - int ret; - if ((ret = regcomp(preg, regex, cflags)) != 0) { - int errmsgsz = regerror(ret, preg, NULL, 0); - char *errmsg = xmalloc(errmsgsz); - regerror(ret, preg, errmsg, errmsgsz); - error_msg_and_die("xregcomp: %s", errmsg); - } -} - - -/* END CODE */ -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/ln.c b/busybox/ln.c deleted file mode 100644 index 7412a86fd..000000000 --- a/busybox/ln.c +++ /dev/null @@ -1,131 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini ln implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - - -static const int LN_SYMLINK = 1; -static const int LN_FORCE = 2; -static const int LN_NODEREFERENCE = 4; - -/* - * linkDestName is where the link points to, - * linkSrcName is the name of the link to be created. - */ -static int fs_link(const char *link_destname, const char *link_srcname, - const int flag) -{ - int status; - int src_is_dir; - char *src_name; - - if (link_destname==NULL) - return(FALSE); - - src_name = (char *) xmalloc(strlen(link_srcname)+strlen(link_destname)+1); - - if (link_srcname==NULL) - strcpy(src_name, link_destname); - else - strcpy(src_name, link_srcname); - - if (flag&LN_NODEREFERENCE) - src_is_dir = is_directory(src_name, TRUE, NULL); - else - src_is_dir = is_directory(src_name, FALSE, NULL); - - if ((src_is_dir==TRUE)&&((flag&LN_NODEREFERENCE)==0)) { - char* srcdir_name; - - srcdir_name = xstrdup(link_destname); - strcat(src_name, "/"); - strcat(src_name, get_last_path_component(srcdir_name)); - free(srcdir_name); - } - - if (flag&LN_FORCE) - unlink(src_name); - - if (flag&LN_SYMLINK) - status = symlink(link_destname, src_name); - else - status = link(link_destname, src_name); - - if (status != 0) { - perror_msg(src_name); - return(FALSE); - } - return(TRUE); -} - -extern int ln_main(int argc, char **argv) -{ - int status = EXIT_SUCCESS; - int flag = 0; - int opt; - - /* Parse any options */ - while ((opt=getopt(argc, argv, "sfn")) != -1) { - switch(opt) { - case 's': - flag |= LN_SYMLINK; - break; - case 'f': - flag |= LN_FORCE; - break; - case 'n': - flag |= LN_NODEREFERENCE; - break; - default: - show_usage(); - } - } - if (optind > (argc-1)) { - show_usage(); - } - if (optind == (argc-1)) { - if (fs_link(argv[optind], - get_last_path_component(argv[optind]), flag)==FALSE) - status = EXIT_FAILURE; - } - while(optind<(argc-1)) { - if (fs_link(argv[optind], argv[argc-1], flag)==FALSE) - status = EXIT_FAILURE; - optind++; - } - exit(status); -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/loadacm.c b/busybox/loadacm.c deleted file mode 100644 index 3fb4e7665..000000000 --- a/busybox/loadacm.c +++ /dev/null @@ -1,357 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Derived from - * mapscrn.c - version 0.92 - * - * Was taken from console-tools and adapted by - * Peter Novodvorsky - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -typedef unsigned short unicode; - -static long int ctoi(unsigned char *s, int *is_unicode); -static int old_screen_map_read_ascii(FILE * fp, unsigned char buf[]); -static int uni_screen_map_read_ascii(FILE * fp, unicode buf[], int *is_unicode); -static unicode utf8_to_ucs2(char *buf); -static int screen_map_load(int fd, FILE * fp); - -int loadacm_main(int argc, char **argv) -{ - int fd; - - if (argc>=2 && *argv[1]=='-') { - show_usage(); - } - - fd = open(CURRENT_VC, O_RDWR); - if (fd < 0) { - perror_msg_and_die("Error opening " CURRENT_VC); - } - - if (screen_map_load(fd, stdin)) { - perror_msg_and_die("Error loading acm"); - } - - write(fd, "\033(K", 3); - - return EXIT_SUCCESS; -} - -static int screen_map_load(int fd, FILE * fp) -{ - struct stat stbuf; - unicode wbuf[E_TABSZ]; - unsigned char buf[E_TABSZ]; - int parse_failed = 0; - int is_unicode; - - if (fstat(fileno(fp), &stbuf)) - perror_msg_and_die("Cannot stat map file"); - - /* first try a UTF screen-map: either ASCII (no restriction) or binary (regular file) */ - if (! - (parse_failed = - (-1 == uni_screen_map_read_ascii(fp, wbuf, &is_unicode))) -|| (S_ISREG(stbuf.st_mode) && (stbuf.st_size == (sizeof(unicode) * E_TABSZ)))) { /* test for binary UTF map by size */ - if (parse_failed) { - if (-1 == fseek(fp, 0, SEEK_SET)) { - if (errno == ESPIPE) - error_msg_and_die("16bit screen-map MUST be a regular file."); - else - perror_msg_and_die("fseek failed reading binary 16bit screen-map"); - } - - if (fread(wbuf, sizeof(unicode) * E_TABSZ, 1, fp) != 1) - perror_msg_and_die("Cannot read [new] map from file"); -#if 0 - else - error_msg("Input screen-map is binary."); -#endif - } - - /* if it was effectively a 16-bit ASCII, OK, else try to read as 8-bit map */ - /* same if it was binary, ie. if parse_failed */ - if (parse_failed || is_unicode) { - if (ioctl(fd, PIO_UNISCRNMAP, wbuf)) - perror_msg_and_die("PIO_UNISCRNMAP ioctl"); - else - return 0; - } - } - - /* rewind... */ - if (-1 == fseek(fp, 0, SEEK_SET)) { - if (errno == ESPIPE) - error_msg("Assuming 8bit screen-map - MUST be a regular file."), - exit(1); - else - perror_msg_and_die("fseek failed assuming 8bit screen-map"); - } - - /* ... and try an old 8-bit screen-map */ - if (!(parse_failed = (-1 == old_screen_map_read_ascii(fp, buf))) || - (S_ISREG(stbuf.st_mode) && (stbuf.st_size == E_TABSZ))) { /* test for binary old 8-bit map by size */ - if (parse_failed) { - if (-1 == fseek(fp, 0, SEEK_SET)) { - if (errno == ESPIPE) - /* should not - it succedeed above */ - error_msg_and_die("fseek() returned ESPIPE !"); - else - perror_msg_and_die("fseek for binary 8bit screen-map"); - } - - if (fread(buf, E_TABSZ, 1, fp) != 1) - perror_msg_and_die("Cannot read [old] map from file"); -#if 0 - else - error_msg("Input screen-map is binary."); -#endif - } - - if (ioctl(fd, PIO_SCRNMAP, buf)) - perror_msg_and_die("PIO_SCRNMAP ioctl"); - else - return 0; - } - error_msg("Error parsing symbolic map"); - return(1); -} - - -/* - * - reads `fp' as a 16-bit ASCII SFM file. - * - returns -1 on error. - * - returns it in `unicode' in an E_TABSZ-elements array. - * - sets `*is_unicode' flagiff there were any non-8-bit - * (ie. real 16-bit) mapping. - * - * FIXME: ignores everything after second word - */ -static int uni_screen_map_read_ascii(FILE * fp, unicode buf[], int *is_unicode) -{ - char buffer[256]; /* line buffer reading file */ - char *p, *q; /* 1st + 2nd words in line */ - int in, on; /* the same, as numbers */ - int tmp_is_unicode; /* tmp for is_unicode calculation */ - int i; /* loop index - result holder */ - int ret_code = 0; /* return code */ - sigset_t acmsigset, old_sigset; - - assert(is_unicode); - - *is_unicode = 0; - - /* first 128 codes defaults to ASCII */ - for (i = 0; i < 128; i++) - buf[i] = i; - /* remaining defaults to replacement char (usually E_TABSZ = 256) */ - for (; i < E_TABSZ; i++) - buf[i] = 0xfffd; - - /* block SIGCHLD */ - sigemptyset(&acmsigset); - sigaddset(&acmsigset, SIGCHLD); - sigprocmask(SIG_BLOCK, &acmsigset, &old_sigset); - - do { - if (NULL == fgets(buffer, sizeof(buffer), fp)) { - if (feof(fp)) - break; - else - perror_msg_and_die("uni_screen_map_read_ascii() can't read line"); - } - - /* get "charset-relative charcode", stripping leading spaces */ - p = strtok(buffer, " \t\n"); - - /* skip empty lines and comments */ - if (!p || *p == '#') - continue; - - /* get unicode mapping */ - q = strtok(NULL, " \t\n"); - if (q) { - in = ctoi(p, NULL); - if (in < 0 || in > 255) { - ret_code = -1; - break; - } - - on = ctoi(q, &tmp_is_unicode); - if (in < 0 && on > 65535) { - ret_code = -1; - break; - } - - *is_unicode |= tmp_is_unicode; - buf[in] = on; - } else { - ret_code = -1; - break; - } - } - while (1); /* terminated by break on feof() */ - - /* restore sig mask */ - sigprocmask(SIG_SETMASK, &old_sigset, NULL); - - return ret_code; -} - - -static int old_screen_map_read_ascii(FILE * fp, unsigned char buf[]) -{ - char buffer[256]; - int in, on; - char *p, *q; - - for (in = 0; in < 256; in++) - buf[in] = in; - - while (fgets(buffer, sizeof(buffer) - 1, fp)) { - p = strtok(buffer, " \t\n"); - - if (!p || *p == '#') - continue; - - q = strtok(NULL, " \t\n#"); - if (q) { - in = ctoi(p, NULL); - if (in < 0 || in > 255) - return -1; - - on = ctoi(q, NULL); - if (in < 0 && on > 255) - return -1; - - buf[in] = on; - } else - return -1; - } - - return (0); -} - - -/* - * - converts a string into an int. - * - supports dec and hex bytes, hex UCS2, single-quoted byte and UTF8 chars. - * - returns the converted value - * - if `is_unicode != NULL', use it to tell whether it was unicode - * - * CAVEAT: will report valid UTF mappings using only 1 byte as 8-bit ones. - */ -static long int ctoi(unsigned char *s, int *is_unicode) -{ - int i; - size_t ls; - - ls = strlen(s); - if (is_unicode) - *is_unicode = 0; - - /* hex-specified UCS2 */ - if ((strncmp(s, "U+", 2) == 0) && - (strspn(s + 2, "0123456789abcdefABCDEF") == ls - 2)) { - sscanf(s + 2, "%x", &i); - if (is_unicode) - *is_unicode = 1; - } - - /* hex-specified byte */ - else if ((ls <= 4) && (strncmp(s, "0x", 2) == 0) && - (strspn(s + 2, "0123456789abcdefABCDEF") == ls - 2)) - sscanf(s + 2, "%x", &i); - - /* oct-specified number (byte) */ - else if ((*s == '0') && (strspn(s, "01234567") == ls)) - sscanf(s, "%o", &i); - - /* dec-specified number (byte) */ - else if (strspn(s, "0123456789") == ls) - sscanf(s, "%d", &i); - - /* single-byte quoted char */ - else if ((strlen(s) == 3) && (s[0] == '\'') && (s[2] == '\'')) - i = s[1]; - - /* multi-byte UTF8 quoted char */ - else if ((s[0] == '\'') && (s[ls - 1] == '\'')) { - s[ls - 1] = 0; /* ensure we'll not "parse UTF too far" */ - i = utf8_to_ucs2(s + 1); - if (is_unicode) - *is_unicode = 1; - } else - return (-1); - - return (i); -} - - -static unicode utf8_to_ucs2(char *buf) -{ - int utf_count = 0; - long utf_char = 0; - unicode tc = 0; - unsigned char c; - - do { - c = *buf; - buf++; - - /* if byte should be part of multi-byte sequence */ - if (c & 0x80) { - /* if we have already started to parse a UTF8 sequence */ - if (utf_count > 0 && (c & 0xc0) == 0x80) { - utf_char = (utf_char << 6) | (c & 0x3f); - utf_count--; - if (utf_count == 0) - tc = utf_char; - else - continue; - } else { /* Possibly 1st char of a UTF8 sequence */ - - if ((c & 0xe0) == 0xc0) { - utf_count = 1; - utf_char = (c & 0x1f); - } else if ((c & 0xf0) == 0xe0) { - utf_count = 2; - utf_char = (c & 0x0f); - } else if ((c & 0xf8) == 0xf0) { - utf_count = 3; - utf_char = (c & 0x07); - } else if ((c & 0xfc) == 0xf8) { - utf_count = 4; - utf_char = (c & 0x03); - } else if ((c & 0xfe) == 0xfc) { - utf_count = 5; - utf_char = (c & 0x01); - } else - utf_count = 0; - continue; - } - } else { /* not part of multi-byte sequence - treat as ASCII - * this makes incomplete sequences to be ignored - */ - tc = c; - utf_count = 0; - } - } - while (utf_count); - - return tc; -} diff --git a/busybox/loadfont.c b/busybox/loadfont.c deleted file mode 100644 index d66500195..000000000 --- a/busybox/loadfont.c +++ /dev/null @@ -1,209 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * loadfont.c - Eugene Crosser & Andries Brouwer - * - * Version 0.96bb - * - * Loads the console font, and possibly the corresponding screen map(s). - * (Adapted for busybox by Matej Vela.) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -static const int PSF_MAGIC1 = 0x36; -static const int PSF_MAGIC2 = 0x04; - -static const int PSF_MODE512 = 0x01; -static const int PSF_MODEHASTAB = 0x02; -static const int PSF_MAXMODE = 0x03; -static const int PSF_SEPARATOR = 0xFFFF; - -struct psf_header { - unsigned char magic1, magic2; /* Magic number */ - unsigned char mode; /* PSF font mode */ - unsigned char charsize; /* Character size */ -}; - -#define PSF_MAGIC_OK(x) ((x).magic1 == PSF_MAGIC1 && (x).magic2 == PSF_MAGIC2) - -static void loadnewfont(int fd); - -extern int loadfont_main(int argc, char **argv) -{ - int fd; - - if (argc != 1) - show_usage(); - - fd = open(CURRENT_VC, O_RDWR); - if (fd < 0) - perror_msg_and_die("Error opening " CURRENT_VC); - loadnewfont(fd); - - return EXIT_SUCCESS; -} - -static void do_loadfont(int fd, char *inbuf, int unit, int fontsize) -{ - char buf[16384]; - int i; - - memset(buf, 0, sizeof(buf)); - - if (unit < 1 || unit > 32) - error_msg_and_die("Bad character size %d", unit); - - for (i = 0; i < fontsize; i++) - memcpy(buf + (32 * i), inbuf + (unit * i), unit); - -#if defined( PIO_FONTX ) && !defined( __sparc__ ) - { - struct consolefontdesc cfd; - - cfd.charcount = fontsize; - cfd.charheight = unit; - cfd.chardata = buf; - - if (ioctl(fd, PIO_FONTX, &cfd) == 0) - return; /* success */ - perror_msg("PIO_FONTX ioctl error (trying PIO_FONT)"); - } -#endif - if (ioctl(fd, PIO_FONT, buf)) - perror_msg_and_die("PIO_FONT ioctl error"); -} - -static void -do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize) -{ - struct unimapinit advice; - struct unimapdesc ud; - struct unipair *up; - int ct = 0, maxct; - int glyph; - u_short unicode; - - maxct = tailsz; /* more than enough */ - up = (struct unipair *) xmalloc(maxct * sizeof(struct unipair)); - - for (glyph = 0; glyph < fontsize; glyph++) { - while (tailsz >= 2) { - unicode = (((u_short) inbuf[1]) << 8) + inbuf[0]; - tailsz -= 2; - inbuf += 2; - if (unicode == PSF_SEPARATOR) - break; - up[ct].unicode = unicode; - up[ct].fontpos = glyph; - ct++; - } - } - - /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP - this printf did not work on many kernels */ - - advice.advised_hashsize = 0; - advice.advised_hashstep = 0; - advice.advised_hashlevel = 0; - if (ioctl(fd, PIO_UNIMAPCLR, &advice)) { -#ifdef ENOIOCTLCMD - if (errno == ENOIOCTLCMD) { - error_msg("It seems this kernel is older than 1.1.92"); - error_msg_and_die("No Unicode mapping table loaded."); - } else -#endif - perror_msg_and_die("PIO_UNIMAPCLR"); - } - ud.entry_ct = ct; - ud.entries = up; - if (ioctl(fd, PIO_UNIMAP, &ud)) { -#if 0 - if (errno == ENOMEM) { - /* change advice parameters */ - } -#endif - perror_msg_and_die("PIO_UNIMAP"); - } -} - -static void loadnewfont(int fd) -{ - int unit; - char inbuf[32768]; /* primitive */ - unsigned int inputlth, offset; - - /* - * We used to look at the length of the input file - * with stat(); now that we accept compressed files, - * just read the entire file. - */ - inputlth = fread(inbuf, 1, sizeof(inbuf), stdin); - if (ferror(stdin)) - perror_msg_and_die("Error reading input font"); - /* use malloc/realloc in case of giant files; - maybe these do not occur: 16kB for the font, - and 16kB for the map leaves 32 unicode values - for each font position */ - if (!feof(stdin)) - perror_msg_and_die("Font too large"); - - /* test for psf first */ - { - struct psf_header psfhdr; - int fontsize; - int hastable; - unsigned int head0, head; - - if (inputlth < sizeof(struct psf_header)) - goto no_psf; - - psfhdr = *(struct psf_header *) &inbuf[0]; - - if (!PSF_MAGIC_OK(psfhdr)) - goto no_psf; - - if (psfhdr.mode > PSF_MAXMODE) - error_msg_and_die("Unsupported psf file mode"); - fontsize = ((psfhdr.mode & PSF_MODE512) ? 512 : 256); -#if !defined( PIO_FONTX ) || defined( __sparc__ ) - if (fontsize != 256) - error_msg_and_die("Only fontsize 256 supported"); -#endif - hastable = (psfhdr.mode & PSF_MODEHASTAB); - unit = psfhdr.charsize; - head0 = sizeof(struct psf_header); - - head = head0 + fontsize * unit; - if (head > inputlth || (!hastable && head != inputlth)) - error_msg_and_die("Input file: bad length"); - do_loadfont(fd, inbuf + head0, unit, fontsize); - if (hastable) - do_loadtable(fd, inbuf + head, inputlth - head, fontsize); - return; - } - no_psf: - - /* file with three code pages? */ - if (inputlth == 9780) { - offset = 40; - unit = 16; - } else { - /* bare font */ - if (inputlth & 0377) - error_msg_and_die("Bad input file size"); - offset = 0; - unit = inputlth / 256; - } - do_loadfont(fd, inbuf + offset, unit, 256); -} diff --git a/busybox/loadkmap.c b/busybox/loadkmap.c deleted file mode 100644 index 4f217d630..000000000 --- a/busybox/loadkmap.c +++ /dev/null @@ -1,89 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini loadkmap implementation for busybox - * - * Copyright (C) 1998 Enrique Zanardi - * - * 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 "busybox.h" - -#define BINARY_KEYMAP_MAGIC "bkeymap" - -/* From */ -struct kbentry { - unsigned char kb_table; - unsigned char kb_index; - unsigned short kb_value; -}; -static const int KDSKBENT = 0x4B47; /* sets one entry in translation table */ - -/* From */ -static const int NR_KEYS = 128; -static const int MAX_NR_KEYMAPS = 256; - -int loadkmap_main(int argc, char **argv) -{ - struct kbentry ke; - u_short *ibuff; - int i, j, fd, readsz, pos, ibuffsz = NR_KEYS * sizeof(u_short); - char flags[MAX_NR_KEYMAPS], buff[7]; - - if (argc != 1) - show_usage(); - - fd = open(CURRENT_VC, O_RDWR); - if (fd < 0) - perror_msg_and_die("Error opening " CURRENT_VC); - - read(0, buff, 7); - if (0 != strncmp(buff, BINARY_KEYMAP_MAGIC, 7)) - error_msg_and_die("This is not a valid binary keymap."); - - if (MAX_NR_KEYMAPS != read(0, flags, MAX_NR_KEYMAPS)) - perror_msg_and_die("Error reading keymap flags"); - - ibuff = (u_short *) xmalloc(ibuffsz); - - for (i = 0; i < MAX_NR_KEYMAPS; i++) { - if (flags[i] == 1) { - pos = 0; - while (pos < ibuffsz) { - if ((readsz = read(0, (char *) ibuff + pos, ibuffsz - pos)) < 0) - perror_msg_and_die("Error reading keymap"); - pos += readsz; - } - for (j = 0; j < NR_KEYS; j++) { - ke.kb_index = j; - ke.kb_table = i; - ke.kb_value = ibuff[j]; - ioctl(fd, KDSKBENT, &ke); - } - } - } - /* Don't bother to close files. Exit does that - * automagically, so we can save a few bytes */ - /* close(fd); */ - return EXIT_SUCCESS; -} diff --git a/busybox/logger.c b/busybox/logger.c deleted file mode 100644 index 9f730915f..000000000 --- a/busybox/logger.c +++ /dev/null @@ -1,200 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini logger implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "busybox.h" -#if !defined BB_SYSLOGD - -#define SYSLOG_NAMES -#include - -#else -#include -# ifndef __dietlibc__ - /* We have to do this since the header file defines static - * structures. Argh.... bad libc, bad, bad... - */ - typedef struct _code { - char *c_name; - int c_val; - } CODE; - extern CODE prioritynames[]; - extern CODE facilitynames[]; -# endif -#endif - -/* Decode a symbolic name to a numeric value - * this function is based on code - * Copyright (c) 1983, 1993 - * The Regents of the University of California. All rights reserved. - * - * Original copyright notice is retained at the end of this file. - */ -static int decode(char *name, CODE * codetab) -{ - CODE *c; - - if (isdigit(*name)) - return (atoi(name)); - for (c = codetab; c->c_name; c++) { - if (!strcasecmp(name, c->c_name)) { - return (c->c_val); - } - } - - return (-1); -} - -/* Decode a symbolic name to a numeric value - * this function is based on code - * Copyright (c) 1983, 1993 - * The Regents of the University of California. All rights reserved. - * - * Original copyright notice is retained at the end of this file. - */ -static int pencode(char *s) -{ - char *save; - int lev, fac = LOG_USER; - - for (save = s; *s && *s != '.'; ++s); - if (*s) { - *s = '\0'; - fac = decode(save, facilitynames); - if (fac < 0) - error_msg_and_die("unknown facility name: %s", save); - *s++ = '.'; - } else { - s = save; - } - lev = decode(s, prioritynames); - if (lev < 0) - error_msg_and_die("unknown priority name: %s", save); - return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK)); -} - - -extern int logger_main(int argc, char **argv) -{ - int pri = LOG_USER | LOG_NOTICE; - int option = 0; - int c, i, len, opt; - char *message=NULL, buf[1024], name[128]; - - /* Fill out the name string early (may be overwritten later) */ - my_getpwuid(name, geteuid()); - - /* Parse any options */ - while ((opt = getopt(argc, argv, "p:st:")) > 0) { - switch (opt) { - case 's': - option |= LOG_PERROR; - break; - case 'p': - pri = pencode(optarg); - break; - case 't': - strncpy(name, optarg, sizeof(name)); - break; - default: - show_usage(); - } - } - - openlog(name, option, (pri | LOG_FACMASK)); - if (optind == argc) { - do { - /* read from stdin */ - i = 0; - while ((c = getc(stdin)) != EOF && c != '\n' && - i < (sizeof(buf)-1)) { - buf[i++] = c; - } - if (i > 0) { - buf[i++] = '\0'; - syslog(pri, "%s", buf); - } - } while (c != EOF); - } else { - len = 1; /* for the '\0' */ - message=xcalloc(1, 1); - for (i = optind; i < argc; i++) { - len += strlen(argv[i]); - len += 1; /* for the space between the args */ - message = xrealloc(message, len); - strcat(message, argv[i]); - strcat(message, " "); - } - message[strlen(message)-1] = '\0'; - syslog(pri, "%s", message); - } - - closelog(); - return EXIT_SUCCESS; -} - - -/*- - * Copyright (c) 1983, 1993 - * The Regents of the University of California. All rights reserved. - * - * This is the original license statement for the decode and pencode functions. - * - * 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. - */ - - - diff --git a/busybox/logname.c b/busybox/logname.c deleted file mode 100644 index 0924b2471..000000000 --- a/busybox/logname.c +++ /dev/null @@ -1,41 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini logname implementation for busybox - * - * 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 - * - */ - -#include -#include -#include -#include "busybox.h" - -extern int logname_main(int argc, char **argv) -{ - char user[9]; - - if (argc > 1) - show_usage(); - - my_getpwuid(user, geteuid()); - if (*user) { - puts(user); - return EXIT_SUCCESS; - } - error_msg_and_die("no login name"); -} diff --git a/busybox/logread.c b/busybox/logread.c deleted file mode 100644 index d3349625c..000000000 --- a/busybox/logread.c +++ /dev/null @@ -1,144 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * circular buffer syslog implementation for busybox - * - * Copyright (C) 2000 by Gennady Feldman - * - * Maintainer: Gennady Feldman as of Mar 12, 2001 - * - * 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" - -#if __GNU_LIBRARY__ < 5 -#error Sorry. Looks like you are using libc5. -#error libc5 shm support isnt good enough. -#error Please disable BB_FEATURE_IPC_SYSLOG -#endif - - -static const long KEY_ID = 0x414e4547; /*"GENA"*/ - -static struct shbuf_ds { - int size; // size of data written - int head; // start of message list - int tail; // end of message list - char data[1]; // data/messages -} *buf = NULL; // shared memory pointer - - -// Semaphore operation structures -static struct sembuf SMrup[1] = {{0, -1, IPC_NOWAIT | SEM_UNDO}}; // set SMrup -static struct sembuf SMrdn[2] = {{1, 0}, {0, +1, SEM_UNDO}}; // set SMrdn - -static int log_shmid = -1; // ipc shared memory id -static int log_semid = -1; // ipc semaphore id -static jmp_buf jmp_env; - -static void error_exit(const char *str); -static void interrupted(int sig); - -/* - * sem_up - up()'s a semaphore. - */ -static inline void sem_up(int semid) -{ - if ( semop(semid, SMrup, 1) == -1 ) - error_exit("semop[SMrup]"); -} - -/* - * sem_down - down()'s a semaphore - */ -static inline void sem_down(int semid) -{ - if ( semop(semid, SMrdn, 2) == -1 ) - error_exit("semop[SMrdn]"); -} - -extern int logread_main(int argc, char **argv) -{ - int i; - - /* no options, no getopt */ - if (argc > 1) - show_usage(); - - // handle intrrupt signal - if (setjmp(jmp_env)) goto output_end; - - // attempt to redefine ^C signal - signal(SIGINT, interrupted); - - if ( (log_shmid = shmget(KEY_ID, 0, 0)) == -1) - error_exit("Can't find circular buffer"); - - // Attach shared memory to our char* - if ( (buf = shmat(log_shmid, NULL, SHM_RDONLY)) == NULL) - error_exit("Can't get access to circular buffer from syslogd"); - - if ( (log_semid = semget(KEY_ID, 0, 0)) == -1) - error_exit("Can't get access to semaphone(s) for circular buffer from syslogd"); - - sem_down(log_semid); - // Read Memory - i=buf->head; - - //printf("head: %i tail: %i size: %i\n",buf->head,buf->tail,buf->size); - if (buf->head == buf->tail) { - printf("\n"); - } - - while ( i != buf->tail) { - printf("%s", buf->data+i); - i+= strlen(buf->data+i) + 1; - if (i >= buf->size ) - i=0; - } - sem_up(log_semid); - -output_end: - if (log_shmid != -1) - shmdt(buf); - - return EXIT_SUCCESS; -} - -static void interrupted(int sig){ - signal(SIGINT, SIG_IGN); - longjmp(jmp_env, 1); -} - -static void error_exit(const char *str){ - perror(str); - //release all acquired resources - if (log_shmid != -1) - shmdt(buf); - - exit(1); -} diff --git a/busybox/ls.c b/busybox/ls.c deleted file mode 100644 index 8d0282dfe..000000000 --- a/busybox/ls.c +++ /dev/null @@ -1,937 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * 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. - */ - -/* - * 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 - * linking in substantial chunks of libc can be disabled. - * - * Although I don't really want to add new features to this program to - * keep it small, I *am* interested to receive bug fixes and ways to make - * it more portable. - * - * 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 - * - * NON-OPTIMAL BEHAVIOUR: - * 1. autowidth reads directories twice - * 2. if you do a short directory listing without filetype characters - * appended, there's no need to stat each one - * PORTABILITY: - * 1. requires lstat (BSD) - how do you do it without? - */ - -enum { - TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */ - COLUMN_WIDTH = 14, /* default if AUTOWIDTH not defined */ - COLUMN_GAP = 2, /* includes the file type char */ -}; - - -/************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#ifdef BB_FEATURE_LS_TIMESTAMPS -#include -#endif - -#ifndef MAJOR -#define MAJOR(dev) (((dev)>>8)&0xff) -#define MINOR(dev) ((dev)&0xff) -#endif - -/* what is the overall style of the listing */ -enum { -STYLE_AUTO = 0, -STYLE_LONG = 1, /* one record per line, extended info */ -STYLE_SINGLE = 2, /* one record per line */ -STYLE_COLUMNS = 3 /* fill columns */ -}; - -/* 51306 lrwxrwxrwx 1 root root 2 May 11 01:43 /bin/view -> vi* */ -/* what file information will be listed */ -#define LIST_INO (1<<0) -#define LIST_BLOCKS (1<<1) -#define LIST_MODEBITS (1<<2) -#define LIST_NLINKS (1<<3) -#define LIST_ID_NAME (1<<4) -#define LIST_ID_NUMERIC (1<<5) -#define LIST_SIZE (1<<6) -#define LIST_DEV (1<<7) -#define LIST_DATE_TIME (1<<8) -#define LIST_FULLTIME (1<<9) -#define LIST_FILENAME (1<<10) -#define LIST_SYMLINK (1<<11) -#define LIST_FILETYPE (1<<12) -#define LIST_EXEC (1<<13) - -/* what files will be displayed */ -#define DISP_NORMAL (0) /* show normal filenames */ -#define DISP_DIRNAME (1<<0) /* 2 or more items? label directories */ -#define DISP_HIDDEN (1<<1) /* show filenames starting with . */ -#define DISP_DOT (1<<2) /* show . and .. */ -#define DISP_NOLIST (1<<3) /* show directory as itself, not contents */ -#define DISP_RECURSIVE (1<<4) /* show directory and everything below it */ -#define DISP_ROWS (1<<5) /* print across rows */ - -#ifdef BB_FEATURE_LS_SORTFILES -/* how will the files be sorted */ -static const int SORT_FORWARD = 0; /* sort in reverse order */ -static const int SORT_REVERSE = 1; /* sort in reverse order */ -static const int SORT_NAME = 2; /* sort by file name */ -static const int SORT_SIZE = 3; /* sort by file size */ -static const int SORT_ATIME = 4; /* sort by last access time */ -static const int SORT_CTIME = 5; /* sort by last change time */ -static const int SORT_MTIME = 6; /* sort by last modification time */ -static const int SORT_VERSION = 7; /* sort by version */ -static const int SORT_EXT = 8; /* sort by file name extension */ -static const int SORT_DIR = 9; /* sort by file or directory */ -#endif - -#ifdef BB_FEATURE_LS_TIMESTAMPS -/* which of the three times will be used */ -static const int TIME_MOD = 0; -static const int TIME_CHANGE = 1; -static const int TIME_ACCESS = 2; -#endif - -#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) - -static const int SPLIT_DIR = 0; -static const int SPLIT_FILE = 1; -static const int SPLIT_SUBDIR = 2; - -#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f) -#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)]) -#ifdef BB_FEATURE_LS_FILETYPES -#define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)]) -#endif - -/* - * 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 */ - struct dnode *next; /* point at the next node */ -}; -typedef struct dnode dnode_t; - -static struct dnode **list_dir(char *); -static struct dnode **dnalloc(int); -static int list_single(struct dnode *); - -static unsigned int disp_opts; -static unsigned int style_fmt; -static unsigned int list_fmt; -#ifdef BB_FEATURE_LS_SORTFILES -static unsigned int sort_opts; -static unsigned int sort_order; -#endif -#ifdef BB_FEATURE_LS_TIMESTAMPS -static unsigned int time_fmt; -#endif -#ifdef BB_FEATURE_LS_FOLLOWLINKS -static unsigned int follow_links=FALSE; -#endif - -static unsigned short column = 0; -#ifdef BB_FEATURE_AUTOWIDTH -static unsigned short terminal_width = TERMINAL_WIDTH; -static unsigned short column_width = COLUMN_WIDTH; -static unsigned short tabstops = COLUMN_GAP; -#else -static unsigned short column_width = COLUMN_WIDTH; -#endif - -static int status = EXIT_SUCCESS; - -#ifdef BB_FEATURE_HUMAN_READABLE -static unsigned long ls_disp_hr = 0; -#endif - -static int my_stat(struct dnode *cur) -{ -#ifdef BB_FEATURE_LS_FOLLOWLINKS - if (follow_links == TRUE) { - if (stat(cur->fullname, &cur->dstat)) { - perror_msg("%s", cur->fullname); - status = EXIT_FAILURE; - free(cur->fullname); - free(cur); - return -1; - } - } else -#endif - if (lstat(cur->fullname, &cur->dstat)) { - perror_msg("%s", cur->fullname); - status = EXIT_FAILURE; - free(cur->fullname); - free(cur); - return -1; - } - return 0; -} - -static void newline(void) -{ - if (column > 0) { - putchar('\n'); - column = 0; - } -} - -/*----------------------------------------------------------------------*/ -#ifdef BB_FEATURE_LS_FILETYPES -static char append_char(mode_t mode) -{ - if ( !(list_fmt & LIST_FILETYPE)) - return '\0'; - if ((list_fmt & LIST_EXEC) && S_ISREG(mode) - && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return '*'; - return APPCHAR(mode); -} -#endif - -/*----------------------------------------------------------------------*/ -static void nexttabstop( void ) -{ - static short nexttab= 0; - int n=0; - - if (column > 0) { - n= nexttab - column; - if (n < 1) n= 1; - while (n--) { - putchar(' '); - column++; - } - } - nexttab= column + column_width + COLUMN_GAP; -} - -/*----------------------------------------------------------------------*/ -static int is_subdir(struct dnode *dn) -{ - return (S_ISDIR(dn->dstat.st_mode) && strcmp(dn->name, ".") != 0 && - strcmp(dn->name, "..") != 0); -} - -static int countdirs(struct dnode **dn, int nfiles) -{ - int i, dirs; - - if (dn==NULL || nfiles < 1) return(0); - dirs= 0; - for (i=0; idstat.st_mode)) dirs++; - } - return(dirs); -} - -static int countsubdirs(struct dnode **dn, int nfiles) -{ - int i, subdirs; - - if (dn == NULL || nfiles < 1) return 0; - subdirs = 0; - for (i = 0; i < nfiles; i++) - if (is_subdir(dn[i])) - subdirs++; - return subdirs; -} - -static int countfiles(struct dnode **dnp) -{ - int nfiles; - struct dnode *cur; - - if (dnp == NULL) return(0); - nfiles= 0; - for (cur= dnp[0]; cur->next != NULL ; cur= cur->next) nfiles++; - 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); - - p= (struct dnode **)xcalloc((size_t)num, (size_t)(sizeof(struct dnode *))); - return(p); -} - -#ifdef BB_FEATURE_LS_RECURSIVE -static void dfree(struct dnode **dnp) -{ - struct dnode *cur, *next; - - if(dnp == NULL) return; - - cur=dnp[0]; - while (cur != NULL) { - if (cur->fullname != NULL) free(cur->fullname); /* free the filename */ - next= cur->next; - free(cur); /* free the dnode */ - cur= next; - } - free(dnp); /* free the array holding the dnode pointers */ -} -#endif - -static struct dnode **splitdnarray(struct dnode **dn, int nfiles, int which) -{ - int dncnt, i, d; - struct dnode **dnp; - - if (dn==NULL || nfiles < 1) return(NULL); - - /* count how many dirs and regular files there are */ - if (which == SPLIT_SUBDIR) - dncnt = countsubdirs(dn, nfiles); - else { - dncnt= countdirs(dn, nfiles); /* assume we are looking for dirs */ - if (which == SPLIT_FILE) - dncnt= nfiles - dncnt; /* looking for files */ - } - - /* allocate a file array and a dir array */ - dnp= dnalloc(dncnt); - - /* copy the entrys into the file or dir array */ - for (d= i=0; idstat.st_mode)) { - dnp[d++]= dn[i]; - } /* else skip the file */ - } else if (which == SPLIT_SUBDIR) { - if (is_subdir(dn[i])) { - dnp[d++]= dn[i]; - } /* else skip the file or dir */ - } else { - if (!(S_ISDIR(dn[i]->dstat.st_mode))) { - dnp[d++]= dn[i]; - } /* else skip the dir */ - } - } - return(dnp); -} - -/*----------------------------------------------------------------------*/ -#ifdef BB_FEATURE_LS_SORTFILES -static int sortcmp(struct dnode *d1, struct dnode *d2) -{ - int cmp, dif; - - cmp= 0; - if (sort_opts == SORT_SIZE) { - dif= (int)(d1->dstat.st_size - d2->dstat.st_size); - } else if (sort_opts == SORT_ATIME) { - dif= (int)(d1->dstat.st_atime - d2->dstat.st_atime); - } else if (sort_opts == SORT_CTIME) { - dif= (int)(d1->dstat.st_ctime - d2->dstat.st_ctime); - } else if (sort_opts == SORT_MTIME) { - dif= (int)(d1->dstat.st_mtime - d2->dstat.st_mtime); - } else if (sort_opts == SORT_DIR) { - dif= S_ISDIR(d1->dstat.st_mode) - S_ISDIR(d2->dstat.st_mode); - /* } else if (sort_opts == SORT_VERSION) { */ - /* } else if (sort_opts == SORT_EXT) { */ - } else { /* assume SORT_NAME */ - dif= 0; - } - - if (dif > 0) cmp= -1; - if (dif < 0) cmp= 1; - if (dif == 0) { - /* sort by name- may be a tie_breaker for time or size cmp */ - dif= strcmp(d1->name, d2->name); - if (dif > 0) cmp= 1; - if (dif < 0) cmp= -1; - } - - if (sort_order == SORT_REVERSE) { - cmp= -1 * cmp; - } - return(cmp); -} - -/*----------------------------------------------------------------------*/ -static void shellsort(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=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; - } - } - } -} -#endif - -/*----------------------------------------------------------------------*/ -static void showfiles(struct dnode **dn, int nfiles) -{ - int i, ncols, nrows, row, nc; -#ifdef BB_FEATURE_AUTOWIDTH - int len; -#endif - - if(dn==NULL || nfiles < 1) return; - -#ifdef BB_FEATURE_AUTOWIDTH - /* find the longest file name- use that as the column width */ - column_width= 0; - for (i=0; iname) + - ((list_fmt & LIST_INO) ? 8 : 0) + - ((list_fmt & LIST_BLOCKS) ? 5 : 0) - ; - if (column_width < len) - column_width= len; - } - if (column_width >= 6) - ncols = (int)(terminal_width / (column_width + COLUMN_GAP)); - else { - ncols = 1; - column_width = COLUMN_WIDTH; - } -#else - ncols= TERMINAL_WIDTH; -#endif - switch (style_fmt) { - case STYLE_LONG: /* one record per line, extended info */ - case STYLE_SINGLE: /* one record per line */ - ncols= 1; - break; - } - - if (ncols > 1) { - nrows = nfiles / ncols; - } else { - nrows = nfiles; - ncols = 1; - } - if ((nrows * ncols) < nfiles) nrows++; /* round up fractionals */ - - if (nrows > nfiles) nrows= nfiles; - for (row=0; rowfullname); - } - subdnp= list_dir(dn[i]->fullname); - nfiles= countfiles(subdnp); - if (nfiles > 0) { - /* list all files at this level */ -#ifdef BB_FEATURE_LS_SORTFILES - shellsort(subdnp, nfiles); -#endif - showfiles(subdnp, nfiles); -#ifdef BB_FEATURE_LS_RECURSIVE - if (disp_opts & DISP_RECURSIVE) { - /* recursive- list the sub-dirs */ - dnd= splitdnarray(subdnp, nfiles, SPLIT_SUBDIR); - dndirs= countsubdirs(subdnp, nfiles); - if (dndirs > 0) { -#ifdef BB_FEATURE_LS_SORTFILES - shellsort(dnd, dndirs); -#endif - showdirs(dnd, dndirs); - free(dnd); /* free the array of dnode pointers to the dirs */ - } - } - dfree(subdnp); /* free the dnodes and the fullname mem */ -#endif - } - } -} - -/*----------------------------------------------------------------------*/ -static struct dnode **list_dir(char *path) -{ - struct dnode *dn, *cur, **dnp; - struct dirent *entry; - DIR *dir; - int i, nfiles; - - if (path==NULL) return(NULL); - - dn= NULL; - nfiles= 0; - dir = opendir(path); - if (dir == NULL) { - perror_msg("%s", path); - status = EXIT_FAILURE; - return(NULL); /* could not open the dir */ - } - while ((entry = readdir(dir)) != NULL) { - /* are we going to list the file- it may be . or .. or a hidden file */ - if ((strcmp(entry->d_name, ".")==0) && !(disp_opts & DISP_DOT)) - continue; - if ((strcmp(entry->d_name, "..")==0) && !(disp_opts & DISP_DOT)) - continue; - if ((entry->d_name[0] == '.') && !(disp_opts & DISP_HIDDEN)) - continue; - cur= (struct dnode *)xmalloc(sizeof(struct dnode)); - cur->fullname = concat_path_file(path, entry->d_name); - cur->name = cur->fullname + - (strlen(cur->fullname) - strlen(entry->d_name)); - if (my_stat(cur)) - continue; - cur->next= dn; - dn= cur; - nfiles++; - } - closedir(dir); - - /* now that we know how many files there are - ** allocate memory for an array to hold dnode pointers - */ - if (nfiles < 1) return(NULL); - dnp= dnalloc(nfiles); - for (i=0, cur=dn; inext; - } - - return(dnp); -} - -/*----------------------------------------------------------------------*/ -static int list_single(struct dnode *dn) -{ - int i; - char scratch[BUFSIZ + 1]; -#ifdef BB_FEATURE_LS_TIMESTAMPS - char *filetime; - time_t ttime, age; -#endif -#if defined (BB_FEATURE_LS_FILETYPES) - struct stat info; -#endif -#ifdef BB_FEATURE_LS_FILETYPES - char append; -#endif - - if (dn==NULL || dn->fullname==NULL) return(0); - -#ifdef BB_FEATURE_LS_TIMESTAMPS - ttime= dn->dstat.st_mtime; /* the default time */ - if (time_fmt & TIME_ACCESS) ttime= dn->dstat.st_atime; - if (time_fmt & TIME_CHANGE) ttime= dn->dstat.st_ctime; - filetime= ctime(&ttime); -#endif -#ifdef BB_FEATURE_LS_FILETYPES - append = append_char(dn->dstat.st_mode); -#endif - - for (i=0; i<=31; i++) { - switch (list_fmt & (1<dstat.st_ino); - column += 8; - break; - case LIST_BLOCKS: -#ifdef BB_FEATURE_HUMAN_READABLE - fprintf(stdout, "%6s ", make_human_readable_str(dn->dstat.st_blocks>>1, - KILOBYTE, (ls_disp_hr==TRUE)? 0: KILOBYTE)); -#else -#if _FILE_OFFSET_BITS == 64 - printf("%4lld ", dn->dstat.st_blocks>>1); -#else - printf("%4ld ", dn->dstat.st_blocks>>1); -#endif -#endif - column += 5; - break; - case LIST_MODEBITS: - printf("%-10s ", (char *)mode_string(dn->dstat.st_mode)); - column += 10; - break; - case LIST_NLINKS: - printf("%4ld ", (long)dn->dstat.st_nlink); - column += 10; - break; - case LIST_ID_NAME: -#ifdef BB_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; -#endif - case LIST_ID_NUMERIC: - printf("%-8d %-8d", dn->dstat.st_uid, dn->dstat.st_gid); - column += 17; - break; - case LIST_SIZE: - case LIST_DEV: - if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) { - printf("%4d, %3d ", (int)MAJOR(dn->dstat.st_rdev), (int)MINOR(dn->dstat.st_rdev)); - } else { -#ifdef BB_FEATURE_HUMAN_READABLE - if (ls_disp_hr==TRUE) { - fprintf(stdout, "%8s ", make_human_readable_str(dn->dstat.st_size, 1, 0)); - } else -#endif - { -#if _FILE_OFFSET_BITS == 64 - printf("%9lld ", (long long)dn->dstat.st_size); -#else - printf("%9ld ", dn->dstat.st_size); -#endif - } - } - column += 10; - break; -#ifdef BB_FEATURE_LS_TIMESTAMPS - case LIST_FULLTIME: - case LIST_DATE_TIME: - if (list_fmt & LIST_FULLTIME) { - printf("%24.24s ", filetime); - column += 25; - break; - } - age = time(NULL) - ttime; - printf("%6.6s ", filetime+4); - if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) { - /* hh:mm if less than 6 months old */ - printf("%5.5s ", filetime+11); - } else { - printf(" %4.4s ", filetime+20); - } - column += 13; - break; -#endif - case LIST_FILENAME: - printf("%s", dn->name); - column += strlen(dn->name); - break; - case LIST_SYMLINK: - if (S_ISLNK(dn->dstat.st_mode)) { - char *lpath = xreadlink(dn->fullname); - if (lpath) { - printf(" -> %s", lpath); -#ifdef BB_FEATURE_LS_FILETYPES - if (!stat(dn->fullname, &info)) { - append = append_char(info.st_mode); - } -#endif - column += strlen(lpath) + 4; - free(lpath); - } - } - break; -#ifdef BB_FEATURE_LS_FILETYPES - case LIST_FILETYPE: - if (append != '\0') { - printf("%1c", append); - column++; - } - break; -#endif - } - } - - return(0); -} - -/*----------------------------------------------------------------------*/ -extern int ls_main(int argc, 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 BB_FEATURE_AUTOWIDTH - struct winsize win = { 0, 0, 0, 0 }; -#endif - - disp_opts= DISP_NORMAL; - style_fmt= STYLE_AUTO; - list_fmt= LIST_SHORT; -#ifdef BB_FEATURE_LS_SORTFILES - sort_opts= SORT_NAME; - sort_order= SORT_FORWARD; -#endif -#ifdef BB_FEATURE_LS_TIMESTAMPS - time_fmt= TIME_MOD; -#endif -#ifdef BB_FEATURE_AUTOWIDTH - ioctl(fileno(stdout), TIOCGWINSZ, &win); - if (win.ws_row > 4) - column_width = win.ws_row - 2; - if (win.ws_col > 0) - terminal_width = win.ws_col - 1; -#endif - nfiles=0; - - /* process options */ - while ((opt = getopt(argc, argv, "1AaCdgilnsx" -#ifdef BB_FEATURE_AUTOWIDTH -"T:w:" -#endif -#ifdef BB_FEATURE_LS_FILETYPES -"Fp" -#endif -#ifdef BB_FEATURE_LS_RECURSIVE -"R" -#endif -#ifdef BB_FEATURE_LS_SORTFILES -"rSvX" -#endif -#ifdef BB_FEATURE_LS_TIMESTAMPS -"cetu" -#endif -#ifdef BB_FEATURE_LS_FOLLOWLINKS -"L" -#endif -#ifdef BB_FEATURE_HUMAN_READABLE -"h" -#endif -"k")) > 0) { - switch (opt) { - case '1': style_fmt = STYLE_SINGLE; break; - case 'A': disp_opts |= DISP_HIDDEN; break; - case 'a': disp_opts |= DISP_HIDDEN | DISP_DOT; break; - case 'C': style_fmt = STYLE_COLUMNS; break; - case 'd': disp_opts |= DISP_NOLIST; break; - case 'g': /* ignore -- for ftp servers */ break; - case 'i': list_fmt |= LIST_INO; break; - case 'l': - style_fmt = STYLE_LONG; - list_fmt |= LIST_LONG; -#ifdef BB_FEATURE_HUMAN_READABLE - ls_disp_hr = FALSE; -#endif - break; - case 'n': list_fmt |= LIST_ID_NUMERIC; break; - case 's': list_fmt |= LIST_BLOCKS; break; - case 'x': disp_opts = DISP_ROWS; break; -#ifdef BB_FEATURE_LS_FILETYPES - case 'F': list_fmt |= LIST_FILETYPE | LIST_EXEC; break; - case 'p': list_fmt |= LIST_FILETYPE; break; -#endif -#ifdef BB_FEATURE_LS_RECURSIVE - case 'R': disp_opts |= DISP_RECURSIVE; break; -#endif -#ifdef BB_FEATURE_LS_SORTFILES - case 'r': sort_order |= SORT_REVERSE; break; - case 'S': sort_opts= SORT_SIZE; break; - case 'v': sort_opts= SORT_VERSION; break; - case 'X': sort_opts= SORT_EXT; break; -#endif -#ifdef BB_FEATURE_LS_TIMESTAMPS - case 'e': list_fmt |= LIST_FULLTIME; break; - case 'c': - time_fmt = TIME_CHANGE; -#ifdef BB_FEATURE_LS_SORTFILES - sort_opts= SORT_CTIME; -#endif - break; - case 'u': - time_fmt = TIME_ACCESS; -#ifdef BB_FEATURE_LS_SORTFILES - sort_opts= SORT_ATIME; -#endif - break; - case 't': -#ifdef BB_FEATURE_LS_SORTFILES - sort_opts= SORT_MTIME; -#endif - break; -#endif -#ifdef BB_FEATURE_LS_FOLLOWLINKS - case 'L': follow_links= TRUE; break; -#endif -#ifdef BB_FEATURE_AUTOWIDTH - case 'T': tabstops= atoi(optarg); break; - case 'w': terminal_width= atoi(optarg); break; -#endif -#ifdef BB_FEATURE_HUMAN_READABLE - case 'h': ls_disp_hr = TRUE; break; -#endif - case 'k': break; - default: - goto print_usage_message; - } - } - - /* sort out which command line options take precedence */ -#ifdef BB_FEATURE_LS_RECURSIVE - if (disp_opts & DISP_NOLIST) - disp_opts &= ~DISP_RECURSIVE; /* no recurse if listing only dir */ -#endif -#if defined (BB_FEATURE_LS_TIMESTAMPS) && defined (BB_FEATURE_LS_SORTFILES) - if (time_fmt & TIME_CHANGE) sort_opts= SORT_CTIME; - if (time_fmt & TIME_ACCESS) sort_opts= SORT_ATIME; -#endif - if (style_fmt != STYLE_LONG) - list_fmt &= ~LIST_ID_NUMERIC; /* numeric uid only for long list */ -#ifdef BB_FEATURE_LS_USERNAME - if (style_fmt == STYLE_LONG && (list_fmt & LIST_ID_NUMERIC)) - list_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */ -#endif - - /* choose a display format */ - if (style_fmt == STYLE_AUTO) - style_fmt = isatty(fileno(stdout)) ? 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]= 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 */ - } - } - - /* now, everything is in the av array */ - if (ac > 1) - disp_opts |= DISP_DIRNAME; /* 2 or more items? label directories */ - - /* stuff the command line file names into an dnode array */ - dn=NULL; - for (oi=0 ; oi < ac; oi++) { - cur= (struct dnode *)xmalloc(sizeof(struct dnode)); - cur->fullname= xstrdup(av[oi]); - cur->name= cur->fullname; - if (my_stat(cur)) - continue; - cur->next= dn; - dn= cur; - nfiles++; - } - - /* now that we know how many files there are - ** allocate memory for an array to hold dnode pointers - */ - dnp= dnalloc(nfiles); - for (i=0, cur=dn; inext; - } - - - if (disp_opts & DISP_NOLIST) { -#ifdef BB_FEATURE_LS_SORTFILES - shellsort(dnp, nfiles); -#endif - if (nfiles > 0) showfiles(dnp, nfiles); - } else { - dnd= splitdnarray(dnp, nfiles, SPLIT_DIR); - dnf= splitdnarray(dnp, nfiles, SPLIT_FILE); - dndirs= countdirs(dnp, nfiles); - dnfiles= nfiles - dndirs; - if (dnfiles > 0) { -#ifdef BB_FEATURE_LS_SORTFILES - shellsort(dnf, dnfiles); -#endif - showfiles(dnf, dnfiles); - } - if (dndirs > 0) { -#ifdef BB_FEATURE_LS_SORTFILES - shellsort(dnd, dndirs); -#endif - showdirs(dnd, dndirs); - } - } - return(status); - - print_usage_message: - show_usage(); -} diff --git a/busybox/lsmod.c b/busybox/lsmod.c deleted file mode 100644 index 76ed2fdd8..000000000 --- a/busybox/lsmod.c +++ /dev/null @@ -1,166 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini lsmod implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * - * Modified by Alcove, Julien Gaulmin and - * Nicolas Ferre to support pre 2.1 kernels - * (which lack the query_module() interface). - * - * 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 -#include -#include -#include "busybox.h" - - - -#ifdef BB_FEATURE_NEW_MODULE_INTERFACE - -struct module_info -{ - unsigned long addr; - unsigned long size; - unsigned long flags; - long usecount; -}; - - -int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret); - -/* Values for query_module's which. */ -static const int QM_MODULES = 1; -static const int QM_DEPS = 2; -static const int QM_REFS = 3; -static const int QM_SYMBOLS = 4; -static const int QM_INFO = 5; - -/* Bits of module.flags. */ -static const int NEW_MOD_RUNNING = 1; -static const int NEW_MOD_DELETED = 2; -static const int NEW_MOD_AUTOCLEAN = 4; -static const int NEW_MOD_VISITED = 8; -static const int NEW_MOD_USED_ONCE = 16; -static const int NEW_MOD_INITIALIZING = 64; - -static int my_query_module(const char *name, int which, void **buf, - size_t *bufsize, size_t *ret) -{ - int my_ret; - - my_ret = query_module(name, which, *buf, *bufsize, ret); - - if (my_ret == -1 && errno == ENOSPC) { - *buf = xrealloc(*buf, *ret); - *bufsize = *ret; - - my_ret = query_module(name, which, *buf, *bufsize, ret); - } - - return my_ret; -} - -extern int lsmod_main(int argc, char **argv) -{ - struct module_info info; - char *module_names, *mn, *deps, *dn; - size_t bufsize, depsize, nmod, count, i, j; - - module_names = xmalloc(bufsize = 256); - if (my_query_module(NULL, QM_MODULES, (void **)&module_names, &bufsize, - &nmod)) { - perror_msg_and_die("QM_MODULES"); - } - - deps = xmalloc(depsize = 256); - printf("Module Size Used by\n"); - for (i = 0, mn = module_names; i < nmod; mn += strlen(mn) + 1, i++) { - if (query_module(mn, QM_INFO, &info, sizeof(info), &count)) { - if (errno == ENOENT) { - /* The module was removed out from underneath us. */ - continue; - } - /* else choke */ - perror_msg_and_die("module %s: QM_INFO", mn); - } - if (my_query_module(mn, QM_REFS, (void **)&deps, &depsize, &count)) { - if (errno == ENOENT) { - /* The module was removed out from underneath us. */ - continue; - } - perror_msg_and_die("module %s: QM_REFS", mn); - } - printf("%-20s%8lu%4ld ", mn, info.size, info.usecount); - if (info.flags & NEW_MOD_DELETED) - printf("(deleted)"); - else if (info.flags & NEW_MOD_INITIALIZING) - printf("(initializing)"); - else if (!(info.flags & NEW_MOD_RUNNING)) - printf("(uninitialized)"); - else { - if (info.flags & NEW_MOD_AUTOCLEAN) - printf("(autoclean) "); - if (!(info.flags & NEW_MOD_USED_ONCE)) - printf("(unused)"); - } - if (count) printf("["); - for (j = 0, dn = deps; j < count; dn += strlen(dn) + 1, j++) { - printf("%s%s", dn, (j==count-1)? "":" "); - } - if (count) printf("] "); - - printf("\n"); - } - - - return( 0); -} - -#else /*BB_FEATURE_OLD_MODULE_INTERFACE*/ - -extern int lsmod_main(int argc, char **argv) -{ - int fd, i; - char line[128]; - - puts("Module Size Used by"); - fflush(stdout); - - if ((fd = open("/proc/modules", O_RDONLY)) >= 0 ) { - while ((i = read(fd, line, sizeof(line))) > 0) { - write(fileno(stdout), line, i); - } - close(fd); - return 0; - } - perror_msg_and_die("/proc/modules"); - return 1; -} - -#endif /*BB_FEATURE_OLD_MODULE_INTERFACE*/ diff --git a/busybox/makedevs.c b/busybox/makedevs.c deleted file mode 100644 index b8c6dd1d8..000000000 --- a/busybox/makedevs.c +++ /dev/null @@ -1,95 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * public domain -- Dave 'Kill a Cop' Cinege - * - * makedevs - * Make ranges of device files quickly. - * known bugs: can't deal with alpha ranges - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -int makedevs_main(int argc, char **argv) -{ - - const char *basedev = argv[1]; - const char *type = argv[2]; - int major = atoi(argv[3]); - int Sminor = atoi(argv[4]); - int S = atoi(argv[5]); - int E = atoi(argv[6]); - int sbase = argc == 8 ? 1 : 0; - - mode_t mode = 0; - dev_t dev = 0; - char devname[255]; - char buf[255]; - - if (argc < 7 || *argv[1]=='-') - show_usage(); - - switch (type[0]) { - case 'c': - mode = S_IFCHR; - break; - case 'b': - mode = S_IFBLK; - break; - case 'f': - mode = S_IFIFO; - break; - default: - show_usage(); - } - mode |= 0660; - - while (S <= E) { - - if (type[0] != 'f') - dev = (major << 8) | Sminor; - strcpy(devname, basedev); - - if (sbase == 0) { - sprintf(buf, "%d", S); - strcat(devname, buf); - } else { - sbase = 0; - } - - if (mknod(devname, mode, dev)) - printf("Failed to create: %s\n", devname); - - S++; - Sminor++; - } - - return 0; -} - -/* -And this is what this program replaces. The shell is too slow! - -makedev () { -local basedev=$1; local S=$2; local E=$3 -local major=$4; local Sminor=$5; local type=$6 -local sbase=$7 - - if [ ! "$sbase" = "" ]; then - mknod "$basedev" $type $major $Sminor - S=`expr $S + 1` - Sminor=`expr $Sminor + 1` - fi - - while [ $S -le $E ]; do - mknod "$basedev$S" $type $major $Sminor - S=`expr $S + 1` - Sminor=`expr $Sminor + 1` - done -} -*/ diff --git a/busybox/md5sum.c b/busybox/md5sum.c deleted file mode 100644 index bb4d115ca..000000000 --- a/busybox/md5sum.c +++ /dev/null @@ -1,1074 +0,0 @@ -/* md5sum.c - Compute MD5 checksum of files or strings according to the - * definition of MD5 in RFC 1321 from April 1992. - * Copyright (C) 1995-1999 Free Software Foundation, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/* Written by Ulrich Drepper */ -/* 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++; - temp = 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++; - temp = 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++; - temp = 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++; - temp = 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++; - temp = 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 = wfopen(filename, "r"); - if (fp == NULL) - return FALSE; - } - - if (md5_stream(fp, md5_result)) { - perror_msg("%s", filename); - - if (fp != stdin) - fclose(fp); - return FALSE; - } - - if (fp != stdin && fclose(fp) == EOF) { - 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 = 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) { - 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)) { - error_msg("%s: read error", checkfile_name); - return FALSE; - } - - if (checkfile_stream != stdin && fclose(checkfile_stream) == EOF) { - perror_msg("md5sum: %s", checkfile_name); - return FALSE; - } - - if (n_properly_formated_lines == 0) { - /* Warn if no tests are found. */ - 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) { - 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) { - 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: - show_usage(); - } - } - - if (file_type_specified && do_check) { - error_msg_and_die("the -b and -t options are meaningless when verifying checksums"); - } - - if (n_strings > 0 && do_check) { - error_msg_and_die("the -g and -c options are mutually exclusive"); - } - - if (status_only && !do_check) { - error_msg_and_die("the -s option is meaningful only when verifying checksums"); - } - - if (warn && !do_check) { - error_msg_and_die("the -w option is meaningful only when verifying checksums"); - } - - if (n_strings > 0) { - size_t i; - - if (optind < argc) { - 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) { - 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) { - error_msg_and_die("write error"); - } - - if (have_read_stdin && fclose (stdin) == EOF) { - error_msg_and_die("standard input"); - } - - if (err == 0) - return EXIT_SUCCESS; - else - return EXIT_FAILURE; -} diff --git a/busybox/miscutils/adjtimex.c b/busybox/miscutils/adjtimex.c deleted file mode 100644 index e3c160d87..000000000 --- a/busybox/miscutils/adjtimex.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * adjtimex.c - read, and possibly modify, the Linux kernel `timex' variables. - * - * Originally written: October 1997 - * Last hack: March 2001 - * Copyright 1997, 2000, 2001 Larry Doolittle - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License (Version 2, - * June 1991) as published by the Free Software Foundation. At the - * time of writing, that license was published by the FSF with the URL - * http://www.gnu.org/copyleft/gpl.html, and is incorporated herein by - * reference. - * - * 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 adjtimex(1) is very similar in intent to adjtimex(8) by Steven - * Dick and Jim Van Zandt - * (see http://metalab.unc.edu/pub/Linux/system/admin/time/adjtimex*). - * That version predates this one, and is _much_ bigger and more - * featureful. My independently written version was very similar to - * Steven's from the start, because they both follow the kernel timex - * structure. I further tweaked this version to be equivalent to Steven's - * where possible, but I don't like getopt_long, so the actual usage - * syntax is incompatible. - * - * Amazingly enough, my Red Hat 5.2 sys/timex (and sub-includes) - * don't actually give a prototype for adjtimex(2), so building - * this code (with -Wall) gives a warning. Later versions of - * glibc fix this issue. - * - * This program is too simple for a Makefile, just build with: - * gcc -Wall -O adjtimex.c -o adjtimex - * - * busyboxed 20 March 2001, Larry Doolittle - * It will autosense if it is built in a busybox environment, based - * on the BB_VER preprocessor macro. - */ - -#include -#include -#include -#include - -#if __GNU_LIBRARY__ < 5 -#include -extern int adjtimex(struct timex *buf); -#else -#include -#endif - -#ifdef BB_VER -#include "busybox.h" -#endif - -static struct {int bit; char *name;} statlist[] = { - { STA_PLL, "PLL" }, - { STA_PPSFREQ, "PPSFREQ" }, - { STA_PPSTIME, "PPSTIME" }, - { STA_FLL, "FFL" }, - { STA_INS, "INS" }, - { STA_DEL, "DEL" }, - { STA_UNSYNC, "UNSYNC" }, - { STA_FREQHOLD, "FREQHOLD" }, - { STA_PPSSIGNAL, "PPSSIGNAL" }, - { STA_PPSJITTER, "PPSJITTER" }, - { STA_PPSWANDER, "PPSWANDER" }, - { STA_PPSERROR, "PPSERROR" }, - { STA_CLOCKERR, "CLOCKERR" }, - { 0, NULL } }; - -static char *ret_code_descript[] = { - "clock synchronized", - "insert leap second", - "delete leap second", - "leap second in progress", - "leap second has occurred", - "clock not synchronized" }; - -#ifdef BB_VER -#define main adjtimex_main -#else -void usage(char *prog) -{ - fprintf(stderr, - "Usage: %s [ -q ] [ -o offset ] [ -f frequency ] [ -p timeconstant ] [ -t tick ]\n", - prog); -} -#define show_usage() usage(argv[0]) -#endif - -int main(int argc, char ** argv) -{ - struct timex txc; - int quiet=0; - int c, i, ret, sep; - char *descript; - txc.modes=0; - for (;;) { - c = getopt( argc, argv, "qo:f:p:t:"); - if (c == EOF) break; - switch (c) { - case 'q': - quiet=1; - break; - case 'o': - txc.offset = atoi(optarg); - txc.modes |= ADJ_OFFSET_SINGLESHOT; - break; - case 'f': - txc.freq = atoi(optarg); - txc.modes |= ADJ_FREQUENCY; - break; - case 'p': - txc.constant = atoi(optarg); - txc.modes |= ADJ_TIMECONST; - break; - case 't': - txc.tick = atoi(optarg); - txc.modes |= ADJ_TICK; - break; - default: - show_usage(); - exit(1); - } - } - if (argc != optind) { /* no valid non-option parameters */ - show_usage(); - exit(1); - } - - ret = adjtimex(&txc); - - if (ret < 0) perror("adjtimex"); - - if (!quiet && ret>=0) { - printf( - " mode: %d\n" - "-o offset: %ld\n" - "-f frequency: %ld\n" - " maxerror: %ld\n" - " esterror: %ld\n" - " status: %d ( ", - txc.modes, txc.offset, txc.freq, txc.maxerror, - txc.esterror, txc.status); - - /* representative output of next code fragment: - "PLL | PPSTIME" */ - sep=0; - for (i=0; statlist[i].name; i++) { - if (txc.status & statlist[i].bit) { - if (sep) fputs(" | ",stdout); - fputs(statlist[i].name,stdout); - sep=1; - } - } - - descript = "error"; - if (ret >= 0 && ret <= 5) descript = ret_code_descript[ret]; - printf(" )\n" - "-p timeconstant: %ld\n" - " precision: %ld\n" - " tolerance: %ld\n" - "-t tick: %ld\n" - " time.tv_sec: %ld\n" - " time.tv_usec: %ld\n" - " return value: %d (%s)\n", - txc.constant, - txc.precision, txc.tolerance, txc.tick, - (long)txc.time.tv_sec, (long)txc.time.tv_usec, ret, descript); - } - return (ret<0); -} diff --git a/busybox/miscutils/dc.c b/busybox/miscutils/dc.c deleted file mode 100644 index 8d7a92a28..000000000 --- a/busybox/miscutils/dc.c +++ /dev/null @@ -1,182 +0,0 @@ -/* vi: set sw=4 ts=4: */ -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */ - -static double stack[100]; -static unsigned int pointer; - -static void push(double a) -{ - if (pointer >= (sizeof(stack) / sizeof(*stack))) - error_msg_and_die("stack overflow"); - stack[pointer++] = a; -} - -static double pop() -{ - if (pointer == 0) - error_msg_and_die("stack underflow"); - return stack[--pointer]; -} - -static void add() -{ - push(pop() + pop()); -} - -static void sub() -{ - double subtrahend = pop(); - - push(pop() - subtrahend); -} - -static void mul() -{ - push(pop() * pop()); -} - -static void divide() -{ - double divisor = pop(); - - push(pop() / divisor); -} - -static void and() -{ - push((unsigned int) pop() & (unsigned int) pop()); -} - -static void or() -{ - push((unsigned int) pop() | (unsigned int) pop()); -} - -static void eor() -{ - push((unsigned int) pop() ^ (unsigned int) pop()); -} - -static void not() -{ - push(~(unsigned int) pop()); -} - -static void print() -{ - printf("%g\n", pop()); -} - -struct op { - const char *name; - void (*function) (); -}; - -static const struct op operators[] = { - {"+", add}, - {"add", add}, - {"-", sub}, - {"sub", sub}, - {"*", mul}, - {"mul", mul}, - {"/", divide}, - {"div", divide}, - {"and", and}, - {"or", or}, - {"not", not}, - {"eor", eor}, - {0, 0} -}; - -static void stack_machine(const char *argument) -{ - char *endPointer = 0; - double d; - const struct op *o = operators; - - if (argument == 0) { - print(); - return; - } - - d = strtod(argument, &endPointer); - - if (endPointer != argument) { - push(d); - return; - } - - while (o->name != 0) { - if (strcmp(o->name, argument) == 0) { - (*(o->function)) (); - return; - } - o++; - } - error_msg_and_die("%s: syntax error.", argument); -} - -/* return pointer to next token in buffer and set *buffer to one char - * past the end of the above mentioned token - */ -static char *get_token(char **buffer) -{ - char *start = NULL; - char *current = *buffer; - - while (isspace(*current)) { current++; } - if (*current != 0) { - start = current; - while (!isspace(*current) && current != 0) { current++; } - *buffer = current; - } - return start; -} - -/* In Perl one might say, scalar m|\s*(\S+)\s*|g */ -static int number_of_tokens(char *buffer) -{ - int i = 0; - char *b = buffer; - while (get_token(&b)) { i++; } - return i; -} - -int dc_main(int argc, char **argv) -{ - /* take stuff from stdin if no args are given */ - if (argc <= 1) { - int i, len; - char *line = NULL; - char *cursor = NULL; - char *token = NULL; - while ((line = get_line_from_file(stdin))) { - cursor = line; - len = number_of_tokens(line); - for (i = 0; i < len; i++) { - token = get_token(&cursor); - *cursor++ = 0; - stack_machine(token); - } - free(line); - } - } else { - if (*argv[1]=='-') - show_usage(); - while (argc >= 2) { - stack_machine(argv[1]); - argv++; - argc--; - } - } - stack_machine(0); - return EXIT_SUCCESS; -} diff --git a/busybox/miscutils/dutmp.c b/busybox/miscutils/dutmp.c deleted file mode 100644 index df7f64d30..000000000 --- a/busybox/miscutils/dutmp.c +++ /dev/null @@ -1,64 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * public domain -- Dave 'Kill a Cop' Cinege - * - * dutmp - * Takes utmp formated file on stdin and dumps it's contents - * out in colon delimited fields. Easy to 'cut' for shell based - * versions of 'who', 'last', etc. IP Addr is output in hex, - * little endian on x86. - * - * Modified to support all sorts of libcs by - * Erik Andersen - */ - -#include -#include - -#include -#include -#include -#include -#include "busybox.h" - -extern int dutmp_main(int argc, char **argv) -{ - - int file; - struct utmp ut; - - if (argc<2) { - file = fileno(stdin); - } else if (*argv[1] == '-' ) { - show_usage(); - } else { - file = open(argv[1], O_RDONLY); - if (file < 0) { - perror_msg_and_die(io_error, argv[1]); - } - } - -/* Kludge around the fact that the binary format for utmp has changed. */ -#if __GNU_LIBRARY__ < 5 || defined __UCLIBC__ - /* Linux libc5 */ - while (read(file, (void*)&ut, sizeof(struct utmp))) { - printf("%d|%d|%s|%s|%s|%s|%s|%lx\n", - ut.ut_type, ut.ut_pid, ut.ut_line, - ut.ut_id, ut.ut_user, ut.ut_host, - ctime(&(ut.ut_time)), - (long)ut.ut_addr); - } -#else - /* Glibc, uClibc, etc. */ - while (read(file, (void*)&ut, sizeof(struct utmp))) { - printf("%d|%d|%s|%s|%s|%s|%d|%d|%ld|%ld|%ld|%x\n", - ut.ut_type, ut.ut_pid, ut.ut_line, - ut.ut_id, ut.ut_user, ut.ut_host, - ut.ut_exit.e_termination, ut.ut_exit.e_exit, - ut.ut_session, - ut.ut_tv.tv_sec, ut.ut_tv.tv_usec, - ut.ut_addr); - } -#endif - return EXIT_SUCCESS; -} diff --git a/busybox/miscutils/makedevs.c b/busybox/miscutils/makedevs.c deleted file mode 100644 index b8c6dd1d8..000000000 --- a/busybox/miscutils/makedevs.c +++ /dev/null @@ -1,95 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * public domain -- Dave 'Kill a Cop' Cinege - * - * makedevs - * Make ranges of device files quickly. - * known bugs: can't deal with alpha ranges - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -int makedevs_main(int argc, char **argv) -{ - - const char *basedev = argv[1]; - const char *type = argv[2]; - int major = atoi(argv[3]); - int Sminor = atoi(argv[4]); - int S = atoi(argv[5]); - int E = atoi(argv[6]); - int sbase = argc == 8 ? 1 : 0; - - mode_t mode = 0; - dev_t dev = 0; - char devname[255]; - char buf[255]; - - if (argc < 7 || *argv[1]=='-') - show_usage(); - - switch (type[0]) { - case 'c': - mode = S_IFCHR; - break; - case 'b': - mode = S_IFBLK; - break; - case 'f': - mode = S_IFIFO; - break; - default: - show_usage(); - } - mode |= 0660; - - while (S <= E) { - - if (type[0] != 'f') - dev = (major << 8) | Sminor; - strcpy(devname, basedev); - - if (sbase == 0) { - sprintf(buf, "%d", S); - strcat(devname, buf); - } else { - sbase = 0; - } - - if (mknod(devname, mode, dev)) - printf("Failed to create: %s\n", devname); - - S++; - Sminor++; - } - - return 0; -} - -/* -And this is what this program replaces. The shell is too slow! - -makedev () { -local basedev=$1; local S=$2; local E=$3 -local major=$4; local Sminor=$5; local type=$6 -local sbase=$7 - - if [ ! "$sbase" = "" ]; then - mknod "$basedev" $type $major $Sminor - S=`expr $S + 1` - Sminor=`expr $Sminor + 1` - fi - - while [ $S -le $E ]; do - mknod "$basedev$S" $type $major $Sminor - S=`expr $S + 1` - Sminor=`expr $Sminor + 1` - done -} -*/ diff --git a/busybox/miscutils/mktemp.c b/busybox/miscutils/mktemp.c deleted file mode 100644 index bc47d0af0..000000000 --- a/busybox/miscutils/mktemp.c +++ /dev/null @@ -1,40 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mktemp implementation for busybox - * - * - * Copyright (C) 2000 by Daniel Jacobowitz - * Written by Daniel Jacobowitz - * - * 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 "busybox.h" - -extern int mktemp_main(int argc, char **argv) -{ - if (argc != 2 && (argc != 3 || strcmp(argv[1], "-q"))) - show_usage(); - if(mkstemp(argv[argc-1]) < 0) - return EXIT_FAILURE; - (void) puts(argv[argc-1]); - return EXIT_SUCCESS; -} diff --git a/busybox/miscutils/mt.c b/busybox/miscutils/mt.c deleted file mode 100644 index 49dc70ac6..000000000 --- a/busybox/miscutils/mt.c +++ /dev/null @@ -1,121 +0,0 @@ -/* vi: set sw=4 ts=4: */ -#include -#include -#include -#include -#include -#include "busybox.h" - -struct mt_opcodes { - char *name; - short value; -}; - -/* missing: eod/seod, stoptions, stwrthreshold, densities */ -static const struct mt_opcodes opcodes[] = { - {"bsf", MTBSF}, - {"bsfm", MTBSFM}, - {"bsr", MTBSR}, - {"bss", MTBSS}, - {"datacompression", MTCOMPRESSION}, - {"eom", MTEOM}, - {"erase", MTERASE}, - {"fsf", MTFSF}, - {"fsfm", MTFSFM}, - {"fsr", MTFSR}, - {"fss", MTFSS}, - {"load", MTLOAD}, - {"lock", MTLOCK}, - {"mkpart", MTMKPART}, - {"nop", MTNOP}, - {"offline", MTOFFL}, - {"rewoffline", MTOFFL}, - {"ras1", MTRAS1}, - {"ras2", MTRAS2}, - {"ras3", MTRAS3}, - {"reset", MTRESET}, - {"retension", MTRETEN}, - {"rewind", MTREW}, - {"seek", MTSEEK}, - {"setblk", MTSETBLK}, - {"setdensity", MTSETDENSITY}, - {"drvbuffer", MTSETDRVBUFFER}, - {"setpart", MTSETPART}, - {"tell", MTTELL}, - {"wset", MTWSM}, - {"unload", MTUNLOAD}, - {"unlock", MTUNLOCK}, - {"eof", MTWEOF}, - {"weof", MTWEOF}, - {0, 0} -}; - -extern int mt_main(int argc, char **argv) -{ - const char *file = "/dev/tape"; - const struct mt_opcodes *code = opcodes; - struct mtop op; - struct mtpos position; - int fd, mode; - - if (argc < 2) { - show_usage(); - } - - if (strcmp(argv[1], "-f") == 0) { - if (argc < 4) { - show_usage(); - } - file = argv[2]; - argv += 2; - argc -= 2; - } - - while (code->name != 0) { - if (strcmp(code->name, argv[1]) == 0) - break; - code++; - } - - if (code->name == 0) { - error_msg("unrecognized opcode %s.", argv[1]); - return EXIT_FAILURE; - } - - op.mt_op = code->value; - if (argc >= 3) - op.mt_count = atoi(argv[2]); - else - op.mt_count = 1; /* One, not zero, right? */ - - switch (code->value) { - case MTWEOF: - case MTERASE: - case MTWSM: - case MTSETDRVBUFFER: - mode = O_WRONLY; - break; - - default: - mode = O_RDONLY; - break; - } - - if ((fd = open(file, mode, 0)) < 0) - perror_msg_and_die("%s", file); - - switch (code->value) { - case MTTELL: - if (ioctl(fd, MTIOCPOS, &position) < 0) - perror_msg_and_die("%s", file); - printf ("At block %d.\n", (int) position.mt_blkno); - break; - - default: - if (ioctl(fd, MTIOCTOP, &op) != 0) - perror_msg_and_die("%s", file); - break; - } - - return EXIT_SUCCESS; -} diff --git a/busybox/miscutils/readlink.c b/busybox/miscutils/readlink.c deleted file mode 100644 index c46ebd108..000000000 --- a/busybox/miscutils/readlink.c +++ /dev/null @@ -1,48 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini readlink implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include "busybox.h" - -int readlink_main(int argc, char **argv) -{ - char *buf = NULL; - - /* no options, no getopt */ - - if (argc != 2) - show_usage(); - - buf = xreadlink(argv[1]); - if (!buf) - return EXIT_FAILURE; - puts(buf); -#ifdef BB_FEATURE_CLEAN_UP - free(buf); -#endif - - return EXIT_SUCCESS; -} diff --git a/busybox/miscutils/update.c b/busybox/miscutils/update.c deleted file mode 100644 index 27a04ddee..000000000 --- a/busybox/miscutils/update.c +++ /dev/null @@ -1,112 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini update implementation for busybox; much pasted from update-2.11 - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * Copyright (c) 1996, 1997, 1999 Torsten Poulin. - * Copyright (c) 2000 by Karl M. Hegbloom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* - * Note: This program is only necessary if you are running a 2.0.x (or - * earlier) kernel. 2.2.x and higher flush filesystem buffers automatically. - */ - -#include -#include -#include /* for getopt() */ -#include - -#if __GNU_LIBRARY__ > 5 - #include -#else - extern int bdflush (int func, long int data); -#endif - -#include "busybox.h" - -static unsigned int sync_duration = 30; -static unsigned int flush_duration = 5; -static int use_sync = 0; - -extern int update_main(int argc, char **argv) -{ - int pid; - int opt; - - while ((opt = getopt(argc, argv, "Ss:f:")) > 0) { - switch (opt) { - case 'S': - use_sync = 1; - break; - case 's': - sync_duration = atoi(optarg); - break; - case 'f': - flush_duration = atoi(optarg); - break; - default: - show_usage(); - } - } - - if (daemon(0, 1) < 0) - perror_msg_and_die("daemon"); - -#ifdef OPEN_MAX - for (pid = 0; pid < OPEN_MAX; pid++) close(pid); -#else - /* glibc 2.1.92 requires using sysconf(_SC_OPEN_MAX) */ - for (pid = 0; pid < sysconf(_SC_OPEN_MAX); pid++) close(pid); -#endif - - /* This is no longer necessary since 1.3.5x, but it will harmlessly - * exit if that is the case. - */ - - /* set the program name that will show up in a 'ps' listing */ - argv[0] = "bdflush (update)"; - argv[1] = NULL; - argv[2] = NULL; - for (;;) { - if (use_sync) { - sleep(sync_duration); - sync(); - } else { - sleep(flush_duration); - if (bdflush(1, 0) < 0) { - openlog("update", LOG_CONS, LOG_DAEMON); - syslog(LOG_INFO, - "This kernel does not need update(8). Exiting."); - closelog(); - return EXIT_SUCCESS; - } - } - } - - return EXIT_SUCCESS; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/miscutils/watchdog.c b/busybox/miscutils/watchdog.c deleted file mode 100644 index f0b0ebd0e..000000000 --- a/busybox/miscutils/watchdog.c +++ /dev/null @@ -1,49 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini watchdog implementation for busybox - * - * Copyright (C) 2000 spoon . - * - * 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 - * - */ - -/* getopt not needed */ - -#include -#include -#include -#include -#include "busybox.h" - -extern int watchdog_main(int argc, char **argv) -{ - int fd; - - if (argc != 2) { - show_usage(); - } - - if ((fd=open(argv[1], O_WRONLY)) == -1) { - perror_msg_and_die(argv[1]); - } - - while (1) { - sleep(30); - write(fd, "\0", 1); - } - - return EXIT_FAILURE; -} diff --git a/busybox/mk_loop_h.sh b/busybox/mk_loop_h.sh deleted file mode 100755 index 71c987376..000000000 --- a/busybox/mk_loop_h.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh -# -# Figure out (i) the type of dev_t (ii) the defines for loop stuff -# -# Output of this script is normally redirected to "loop.h". - -# Since 1.3.79 there is an include file -# that defines __kernel_dev_t. -# (The file itself appeared in 1.3.78, but there it defined __dev_t.) -# If it exists, we use it, or, rather, which -# avoids namespace pollution. Otherwise we guess that __kernel_dev_t -# is an unsigned short (which is true on i386, but false on alpha). - -# BUG: This test is actually broken if your gcc is not configured to -# search /usr/include, as may well happen with cross-compilers. -# It would be better to ask $(CC) if these files can be found. - -if [ -f /usr/include/linux/posix_types.h ]; then - echo '#include ' - echo '#undef dev_t' - echo '#define dev_t __kernel_dev_t' -else - echo '#undef dev_t' - echo '#define dev_t unsigned short' -fi - -# Next we have to find the loop stuff itself. -# First try kernel source, then a private version. - -if [ -f /usr/include/linux/loop.h ]; then - echo '#include ' -else - echo '#include "real_loop.h"' -fi - -echo '#undef dev_t' - diff --git a/busybox/mkdir.c b/busybox/mkdir.c deleted file mode 100644 index 03c49f098..000000000 --- a/busybox/mkdir.c +++ /dev/null @@ -1,64 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mkdir implementation for busybox - * - * 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "busybox.h" - -extern int mkdir_main (int argc, char **argv) -{ - mode_t mode = -1; - int flags = 0; - int status = 0; - int i, opt; - - while ((opt = getopt (argc, argv, "m:p")) != -1) { - switch (opt) { - case 'm': - mode = 0777; - if (!parse_mode (optarg, &mode)) - error_msg_and_die ("invalid mode `%s'", optarg); - break; - case 'p': - flags |= FILEUTILS_RECUR; - break; - default: - show_usage (); - } - } - - if (optind == argc) - show_usage (); - - for (i = optind; i < argc; i++) - if (make_directory (argv[i], mode, flags) < 0) - status = 1; - - return status; -} diff --git a/busybox/mkfifo.c b/busybox/mkfifo.c deleted file mode 100644 index ca217fa23..000000000 --- a/busybox/mkfifo.c +++ /dev/null @@ -1,60 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mkfifo implementation for busybox - * - * Copyright (C) 1999 by Randolph Chung - * - * 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 "busybox.h" - -extern int mkfifo_main(int argc, char **argv) -{ - char *thisarg; - mode_t mode = 0666; - - argc--; - argv++; - - /* Parse any options */ - while (argc > 1) { - if (**argv != '-') - show_usage(); - thisarg = *argv; - thisarg++; - switch (*thisarg) { - case 'm': - argc--; - argv++; - parse_mode(*argv, &mode); - break; - default: - show_usage(); - } - argc--; - argv++; - } - if (argc < 1 || *argv[0] == '-') - show_usage(); - if (mkfifo(*argv, mode) < 0) - perror_msg_and_die("mkfifo"); - return EXIT_SUCCESS; -} diff --git a/busybox/mkfs_minix.c b/busybox/mkfs_minix.c deleted file mode 100644 index ccc0e85d7..000000000 --- a/busybox/mkfs_minix.c +++ /dev/null @@ -1,847 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * mkfs.c - make a linux (minix) file-system. - * - * (C) 1991 Linus Torvalds. This file may be redistributed as per - * the Linux copyright. - */ - -/* - * DD.MM.YY - * - * 24.11.91 - Time began. Used the fsck sources to get started. - * - * 25.11.91 - Corrected some bugs. Added support for ".badblocks" - * The algorithm for ".badblocks" is a bit weird, but - * it should work. Oh, well. - * - * 25.01.92 - Added the -l option for getting the list of bad blocks - * out of a named file. (Dave Rivers, rivers@ponds.uucp) - * - * 28.02.92 - Added %-information when using -c. - * - * 28.02.93 - Added support for other namelengths than the original - * 14 characters so that I can test the new kernel routines.. - * - * 09.10.93 - Make exit status conform to that required by fsutil - * (Rik Faith, faith@cs.unc.edu) - * - * 31.10.93 - Added inode request feature, for backup floppies: use - * 32 inodes, for a news partition use more. - * (Scott Heavner, sdh@po.cwru.edu) - * - * 03.01.94 - Added support for file system valid flag. - * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu) - * - * 30.10.94 - added support for v2 filesystem - * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de) - * - * 09.11.94 - Added test to prevent overwrite of mounted fs adapted - * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs - * program. (Daniel Quinlan, quinlan@yggdrasil.com) - * - * 03.20.95 - Clear first 512 bytes of filesystem to make certain that - * the filesystem is not misidentified as a MS-DOS FAT filesystem. - * (Daniel Quinlan, quinlan@yggdrasil.com) - * - * 02.07.96 - Added small patch from Russell King to make the program a - * good deal more portable (janl@math.uio.no) - * - * Usage: mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks] - * - * -c for readablility checking (SLOW!) - * -l for getting a list of bad blocks from a file. - * -n for namelength (currently the kernel only uses 14 or 30) - * -i for number of inodes - * -v for v2 filesystem - * - * The device may be a block device or a image of one, but this isn't - * enforced (but it's not much fun on a character device :-). - * - * Modified for BusyBox by Erik Andersen -- - * removed getopt based parser and added a hand rolled one. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#define MINIX_ROOT_INO 1 -#define MINIX_LINK_MAX 250 -#define MINIX2_LINK_MAX 65530 - -#define MINIX_I_MAP_SLOTS 8 -#define MINIX_Z_MAP_SLOTS 64 -#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ -#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ -#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */ -#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */ -#define MINIX_VALID_FS 0x0001 /* Clean fs. */ -#define MINIX_ERROR_FS 0x0002 /* fs has errors. */ - -#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) -#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode))) - -#define MINIX_V1 0x0001 /* original minix fs */ -#define MINIX_V2 0x0002 /* minix V2 fs */ - -#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version - -/* - * This is the original minix inode layout on disk. - * Note the 8-bit gid and atime and ctime. - */ -struct minix_inode { - u_int16_t i_mode; - u_int16_t i_uid; - u_int32_t i_size; - u_int32_t i_time; - u_int8_t i_gid; - u_int8_t i_nlinks; - u_int16_t i_zone[9]; -}; - -/* - * The new minix inode has all the time entries, as well as - * long block numbers and a third indirect block (7+1+1+1 - * instead of 7+1+1). Also, some previously 8-bit values are - * now 16-bit. The inode is now 64 bytes instead of 32. - */ -struct minix2_inode { - u_int16_t i_mode; - u_int16_t i_nlinks; - u_int16_t i_uid; - u_int16_t i_gid; - u_int32_t i_size; - u_int32_t i_atime; - u_int32_t i_mtime; - u_int32_t i_ctime; - u_int32_t i_zone[10]; -}; - -/* - * minix super-block data on disk - */ -struct minix_super_block { - u_int16_t s_ninodes; - u_int16_t s_nzones; - u_int16_t s_imap_blocks; - u_int16_t s_zmap_blocks; - u_int16_t s_firstdatazone; - u_int16_t s_log_zone_size; - u_int32_t s_max_size; - u_int16_t s_magic; - u_int16_t s_state; - u_int32_t s_zones; -}; - -struct minix_dir_entry { - u_int16_t inode; - char name[0]; -}; - -#define BLOCK_SIZE_BITS 10 -#define BLOCK_SIZE (1<> 3] & (1<<(i & 7))) != 0; -} -#define inode_in_use(x) (bit(inode_map,(x))) -#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1)) - -#define mark_inode(x) (setbit(inode_map,(x))) -#define unmark_inode(x) (clrbit(inode_map,(x))) - -#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1)) -#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1)) - -/* - * Check to make certain that our new filesystem won't be created on - * an already mounted partition. Code adapted from mke2fs, Copyright - * (C) 1994 Theodore Ts'o. Also licensed under GPL. - */ -static void check_mount(void) -{ - FILE *f; - struct mntent *mnt; - - if ((f = setmntent(MOUNTED, "r")) == NULL) - return; - while ((mnt = getmntent(f)) != NULL) - if (strcmp(device_name, mnt->mnt_fsname) == 0) - break; - endmntent(f); - if (!mnt) - return; - - error_msg_and_die("%s is mounted; will not make a filesystem here!", device_name); -} - -static long valid_offset(int fd, int offset) -{ - char ch; - - if (lseek(fd, offset, 0) < 0) - return 0; - if (read(fd, &ch, 1) < 1) - return 0; - return 1; -} - -static int count_blocks(int fd) -{ - int high, low; - - low = 0; - for (high = 1; valid_offset(fd, high); high *= 2) - low = high; - while (low < high - 1) { - const int mid = (low + high) / 2; - - if (valid_offset(fd, mid)) - low = mid; - else - high = mid; - } - valid_offset(fd, 0); - return (low + 1); -} - -static int get_size(const char *file) -{ - int fd; - long size; - - if ((fd = open(file, O_RDWR)) < 0) - perror_msg_and_die("%s", file); - if (ioctl(fd, BLKGETSIZE, &size) >= 0) { - close(fd); - return (size * 512); - } - - size = count_blocks(fd); - close(fd); - return size; -} - -static void write_tables(void) -{ - /* Mark the super block valid. */ - Super.s_state |= MINIX_VALID_FS; - Super.s_state &= ~MINIX_ERROR_FS; - - if (lseek(DEV, 0, SEEK_SET)) - error_msg_and_die("seek to boot block failed in write_tables"); - if (512 != write(DEV, boot_block_buffer, 512)) - error_msg_and_die("unable to clear boot sector"); - if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET)) - error_msg_and_die("seek failed in write_tables"); - if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE)) - error_msg_and_die("unable to write super-block"); - if (IMAPS * BLOCK_SIZE != write(DEV, inode_map, IMAPS * BLOCK_SIZE)) - error_msg_and_die("unable to write inode map"); - if (ZMAPS * BLOCK_SIZE != write(DEV, zone_map, ZMAPS * BLOCK_SIZE)) - error_msg_and_die("unable to write zone map"); - if (INODE_BUFFER_SIZE != write(DEV, inode_buffer, INODE_BUFFER_SIZE)) - error_msg_and_die("unable to write inodes"); - -} - -static void write_block(int blk, char *buffer) -{ - if (blk * BLOCK_SIZE != lseek(DEV, blk * BLOCK_SIZE, SEEK_SET)) - error_msg_and_die("seek failed in write_block"); - if (BLOCK_SIZE != write(DEV, buffer, BLOCK_SIZE)) - error_msg_and_die("write failed in write_block"); -} - -static int get_free_block(void) -{ - int blk; - - if (used_good_blocks + 1 >= MAX_GOOD_BLOCKS) - error_msg_and_die("too many bad blocks"); - if (used_good_blocks) - blk = good_blocks_table[used_good_blocks - 1] + 1; - else - blk = FIRSTZONE; - while (blk < ZONES && zone_in_use(blk)) - blk++; - if (blk >= ZONES) - error_msg_and_die("not enough good blocks"); - good_blocks_table[used_good_blocks] = blk; - used_good_blocks++; - return blk; -} - -static void mark_good_blocks(void) -{ - int blk; - - for (blk = 0; blk < used_good_blocks; blk++) - mark_zone(good_blocks_table[blk]); -} - -static int next(int zone) -{ - if (!zone) - zone = FIRSTZONE - 1; - while (++zone < ZONES) - if (zone_in_use(zone)) - return zone; - return 0; -} - -static void make_bad_inode(void) -{ - struct minix_inode *inode = &Inode[MINIX_BAD_INO]; - int i, j, zone; - int ind = 0, dind = 0; - unsigned short ind_block[BLOCK_SIZE >> 1]; - unsigned short dind_block[BLOCK_SIZE >> 1]; - -#define NEXT_BAD (zone = next(zone)) - - if (!badblocks) - return; - mark_inode(MINIX_BAD_INO); - inode->i_nlinks = 1; - inode->i_time = time(NULL); - inode->i_mode = S_IFREG + 0000; - inode->i_size = badblocks * BLOCK_SIZE; - zone = next(0); - for (i = 0; i < 7; i++) { - inode->i_zone[i] = zone; - if (!NEXT_BAD) - goto end_bad; - } - inode->i_zone[7] = ind = get_free_block(); - memset(ind_block, 0, BLOCK_SIZE); - for (i = 0; i < 512; i++) { - ind_block[i] = zone; - if (!NEXT_BAD) - goto end_bad; - } - inode->i_zone[8] = dind = get_free_block(); - memset(dind_block, 0, BLOCK_SIZE); - for (i = 0; i < 512; i++) { - write_block(ind, (char *) ind_block); - dind_block[i] = ind = get_free_block(); - memset(ind_block, 0, BLOCK_SIZE); - for (j = 0; j < 512; j++) { - ind_block[j] = zone; - if (!NEXT_BAD) - goto end_bad; - } - } - error_msg_and_die("too many bad blocks"); - end_bad: - if (ind) - write_block(ind, (char *) ind_block); - if (dind) - write_block(dind, (char *) dind_block); -} - -#ifdef BB_FEATURE_MINIX2 -static void make_bad_inode2(void) -{ - struct minix2_inode *inode = &Inode2[MINIX_BAD_INO]; - int i, j, zone; - int ind = 0, dind = 0; - unsigned long ind_block[BLOCK_SIZE >> 2]; - unsigned long dind_block[BLOCK_SIZE >> 2]; - - if (!badblocks) - return; - mark_inode(MINIX_BAD_INO); - inode->i_nlinks = 1; - inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL); - inode->i_mode = S_IFREG + 0000; - inode->i_size = badblocks * BLOCK_SIZE; - zone = next(0); - for (i = 0; i < 7; i++) { - inode->i_zone[i] = zone; - if (!NEXT_BAD) - goto end_bad; - } - inode->i_zone[7] = ind = get_free_block(); - memset(ind_block, 0, BLOCK_SIZE); - for (i = 0; i < 256; i++) { - ind_block[i] = zone; - if (!NEXT_BAD) - goto end_bad; - } - inode->i_zone[8] = dind = get_free_block(); - memset(dind_block, 0, BLOCK_SIZE); - for (i = 0; i < 256; i++) { - write_block(ind, (char *) ind_block); - dind_block[i] = ind = get_free_block(); - memset(ind_block, 0, BLOCK_SIZE); - for (j = 0; j < 256; j++) { - ind_block[j] = zone; - if (!NEXT_BAD) - goto end_bad; - } - } - /* Could make triple indirect block here */ - error_msg_and_die("too many bad blocks"); - end_bad: - if (ind) - write_block(ind, (char *) ind_block); - if (dind) - write_block(dind, (char *) dind_block); -} -#endif - -static void make_root_inode(void) -{ - struct minix_inode *inode = &Inode[MINIX_ROOT_INO]; - - mark_inode(MINIX_ROOT_INO); - inode->i_zone[0] = get_free_block(); - inode->i_nlinks = 2; - inode->i_time = time(NULL); - if (badblocks) - inode->i_size = 3 * dirsize; - else { - root_block[2 * dirsize] = '\0'; - root_block[2 * dirsize + 1] = '\0'; - inode->i_size = 2 * dirsize; - } - inode->i_mode = S_IFDIR + 0755; - inode->i_uid = getuid(); - if (inode->i_uid) - inode->i_gid = getgid(); - write_block(inode->i_zone[0], root_block); -} - -#ifdef BB_FEATURE_MINIX2 -static void make_root_inode2(void) -{ - struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO]; - - mark_inode(MINIX_ROOT_INO); - inode->i_zone[0] = get_free_block(); - inode->i_nlinks = 2; - inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL); - if (badblocks) - inode->i_size = 3 * dirsize; - else { - root_block[2 * dirsize] = '\0'; - root_block[2 * dirsize + 1] = '\0'; - inode->i_size = 2 * dirsize; - } - inode->i_mode = S_IFDIR + 0755; - inode->i_uid = getuid(); - if (inode->i_uid) - inode->i_gid = getgid(); - write_block(inode->i_zone[0], root_block); -} -#endif - -static void setup_tables(void) -{ - int i; - unsigned long inodes; - - memset(super_block_buffer, 0, BLOCK_SIZE); - memset(boot_block_buffer, 0, 512); - MAGIC = magic; - ZONESIZE = 0; - MAXSIZE = version2 ? 0x7fffffff : (7 + 512 + 512 * 512) * 1024; - ZONES = BLOCKS; -/* some magic nrs: 1 inode / 3 blocks */ - if (req_nr_inodes == 0) - inodes = BLOCKS / 3; - else - inodes = req_nr_inodes; - /* Round up inode count to fill block size */ -#ifdef BB_FEATURE_MINIX2 - if (version2) - inodes = ((inodes + MINIX2_INODES_PER_BLOCK - 1) & - ~(MINIX2_INODES_PER_BLOCK - 1)); - else -#endif - inodes = ((inodes + MINIX_INODES_PER_BLOCK - 1) & - ~(MINIX_INODES_PER_BLOCK - 1)); - if (inodes > 65535) - inodes = 65535; - INODES = inodes; - IMAPS = UPPER(INODES + 1, BITS_PER_BLOCK); - ZMAPS = 0; - i = 0; - while (ZMAPS != - UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1, - BITS_PER_BLOCK) && i < 1000) { - ZMAPS = - UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1, - BITS_PER_BLOCK); - i++; - } - /* Real bad hack but overwise mkfs.minix can be thrown - * in infinite loop... - * try: - * dd if=/dev/zero of=test.fs count=10 bs=1024 - * /sbin/mkfs.minix -i 200 test.fs - * */ - if (i >= 999) { - error_msg_and_die("unable to allocate buffers for maps"); - } - FIRSTZONE = NORM_FIRSTZONE; - inode_map = xmalloc(IMAPS * BLOCK_SIZE); - zone_map = xmalloc(ZMAPS * BLOCK_SIZE); - memset(inode_map, 0xff, IMAPS * BLOCK_SIZE); - memset(zone_map, 0xff, ZMAPS * BLOCK_SIZE); - for (i = FIRSTZONE; i < ZONES; i++) - unmark_zone(i); - for (i = MINIX_ROOT_INO; i <= INODES; i++) - unmark_inode(i); - inode_buffer = xmalloc(INODE_BUFFER_SIZE); - memset(inode_buffer, 0, INODE_BUFFER_SIZE); - printf("%ld inodes\n", INODES); - printf("%ld blocks\n", ZONES); - printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE); - printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE); - printf("Maxsize=%ld\n\n", MAXSIZE); -} - -/* - * Perform a test of a block; return the number of - * blocks readable/writeable. - */ -static long do_check(char *buffer, int try, unsigned int current_block) -{ - long got; - - /* Seek to the correct loc. */ - if (lseek(DEV, current_block * BLOCK_SIZE, SEEK_SET) != - current_block * BLOCK_SIZE) { - error_msg_and_die("seek failed during testing of blocks"); - } - - - /* Try the read */ - got = read(DEV, buffer, try * BLOCK_SIZE); - if (got < 0) - got = 0; - if (got & (BLOCK_SIZE - 1)) { - printf("Weird values in do_check: probably bugs\n"); - } - got /= BLOCK_SIZE; - return got; -} - -static unsigned int currently_testing = 0; - -static void alarm_intr(int alnum) -{ - if (currently_testing >= ZONES) - return; - signal(SIGALRM, alarm_intr); - alarm(5); - if (!currently_testing) - return; - printf("%d ...", currently_testing); - fflush(stdout); -} - -static void check_blocks(void) -{ - int try, got; - static char buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS]; - - currently_testing = 0; - signal(SIGALRM, alarm_intr); - alarm(5); - while (currently_testing < ZONES) { - if (lseek(DEV, currently_testing * BLOCK_SIZE, SEEK_SET) != - currently_testing * BLOCK_SIZE) - error_msg_and_die("seek failed in check_blocks"); - try = TEST_BUFFER_BLOCKS; - if (currently_testing + try > ZONES) - try = ZONES - currently_testing; - got = do_check(buffer, try, currently_testing); - currently_testing += got; - if (got == try) - continue; - if (currently_testing < FIRSTZONE) - error_msg_and_die("bad blocks before data-area: cannot make fs"); - mark_zone(currently_testing); - badblocks++; - currently_testing++; - } - if (badblocks > 1) - printf("%d bad blocks\n", badblocks); - else if (badblocks == 1) - printf("one bad block\n"); -} - -static void get_list_blocks(filename) -char *filename; - -{ - FILE *listfile; - unsigned long blockno; - - listfile = xfopen(filename, "r"); - while (!feof(listfile)) { - fscanf(listfile, "%ld\n", &blockno); - mark_zone(blockno); - badblocks++; - } - if (badblocks > 1) - printf("%d bad blocks\n", badblocks); - else if (badblocks == 1) - printf("one bad block\n"); -} - -extern int mkfs_minix_main(int argc, char **argv) -{ - int i=1; - char *tmp; - struct stat statbuf; - char *listfile = NULL; - int stopIt=FALSE; - - if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) - error_msg_and_die("bad inode size"); -#ifdef BB_FEATURE_MINIX2 - if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) - error_msg_and_die("bad inode size"); -#endif - - /* Parse options */ - argv++; - while (--argc >= 0 && *argv && **argv) { - if (**argv == '-') { - stopIt=FALSE; - while (i > 0 && *++(*argv) && stopIt==FALSE) { - switch (**argv) { - case 'c': - check = 1; - break; - case 'i': - { - char *cp=NULL; - if (*(*argv+1) != 0) { - cp = ++(*argv); - } else { - if (--argc == 0) { - goto goodbye; - } - cp = *(++argv); - } - req_nr_inodes = strtoul(cp, &tmp, 0); - if (*tmp) - show_usage(); - stopIt=TRUE; - break; - } - case 'l': - if (--argc == 0) { - goto goodbye; - } - listfile = *(++argv); - break; - case 'n': - { - char *cp=NULL; - - if (*(*argv+1) != 0) { - cp = ++(*argv); - } else { - if (--argc == 0) { - goto goodbye; - } - cp = *(++argv); - } - i = strtoul(cp, &tmp, 0); - if (*tmp) - show_usage(); - if (i == 14) - magic = MINIX_SUPER_MAGIC; - else if (i == 30) - magic = MINIX_SUPER_MAGIC2; - else - show_usage(); - namelen = i; - dirsize = i + 2; - stopIt=TRUE; - break; - } - case 'v': -#ifdef BB_FEATURE_MINIX2 - version2 = 1; -#else - error_msg("%s: not compiled with minix v2 support", - device_name); - exit(-1); -#endif - break; - case '-': - case 'h': - default: -goodbye: - show_usage(); - } - } - } else { - if (device_name == NULL) - device_name = *argv; - else if (BLOCKS == 0) - BLOCKS = strtol(*argv, &tmp, 0); - else { - goto goodbye; - } - } - argv++; - } - - if (device_name && !BLOCKS) - BLOCKS = get_size(device_name) / 1024; - if (!device_name || BLOCKS < 10) { - show_usage(); - } -#ifdef BB_FEATURE_MINIX2 - if (version2) { - if (namelen == 14) - magic = MINIX2_SUPER_MAGIC; - else - magic = MINIX2_SUPER_MAGIC2; - } else -#endif - if (BLOCKS > 65535) - BLOCKS = 65535; - check_mount(); /* is it already mounted? */ - tmp = root_block; - *(short *) tmp = 1; - strcpy(tmp + 2, "."); - tmp += dirsize; - *(short *) tmp = 1; - strcpy(tmp + 2, ".."); - tmp += dirsize; - *(short *) tmp = 2; - strcpy(tmp + 2, ".badblocks"); - DEV = open(device_name, O_RDWR); - if (DEV < 0) - error_msg_and_die("unable to open %s", device_name); - if (fstat(DEV, &statbuf) < 0) - error_msg_and_die("unable to stat %s", device_name); - if (!S_ISBLK(statbuf.st_mode)) - check = 0; - else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) - error_msg_and_die("will not try to make filesystem on '%s'", device_name); - setup_tables(); - if (check) - check_blocks(); - else if (listfile) - get_list_blocks(listfile); -#ifdef BB_FEATURE_MINIX2 - if (version2) { - make_root_inode2(); - make_bad_inode2(); - } else -#endif - { - make_root_inode(); - make_bad_inode(); - } - mark_good_blocks(); - write_tables(); - return( 0); - -} diff --git a/busybox/mknod.c b/busybox/mknod.c deleted file mode 100644 index b4d4b82a1..000000000 --- a/busybox/mknod.c +++ /dev/null @@ -1,92 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mknod implementation for busybox - * - * 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -int mknod_main(int argc, char **argv) -{ - char *thisarg; - mode_t mode = 0; - mode_t perm = 0666; - dev_t dev = 0; - - argc--; - argv++; - - /* Parse any options */ - while (argc > 1) { - if (**argv != '-') - break; - thisarg = *argv; - thisarg++; - switch (*thisarg) { - case 'm': - argc--; - argv++; - parse_mode(*argv, &perm); - umask(0); - break; - default: - show_usage(); - } - argc--; - argv++; - } - if (argc != 4 && argc != 2) { - show_usage(); - } - switch (argv[1][0]) { - case 'c': - case 'u': - mode = S_IFCHR; - break; - case 'b': - mode = S_IFBLK; - break; - case 'p': - mode = S_IFIFO; - if (argc!=2) { - show_usage(); - } - break; - default: - show_usage(); - } - - if (mode == S_IFCHR || mode == S_IFBLK) { - dev = (atoi(argv[2]) << 8) | atoi(argv[3]); - } - - mode |= perm; - - if (mknod(argv[0], mode, dev) != 0) - perror_msg_and_die("%s", argv[0]); - return EXIT_SUCCESS; -} - diff --git a/busybox/mkswap.c b/busybox/mkswap.c deleted file mode 100644 index f72c7009a..000000000 --- a/busybox/mkswap.c +++ /dev/null @@ -1,422 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * mkswap.c - set up a linux swap device - * - * (C) 1991 Linus Torvalds. This file may be redistributed as per - * the Linux copyright. - */ - -/* - * 20.12.91 - time began. Got VM working yesterday by doing this by hand. - * - * Usage: mkswap [-c] [-vN] [-f] device [size-in-blocks] - * - * -c for readability checking. (Use it unless you are SURE!) - * -vN for swap areas version N. (Only N=0,1 known today.) - * -f for forcing swap creation even if it would smash partition table. - * - * The device may be a block device or an image of one, but this isn't - * enforced (but it's not much fun on a character device :-). - * - * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the - * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995. - * - * Version 1 swap area code (for kernel 2.1.117), aeb, 981010. - * - * Sparc fixes, jj@ultra.linux.cz (Jakub Jelinek), 981201 - mangled by aeb. - * V1_MAX_PAGES fixes, jj, 990325. - * - * 1999-02-22 Arkadiusz Mi¶kiewicz - * - added Native Language Support - * - * from util-linux -- adapted for busybox by - * Erik Andersen . I ripped out Native Language - * Support, made some stuff smaller, and fitted for life in busybox. - * - */ - -#include -#include -#include -#include -#include -#include /* for _IO */ -#include -#include /* for PAGE_SIZE and PAGE_SHIFT */ - /* we also get PAGE_SIZE via getpagesize() */ -#include "busybox.h" - -#ifndef _IO -/* pre-1.3.45 */ -static const int BLKGETSIZE = 0x1260; -#else -/* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */ -#define BLKGETSIZE _IO(0x12,96) -#endif - -static char *device_name = NULL; -static int DEV = -1; -static long PAGES = 0; -static int check = 0; -static int badpages = 0; -static int version = -1; - -#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r)) - -/* - * The definition of the union swap_header uses the constant PAGE_SIZE. - * Unfortunately, on some architectures this depends on the hardware model, - * and can only be found at run time -- we use getpagesize(). - */ - -static int pagesize; -static int *signature_page; - -static struct swap_header_v1 { - char bootbits[1024]; /* Space for disklabel etc. */ - unsigned int version; - unsigned int last_page; - unsigned int nr_badpages; - unsigned int padding[125]; - unsigned int badpages[1]; -} *p; - -static void init_signature_page() -{ - pagesize = getpagesize(); - -#ifdef PAGE_SIZE - if (pagesize != PAGE_SIZE) - error_msg("Assuming pages of size %d", pagesize); -#endif - signature_page = (int *) xmalloc(pagesize); - memset(signature_page, 0, pagesize); - p = (struct swap_header_v1 *) signature_page; -} - -static void write_signature(char *sig) -{ - char *sp = (char *) signature_page; - - strncpy(sp + pagesize - 10, sig, 10); -} - -#define V0_MAX_PAGES (8 * (pagesize - 10)) -/* Before 2.2.0pre9 */ -#define V1_OLD_MAX_PAGES ((0x7fffffff / pagesize) - 1) -/* Since 2.2.0pre9: - error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL)) - with variations on - #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8)) - #define SWP_OFFSET(entry) ((entry) >> 8) - on the various architectures. Below the result - yuk. - - Machine pagesize SWP_ENTRY SWP_OFFSET bound+1 oldbound+2 - i386 2^12 o<<8 e>>8 1<<24 1<<19 - mips 2^12 o<<15 e>>15 1<<17 1<<19 - alpha 2^13 o<<40 e>>40 1<<24 1<<18 - m68k 2^12 o<<12 e>>12 1<<20 1<<19 - sparc 2^{12,13} (o&0x3ffff)<<9 (e>>9)&0x3ffff 1<<18 1<<{19,18} - sparc64 2^13 o<<13 e>>13 1<<51 1<<18 - ppc 2^12 o<<8 e>>8 1<<24 1<<19 - armo 2^{13,14,15} o<<8 e>>8 1<<24 1<<{18,17,16} - armv 2^12 o<<9 e>>9 1<<23 1<<19 - - assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere. - - The bad part is that we need to know this since the kernel will - refuse a swap space if it is too large. -*/ -/* patch from jj - why does this differ from the above? */ -#if defined(__alpha__) -#define V1_MAX_PAGES ((1 << 24) - 1) -#elif defined(__mips__) -#define V1_MAX_PAGES ((1 << 17) - 1) -#elif defined(__sparc_v9__) -#define V1_MAX_PAGES ((3 << 29) - 1) -#elif defined(__sparc__) -#define V1_MAX_PAGES (pagesize == 8192 ? ((3 << 29) - 1) : ((1 << 18) - 1)) -#else -#define V1_MAX_PAGES V1_OLD_MAX_PAGES -#endif -/* man page now says: -The maximum useful size of a swap area now depends on the architecture. -It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips, -128GB on alpha and 3TB on sparc64. -*/ - -#define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int)) - -static void bit_set(unsigned int *addr, unsigned int nr) -{ - unsigned int r, m; - - addr += nr / (8 * sizeof(int)); - - r = *addr; - m = 1 << (nr & (8 * sizeof(int) - 1)); - - *addr = r | m; -} - -static int bit_test_and_clear(unsigned int *addr, unsigned int nr) -{ - unsigned int r, m; - - addr += nr / (8 * sizeof(int)); - - r = *addr; - m = 1 << (nr & (8 * sizeof(int) - 1)); - - *addr = r & ~m; - return (r & m) != 0; -} - - -static void page_ok(int page) -{ - if (version == 0) - bit_set(signature_page, page); -} - -static void page_bad(int page) -{ - if (version == 0) - bit_test_and_clear(signature_page, page); - else { - if (badpages == MAX_BADPAGES) - error_msg_and_die("too many bad pages"); - p->badpages[badpages] = page; - } - badpages++; -} - -static void check_blocks(void) -{ - unsigned int current_page; - int do_seek = 1; - char *buffer; - - buffer = xmalloc(pagesize); - current_page = 0; - while (current_page < PAGES) { - if (!check) { - page_ok(current_page++); - continue; - } - if (do_seek && lseek(DEV, current_page * pagesize, SEEK_SET) != - current_page * pagesize) - error_msg_and_die("seek failed in check_blocks"); - if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) { - page_bad(current_page++); - continue; - } - page_ok(current_page++); - } - if (badpages == 1) - printf("one bad page\n"); - else if (badpages > 1) - printf("%d bad pages\n", badpages); -} - -static long valid_offset(int fd, int offset) -{ - char ch; - - if (lseek(fd, offset, 0) < 0) - return 0; - if (read(fd, &ch, 1) < 1) - return 0; - return 1; -} - -static int find_size(int fd) -{ - unsigned int high, low; - - low = 0; - for (high = 1; high > 0 && valid_offset(fd, high); high *= 2) - low = high; - while (low < high - 1) { - const int mid = (low + high) / 2; - - if (valid_offset(fd, mid)) - low = mid; - else - high = mid; - } - return (low + 1); -} - -/* return size in pages, to avoid integer overflow */ -static long get_size(const char *file) -{ - int fd; - long size; - - if ((fd = open(file, O_RDONLY)) < 0) - perror_msg_and_die("%s", file); - if (ioctl(fd, BLKGETSIZE, &size) >= 0) { - int sectors_per_page = pagesize / 512; - - size /= sectors_per_page; - } else { - size = find_size(fd) / pagesize; - } - close(fd); - return size; -} - -int mkswap_main(int argc, char **argv) -{ - char *tmp; - struct stat statbuf; - int sz; - int maxpages; - int goodpages; - int offset; - int force = 0; - - init_signature_page(); /* get pagesize */ - - while (argc-- > 1) { - argv++; - if (argv[0][0] != '-') { - if (device_name) { - int blocks_per_page = pagesize / 1024; - - PAGES = strtol(argv[0], &tmp, 0) / blocks_per_page; - if (*tmp) - show_usage(); - } else - device_name = argv[0]; - } else { - switch (argv[0][1]) { - case 'c': - check = 1; - break; - case 'f': - force = 1; - break; - case 'v': - version = atoi(argv[0] + 2); - break; - default: - show_usage(); - } - } - } - if (!device_name) { - error_msg("error: Nowhere to set up swap on?"); - show_usage(); - } - sz = get_size(device_name); - if (!PAGES) { - PAGES = sz; - } else if (PAGES > sz && !force) { - error_msg("error: size %ld is larger than device size %d", - PAGES * (pagesize / 1024), sz * (pagesize / 1024)); - return EXIT_FAILURE; - } - - if (version == -1) { - if (PAGES <= V0_MAX_PAGES) - version = 0; - else if (get_kernel_revision() < MAKE_VERSION(2, 1, 117)) - version = 0; - else if (pagesize < 2048) - version = 0; - else - version = 1; - } - if (version != 0 && version != 1) { - error_msg("error: unknown version %d", version); - show_usage(); - } - if (PAGES < 10) { - error_msg("error: swap area needs to be at least %ldkB", - (long) (10 * pagesize / 1024)); - show_usage(); - } -#if 0 - maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES); -#else - if (!version) - maxpages = V0_MAX_PAGES; - else if (get_kernel_revision() >= MAKE_VERSION(2, 2, 1)) - maxpages = V1_MAX_PAGES; - else { - maxpages = V1_OLD_MAX_PAGES; - if (maxpages > V1_MAX_PAGES) - maxpages = V1_MAX_PAGES; - } -#endif - if (PAGES > maxpages) { - PAGES = maxpages; - error_msg("warning: truncating swap area to %ldkB", - PAGES * pagesize / 1024); - } - - DEV = open(device_name, O_RDWR); - if (DEV < 0 || fstat(DEV, &statbuf) < 0) - perror_msg_and_die("%s", device_name); - if (!S_ISBLK(statbuf.st_mode)) - check = 0; - else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) - error_msg_and_die("Will not try to make swapdevice on '%s'", device_name); - -#ifdef __sparc__ - if (!force && version == 0) { - /* Don't overwrite partition table unless forced */ - unsigned char *buffer = (unsigned char *) signature_page; - unsigned short *q, sum; - - if (read(DEV, buffer, 512) != 512) - error_msg_and_die("fatal: first page unreadable"); - if (buffer[508] == 0xDA && buffer[509] == 0xBE) { - q = (unsigned short *) (buffer + 510); - for (sum = 0; q >= (unsigned short *) buffer;) - sum ^= *q--; - if (!sum) { - error_msg("Device '%s' contains a valid Sun disklabel.\n" -"This probably means creating v0 swap would destroy your partition table\n" -"No swap created. If you really want to create swap v0 on that device, use\n" -"the -f option to force it.", device_name); - return EXIT_FAILURE; - } - } - } -#endif - - if (version == 0 || check) - check_blocks(); - if (version == 0 && !bit_test_and_clear(signature_page, 0)) - error_msg_and_die("fatal: first page unreadable"); - if (version == 1) { - p->version = version; - p->last_page = PAGES - 1; - p->nr_badpages = badpages; - } - - goodpages = PAGES - badpages - 1; - if (goodpages <= 0) - error_msg_and_die("Unable to set up swap-space: unreadable"); - printf("Setting up swapspace version %d, size = %ld bytes\n", - version, (long) (goodpages * pagesize)); - write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2"); - - offset = ((version == 0) ? 0 : 1024); - if (lseek(DEV, offset, SEEK_SET) != offset) - error_msg_and_die("unable to rewind swap-device"); - if (write(DEV, (char *) signature_page + offset, pagesize - offset) - != pagesize - offset) - error_msg_and_die("unable to write signature page"); - - /* - * A subsequent swapon() will fail if the signature - * is not actually on disk. (This is a kernel bug.) - */ - if (fsync(DEV)) - error_msg_and_die("fsync failed"); - return EXIT_SUCCESS; -} diff --git a/busybox/mktemp.c b/busybox/mktemp.c deleted file mode 100644 index bc47d0af0..000000000 --- a/busybox/mktemp.c +++ /dev/null @@ -1,40 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mktemp implementation for busybox - * - * - * Copyright (C) 2000 by Daniel Jacobowitz - * Written by Daniel Jacobowitz - * - * 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 "busybox.h" - -extern int mktemp_main(int argc, char **argv) -{ - if (argc != 2 && (argc != 3 || strcmp(argv[1], "-q"))) - show_usage(); - if(mkstemp(argv[argc-1]) < 0) - return EXIT_FAILURE; - (void) puts(argv[argc-1]); - return EXIT_SUCCESS; -} diff --git a/busybox/modprobe.c b/busybox/modprobe.c deleted file mode 100644 index 05b40c53f..000000000 --- a/busybox/modprobe.c +++ /dev/null @@ -1,121 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * really dumb modprobe implementation for busybox - * Copyright (C) 2001 Lineo, davidm@lineo.com - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -static char cmd[128]; - -extern int modprobe_main(int argc, char** argv) -{ - int ch, rc = 0; - int loadall = 0, showconfig = 0, debug = 0, autoclean = 0, list = 0; - int show_only = 0, quiet = 0, remove_opt = 0, do_syslog = 0, verbose = 0; - char *load_type = NULL, *config = NULL; - - while ((ch = getopt(argc, argv, "acdklnqrst:vVC:")) != -1) - switch(ch) { - case 'a': - loadall++; - break; - case 'c': - showconfig++; - break; - case 'd': - debug++; - break; - case 'k': - autoclean++; - break; - case 'l': - list++; - break; - case 'n': - show_only++; - break; - case 'q': - quiet++; - break; - case 'r': - remove_opt++; - break; - case 's': - do_syslog++; - break; - case 't': - load_type = optarg; - break; - case 'v': - verbose++; - break; - case 'C': - config = optarg; - break; - case 'V': - default: - show_usage(); - break; - } - - if (load_type || config) { - fprintf(stderr, "-t and -C not supported\n"); - exit(EXIT_FAILURE); - } - - if (showconfig) - exit(EXIT_SUCCESS); - - if (list) - exit(EXIT_SUCCESS); - - if (remove_opt) { - do { - sprintf(cmd, "rmmod %s %s %s", - optind >= argc ? "-a" : "", - do_syslog ? "-s" : "", - optind < argc ? argv[optind] : ""); - if (do_syslog) - syslog(LOG_INFO, "%s", cmd); - if (show_only || verbose) - printf("%s\n", cmd); - if (!show_only) - rc = system(cmd); - } while (++optind < argc); - exit(EXIT_SUCCESS); - } - - if (optind >= argc) { - fprintf(stderr, "No module or pattern provided\n"); - exit(EXIT_FAILURE); - } - - sprintf(cmd, "insmod %s %s %s", - do_syslog ? "-s" : "", - quiet ? "-q" : "", - autoclean ? "-k" : ""); - while (optind < argc) { - strcat(cmd, argv[optind]); - strcat(cmd, " "); - optind++; - } - if (do_syslog) - syslog(LOG_INFO, "%s", cmd); - if (show_only || verbose) - printf("%s\n", cmd); - if (!show_only) - rc = system(cmd); - else - rc = 0; - - exit(rc ? EXIT_FAILURE : EXIT_SUCCESS); -} - - diff --git a/busybox/modutils/insmod.c b/busybox/modutils/insmod.c deleted file mode 100644 index 413af5ce7..000000000 --- a/busybox/modutils/insmod.c +++ /dev/null @@ -1,3481 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini insmod implementation for busybox - * - * This version of insmod supports x86, ARM, SH3/4, powerpc, m68k, - * and MIPS. - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen - * and Ron Alder - * - * Modified by Bryan Rittmeyer to support SH4 - * and (theoretically) SH3. I have only tested SH4 in little endian mode. - * - * Modified by Alcove, Julien Gaulmin and - * Nicolas Ferre to support ARM7TDMI. Only - * very minor changes required to also work with StrongArm and presumably - * all ARM based systems. - * - * Magnus Damm added PowerPC support 20-Feb-2001. - * PowerPC specific code stolen from modutils-2.3.16, - * written by Paul Mackerras, Copyright 1996, 1997 Linux International. - * I've only tested the code on mpc8xx platforms in big-endian mode. - * Did some cleanup and added BB_USE_xxx_ENTRIES... - * - * Quinn Jensen added MIPS support 23-Feb-2001. - * based on modutils-2.4.2 - * MIPS specific support for Elf loading and relocation. - * Copyright 1996, 1997 Linux International. - * Contributed by Ralf Baechle - * - * Based almost entirely on the Linux modutils-2.3.11 implementation. - * Copyright 1996, 1997 Linux International. - * New implementation contributed by Richard Henderson - * Based on original work by Bjorn Ekwall - * Restructured (and partly rewritten) by: - * Björn Ekwall February 1999 - * - * 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 -#include -#include "busybox.h" - -#ifdef BB_FEATURE_NEW_MODULE_INTERFACE -# undef BB_FEATURE_OLD_MODULE_INTERFACE -# define new_sys_init_module init_module -#else -# define old_sys_init_module init_module -#endif - -#ifdef BB_FEATURE_INSMOD_LOADINKMEM -#define LOADBITS 0 -#else -#define LOADBITS 1 -#endif - -#if defined(__powerpc__) -#define BB_USE_PLT_ENTRIES -#define BB_PLT_ENTRY_SIZE 16 -#endif - -#if defined(__arm__) -#define BB_USE_PLT_ENTRIES -#define BB_PLT_ENTRY_SIZE 8 -#define BB_USE_GOT_ENTRIES -#define BB_GOT_ENTRY_SIZE 8 -#endif - -#if defined(__sh__) -#define BB_USE_GOT_ENTRIES -#define BB_GOT_ENTRY_SIZE 4 -#endif - -#if defined(__i386__) -#define BB_USE_GOT_ENTRIES -#define BB_GOT_ENTRY_SIZE 4 -#endif - -#if defined(__mips__) -// neither used -#endif - -//---------------------------------------------------------------------------- -//--------modutils module.h, lines 45-242 -//---------------------------------------------------------------------------- - -/* Definitions for the Linux module syscall interface. - Copyright 1996, 1997 Linux International. - - Contributed by Richard Henderson - - This file is part of the Linux modutils. - - 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. */ - - -#ifndef MODUTILS_MODULE_H -static const int MODUTILS_MODULE_H = 1; - -/* This file contains the structures used by the 2.0 and 2.1 kernels. - We do not use the kernel headers directly because we do not wish - to be dependant on a particular kernel version to compile insmod. */ - - -/*======================================================================*/ -/* The structures used by Linux 2.0. */ - -/* The symbol format used by get_kernel_syms(2). */ -struct old_kernel_sym -{ - unsigned long value; - char name[60]; -}; - -struct old_module_ref -{ - unsigned long module; /* kernel addresses */ - unsigned long next; -}; - -struct old_module_symbol -{ - unsigned long addr; - unsigned long name; -}; - -struct old_symbol_table -{ - int size; /* total, including string table!!! */ - int n_symbols; - int n_refs; - struct old_module_symbol symbol[0]; /* actual size defined by n_symbols */ - struct old_module_ref ref[0]; /* actual size defined by n_refs */ -}; - -struct old_mod_routines -{ - unsigned long init; - unsigned long cleanup; -}; - -struct old_module -{ - unsigned long next; - unsigned long ref; /* the list of modules that refer to me */ - unsigned long symtab; - unsigned long name; - int size; /* size of module in pages */ - unsigned long addr; /* address of module */ - int state; - unsigned long cleanup; /* cleanup routine */ -}; - -/* Sent to init_module(2) or'ed into the code size parameter. */ -static const int OLD_MOD_AUTOCLEAN = 0x40000000; /* big enough, but no sign problems... */ - -int get_kernel_syms(struct old_kernel_sym *); -int old_sys_init_module(const char *name, char *code, unsigned codesize, - struct old_mod_routines *, struct old_symbol_table *); - -/*======================================================================*/ -/* For sizeof() which are related to the module platform and not to the - environment isnmod is running in, use sizeof_xx instead of sizeof(xx). */ - -#define tgt_sizeof_char sizeof(char) -#define tgt_sizeof_short sizeof(short) -#define tgt_sizeof_int sizeof(int) -#define tgt_sizeof_long sizeof(long) -#define tgt_sizeof_char_p sizeof(char *) -#define tgt_sizeof_void_p sizeof(void *) -#define tgt_long long - -#if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64) -#undef tgt_sizeof_long -#undef tgt_sizeof_char_p -#undef tgt_sizeof_void_p -#undef tgt_long -static const int tgt_sizeof_long = 8; -static const int tgt_sizeof_char_p = 8; -static const int tgt_sizeof_void_p = 8; -#define tgt_long long long -#endif - -/*======================================================================*/ -/* The structures used in Linux 2.1. */ - -/* Note: new_module_symbol does not use tgt_long intentionally */ -struct new_module_symbol -{ - unsigned long value; - unsigned long name; -}; - -struct new_module_persist; - -struct new_module_ref -{ - unsigned tgt_long dep; /* kernel addresses */ - unsigned tgt_long ref; - unsigned tgt_long next_ref; -}; - -struct new_module -{ - unsigned tgt_long size_of_struct; /* == sizeof(module) */ - unsigned tgt_long next; - unsigned tgt_long name; - unsigned tgt_long size; - - tgt_long usecount; - unsigned tgt_long flags; /* AUTOCLEAN et al */ - - unsigned nsyms; - unsigned ndeps; - - unsigned tgt_long syms; - unsigned tgt_long deps; - unsigned tgt_long refs; - unsigned tgt_long init; - unsigned tgt_long cleanup; - unsigned tgt_long ex_table_start; - unsigned tgt_long ex_table_end; -#ifdef __alpha__ - unsigned tgt_long gp; -#endif - /* Everything after here is extension. */ - unsigned tgt_long persist_start; - unsigned tgt_long persist_end; - unsigned tgt_long can_unload; - unsigned tgt_long runsize; -#ifdef BB_FEATURE_NEW_MODULE_INTERFACE - const char *kallsyms_start; /* All symbols for kernel debugging */ - const char *kallsyms_end; - const char *archdata_start; /* arch specific data for module */ - const char *archdata_end; - const char *kernel_data; /* Reserved for kernel internal use */ -#endif -}; - -#define ARCHDATA_SEC_NAME "__archdata" -#define KALLSYMS_SEC_NAME "__kallsyms" - - -struct new_module_info -{ - unsigned long addr; - unsigned long size; - unsigned long flags; - long usecount; -}; - -/* Bits of module.flags. */ -static const int NEW_MOD_RUNNING = 1; -static const int NEW_MOD_DELETED = 2; -static const int NEW_MOD_AUTOCLEAN = 4; -static const int NEW_MOD_VISITED = 8; -static const int NEW_MOD_USED_ONCE = 16; - -int new_sys_init_module(const char *name, const struct new_module *); -int query_module(const char *name, int which, void *buf, size_t bufsize, - size_t *ret); - -/* Values for query_module's which. */ - -static const int QM_MODULES = 1; -static const int QM_DEPS = 2; -static const int QM_REFS = 3; -static const int QM_SYMBOLS = 4; -static const int QM_INFO = 5; - -/*======================================================================*/ -/* The system calls unchanged between 2.0 and 2.1. */ - -unsigned long create_module(const char *, size_t); -int delete_module(const char *); - - -#endif /* module.h */ - -//---------------------------------------------------------------------------- -//--------end of modutils module.h -//---------------------------------------------------------------------------- - - - -//---------------------------------------------------------------------------- -//--------modutils obj.h, lines 253-462 -//---------------------------------------------------------------------------- - -/* Elf object file loading and relocation routines. - Copyright 1996, 1997 Linux International. - - Contributed by Richard Henderson - - This file is part of the Linux modutils. - - 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. */ - - -#ifndef MODUTILS_OBJ_H -static const int MODUTILS_OBJ_H = 1; - -/* The relocatable object is manipulated using elfin types. */ - -#include -#include - - -/* Machine-specific elf macros for i386 et al. */ - -/* the SH changes have only been tested on the SH4 in =little endian= mode */ -/* I'm not sure about big endian, so let's warn: */ - -#if (defined(__SH4__) || defined(__SH3__)) && defined(__BIG_ENDIAN__) -#error insmod.c may require changes for use on big endian SH4/SH3 -#endif - -/* it may or may not work on the SH1/SH2... So let's error on those - also */ -#if (defined(__sh__) && (!(defined(__SH3__) || defined(__SH4__)))) -#error insmod.c may require changes for non-SH3/SH4 use -#endif - -#define ELFCLASSM ELFCLASS32 - -#if (defined(__mc68000__)) -#define ELFDATAM ELFDATA2MSB -#endif - - - -#if defined(__sh__) - -#define MATCH_MACHINE(x) (x == EM_SH) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela -#define ELFDATAM ELFDATA2LSB - -#elif defined(__arm__) - -#define MATCH_MACHINE(x) (x == EM_ARM) -#define SHT_RELM SHT_REL -#define Elf32_RelM Elf32_Rel -#define ELFDATAM ELFDATA2LSB - -#elif defined(__powerpc__) - -#define MATCH_MACHINE(x) (x == EM_PPC) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela -#define ELFDATAM ELFDATA2MSB - -#elif defined(__mips__) - -/* Account for ELF spec changes. */ -#ifndef EM_MIPS_RS3_LE -#ifdef EM_MIPS_RS4_BE -#define EM_MIPS_RS3_LE EM_MIPS_RS4_BE -#else -#define EM_MIPS_RS3_LE 10 -#endif -#endif /* !EM_MIPS_RS3_LE */ - -#define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE) -#define SHT_RELM SHT_REL -#define Elf32_RelM Elf32_Rel -#ifdef __MIPSEB__ -#define ELFDATAM ELFDATA2MSB -#endif -#ifdef __MIPSEL__ -#define ELFDATAM ELFDATA2LSB -#endif - -#elif defined(__i386__) - -/* presumably we can use these for anything but the SH and ARM*/ -/* this is the previous behavior, but it does result in - insmod.c being broken on anything except i386 */ -#ifndef EM_486 -#define MATCH_MACHINE(x) (x == EM_386) -#else -#define MATCH_MACHINE(x) (x == EM_386 || x == EM_486) -#endif - -#define SHT_RELM SHT_REL -#define Elf32_RelM Elf32_Rel -#define ELFDATAM ELFDATA2LSB - -#elif defined(__mc68000__) - -#define MATCH_MACHINE(x) (x == EM_68K) -#define SHT_RELM SHT_RELA -#define Elf32_RelM Elf32_Rela - -#else -#error Sorry, but insmod.c does not yet support this architecture... -#endif - -#ifndef ElfW -# if ELFCLASSM == ELFCLASS32 -# define ElfW(x) Elf32_ ## x -# define ELFW(x) ELF32_ ## x -# else -# define ElfW(x) Elf64_ ## x -# define ELFW(x) ELF64_ ## x -# endif -#endif - -/* For some reason this is missing from libc5. */ -#ifndef ELF32_ST_INFO -# define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) -#endif - -#ifndef ELF64_ST_INFO -# define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) -#endif - -struct obj_string_patch; -struct obj_symbol_patch; - -struct obj_section -{ - ElfW(Shdr) header; - const char *name; - char *contents; - struct obj_section *load_next; - int idx; -}; - -struct obj_symbol -{ - struct obj_symbol *next; /* hash table link */ - const char *name; - unsigned long value; - unsigned long size; - int secidx; /* the defining section index/module */ - int info; - int ksymidx; /* for export to the kernel symtab */ - int referenced; /* actually used in the link */ -}; - -/* Hardcode the hash table size. We shouldn't be needing so many - symbols that we begin to degrade performance, and we get a big win - by giving the compiler a constant divisor. */ - -#define HASH_BUCKETS 521 - -struct obj_file -{ - ElfW(Ehdr) header; - ElfW(Addr) baseaddr; - struct obj_section **sections; - struct obj_section *load_order; - struct obj_section **load_order_search_start; - struct obj_string_patch *string_patches; - struct obj_symbol_patch *symbol_patches; - int (*symbol_cmp)(const char *, const char *); - unsigned long (*symbol_hash)(const char *); - unsigned long local_symtab_size; - struct obj_symbol **local_symtab; - struct obj_symbol *symtab[HASH_BUCKETS]; -}; - -enum obj_reloc -{ - obj_reloc_ok, - obj_reloc_overflow, - obj_reloc_dangerous, - obj_reloc_unhandled -}; - -struct obj_string_patch -{ - struct obj_string_patch *next; - int reloc_secidx; - ElfW(Addr) reloc_offset; - ElfW(Addr) string_offset; -}; - -struct obj_symbol_patch -{ - struct obj_symbol_patch *next; - int reloc_secidx; - ElfW(Addr) reloc_offset; - struct obj_symbol *sym; -}; - - -/* Generic object manipulation routines. */ - -static unsigned long obj_elf_hash(const char *); - -static unsigned long obj_elf_hash_n(const char *, unsigned long len); - -static struct obj_symbol *obj_find_symbol (struct obj_file *f, - const char *name); - -static ElfW(Addr) obj_symbol_final_value(struct obj_file *f, - struct obj_symbol *sym); - -#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING -static void obj_set_symbol_compare(struct obj_file *f, - int (*cmp)(const char *, const char *), - unsigned long (*hash)(const char *)); -#endif - -static struct obj_section *obj_find_section (struct obj_file *f, - const char *name); - -static void obj_insert_section_load_order (struct obj_file *f, - struct obj_section *sec); - -static struct obj_section *obj_create_alloced_section (struct obj_file *f, - const char *name, - unsigned long align, - unsigned long size); - -static struct obj_section *obj_create_alloced_section_first (struct obj_file *f, - const char *name, - unsigned long align, - unsigned long size); - -static void *obj_extend_section (struct obj_section *sec, unsigned long more); - -static int obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, - const char *string); - -static int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, - struct obj_symbol *sym); - -static int obj_check_undefineds(struct obj_file *f); - -static void obj_allocate_commons(struct obj_file *f); - -static unsigned long obj_load_size (struct obj_file *f); - -static int obj_relocate (struct obj_file *f, ElfW(Addr) base); - -static struct obj_file *obj_load(FILE *f, int loadprogbits); - -static int obj_create_image (struct obj_file *f, char *image); - -/* Architecture specific manipulation routines. */ - -static struct obj_file *arch_new_file (void); - -static struct obj_section *arch_new_section (void); - -static struct obj_symbol *arch_new_symbol (void); - -static enum obj_reloc arch_apply_relocation (struct obj_file *f, - struct obj_section *targsec, - struct obj_section *symsec, - struct obj_symbol *sym, - ElfW(RelM) *rel, ElfW(Addr) value); - -static int arch_create_got (struct obj_file *f); - -static int arch_init_module (struct obj_file *f, struct new_module *); - -#endif /* obj.h */ -//---------------------------------------------------------------------------- -//--------end of modutils obj.h -//---------------------------------------------------------------------------- - - - - - -#define _PATH_MODULES "/lib/modules" -static const int STRVERSIONLEN = 32; - -/*======================================================================*/ - -static int flag_force_load = 0; -static int flag_autoclean = 0; -static int flag_verbose = 0; -static int flag_export = 1; - - -/*======================================================================*/ - -/* previously, these were named i386_* but since we could be - compiling for the sh, I've renamed them to the more general - arch_* These structures are the same between the x86 and SH, - and we can't support anything else right now anyway. In the - future maybe they should be #if defined'd */ - -/* Done ;-) */ - - - -#if defined(BB_USE_PLT_ENTRIES) -struct arch_plt_entry -{ - int offset; - int allocated:1; - int inited:1; /* has been set up */ -}; -#endif - -#if defined(BB_USE_GOT_ENTRIES) -struct arch_got_entry { - int offset; - unsigned offset_done:1; - unsigned reloc_done:1; -}; -#endif - -#if defined(__mips__) -struct mips_hi16 -{ - struct mips_hi16 *next; - Elf32_Addr *addr; - Elf32_Addr value; -}; -#endif - -struct arch_file { - struct obj_file root; -#if defined(BB_USE_PLT_ENTRIES) - struct obj_section *plt; -#endif -#if defined(BB_USE_GOT_ENTRIES) - struct obj_section *got; -#endif -#if defined(__mips__) - struct mips_hi16 *mips_hi16_list; -#endif -}; - -struct arch_symbol { - struct obj_symbol root; -#if defined(BB_USE_PLT_ENTRIES) - struct arch_plt_entry pltent; -#endif -#if defined(BB_USE_GOT_ENTRIES) - struct arch_got_entry gotent; -#endif -}; - - -struct external_module { - const char *name; - ElfW(Addr) addr; - int used; - size_t nsyms; - struct new_module_symbol *syms; -}; - -static struct new_module_symbol *ksyms; -static size_t nksyms; - -static struct external_module *ext_modules; -static int n_ext_modules; -static int n_ext_modules_used; -extern int delete_module(const char *); - -static char m_filename[FILENAME_MAX + 1]; -static char m_fullName[FILENAME_MAX + 1]; - - - -/*======================================================================*/ - - -static int check_module_name_match(const char *filename, struct stat *statbuf, - void *userdata) -{ - char *fullname = (char *) userdata; - - if (fullname[0] == '\0') - return (FALSE); - else { - char *tmp, *tmp1 = strdup(filename); - tmp = get_last_path_component(tmp1); - if (strcmp(tmp, fullname) == 0) { - free(tmp1); - /* Stop searching if we find a match */ - safe_strncpy(m_filename, filename, sizeof(m_filename)); - return (TRUE); - } - free(tmp1); - } - return (FALSE); -} - - -/*======================================================================*/ - -static struct obj_file *arch_new_file(void) -{ - struct arch_file *f; - f = xmalloc(sizeof(*f)); - -#if defined(BB_USE_PLT_ENTRIES) - f->plt = NULL; -#endif -#if defined(BB_USE_GOT_ENTRIES) - f->got = NULL; -#endif -#if defined(__mips__) - f->mips_hi16_list = NULL; -#endif - - return &f->root; -} - -static struct obj_section *arch_new_section(void) -{ - return xmalloc(sizeof(struct obj_section)); -} - -static struct obj_symbol *arch_new_symbol(void) -{ - struct arch_symbol *sym; - sym = xmalloc(sizeof(*sym)); - -#if defined(BB_USE_PLT_ENTRIES) - memset(&sym->pltent, 0, sizeof(sym->pltent)); -#endif -#if defined(BB_USE_GOT_ENTRIES) - memset(&sym->gotent, 0, sizeof(sym->gotent)); -#endif - - return &sym->root; -} - -static enum obj_reloc -arch_apply_relocation(struct obj_file *f, - struct obj_section *targsec, - struct obj_section *symsec, - struct obj_symbol *sym, - ElfW(RelM) *rel, ElfW(Addr) v) -{ - struct arch_file *ifile = (struct arch_file *) f; -#if !(defined(__mips__)) - struct arch_symbol *isym = (struct arch_symbol *) sym; -#endif - - ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset); - ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset; -#if defined(BB_USE_GOT_ENTRIES) - ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0; -#endif -#if defined(BB_USE_PLT_ENTRIES) - ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0; - struct arch_plt_entry *pe; - unsigned long *ip; -#endif - enum obj_reloc ret = obj_reloc_ok; - - switch (ELF32_R_TYPE(rel->r_info)) { - -/* even though these constants seem to be the same for - the i386 and the sh, we "#if define" them for clarity - and in case that ever changes */ -#if defined(__sh__) - case R_SH_NONE: -#elif defined(__arm__) - case R_ARM_NONE: -#elif defined(__i386__) - case R_386_NONE: -#elif defined(__mc68000__) - case R_68K_NONE: -#elif defined(__powerpc__) - case R_PPC_NONE: -#elif defined(__mips__) - case R_MIPS_NONE: -#endif - break; - -#if defined(__sh__) - case R_SH_DIR32: -#elif defined(__arm__) - case R_ARM_ABS32: -#elif defined(__i386__) - case R_386_32: -#elif defined(__mc68000__) - case R_68K_32: -#elif defined(__powerpc__) - case R_PPC_ADDR32: -#elif defined(__mips__) - case R_MIPS_32: -#endif - *loc += v; - break; -#if defined(__mc68000__) - case R_68K_8: - if (v > 0xff) - ret = obj_reloc_overflow; - *(char *)loc = v; - break; - case R_68K_16: - if (v > 0xffff) - ret = obj_reloc_overflow; - *(short *)loc = v; - break; -#endif /* __mc68000__ */ - -#if defined(__powerpc__) - case R_PPC_ADDR16_HA: - *(unsigned short *)loc = (v + 0x8000) >> 16; - break; - - case R_PPC_ADDR16_HI: - *(unsigned short *)loc = v >> 16; - break; - - case R_PPC_ADDR16_LO: - *(unsigned short *)loc = v; - break; -#endif - -#if defined(__mips__) - case R_MIPS_26: - if (v % 4) - ret = obj_reloc_dangerous; - if ((v & 0xf0000000) != ((dot + 4) & 0xf0000000)) - ret = obj_reloc_overflow; - *loc = - (*loc & ~0x03ffffff) | ((*loc + (v >> 2)) & - 0x03ffffff); - break; - - case R_MIPS_HI16: - { - struct mips_hi16 *n; - - /* We cannot relocate this one now because we don't know the value - of the carry we need to add. Save the information, and let LO16 - do the actual relocation. */ - n = (struct mips_hi16 *) xmalloc(sizeof *n); - n->addr = loc; - n->value = v; - n->next = ifile->mips_hi16_list; - ifile->mips_hi16_list = n; - break; - } - - case R_MIPS_LO16: - { - unsigned long insnlo = *loc; - Elf32_Addr val, vallo; - - /* Sign extend the addend we extract from the lo insn. */ - vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; - - if (ifile->mips_hi16_list != NULL) { - struct mips_hi16 *l; - - l = ifile->mips_hi16_list; - while (l != NULL) { - struct mips_hi16 *next; - unsigned long insn; - - /* The value for the HI16 had best be the same. */ - assert(v == l->value); - - /* Do the HI16 relocation. Note that we actually don't - need to know anything about the LO16 itself, except where - to find the low 16 bits of the addend needed by the LO16. */ - insn = *l->addr; - val = - ((insn & 0xffff) << 16) + - vallo; - val += v; - - /* Account for the sign extension that will happen in the - low bits. */ - val = - ((val >> 16) + - ((val & 0x8000) != - 0)) & 0xffff; - - insn = (insn & ~0xffff) | val; - *l->addr = insn; - - next = l->next; - free(l); - l = next; - } - - ifile->mips_hi16_list = NULL; - } - - /* Ok, we're done with the HI16 relocs. Now deal with the LO16. */ - val = v + vallo; - insnlo = (insnlo & ~0xffff) | (val & 0xffff); - *loc = insnlo; - break; - } -#endif - -#if defined(__arm__) -#elif defined(__sh__) - case R_SH_REL32: - *loc += v - dot; - break; -#elif defined(__i386__) - case R_386_PLT32: - case R_386_PC32: - *loc += v - dot; - break; -#elif defined(__mc68000__) - case R_68K_PC8: - v -= dot; - if ((Elf32_Sword)v > 0x7f || (Elf32_Sword)v < -(Elf32_Sword)0x80) - ret = obj_reloc_overflow; - *(char *)loc = v; - break; - case R_68K_PC16: - v -= dot; - if ((Elf32_Sword)v > 0x7fff || (Elf32_Sword)v < -(Elf32_Sword)0x8000) - ret = obj_reloc_overflow; - *(short *)loc = v; - break; - case R_68K_PC32: - *(int *)loc = v - dot; - break; -#elif defined(__powerpc__) - case R_PPC_REL32: - *loc = v - dot; - break; -#endif - -#if defined(__sh__) - case R_SH_PLT32: - *loc = v - dot; - break; -#elif defined(__i386__) -#endif - -#if defined(BB_USE_PLT_ENTRIES) - -#if defined(__arm__) - case R_ARM_PC24: - case R_ARM_PLT32: -#endif -#if defined(__powerpc__) - case R_PPC_REL24: -#endif - /* find the plt entry and initialize it if necessary */ - assert(isym != NULL); - - pe = (struct arch_plt_entry*) &isym->pltent; - - if (! pe->inited) { - ip = (unsigned long *) (ifile->plt->contents + pe->offset); - - /* generate some machine code */ - -#if defined(__arm__) - ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */ - ip[1] = v; /* sym@ */ -#endif -#if defined(__powerpc__) - ip[0] = 0x3d600000 + ((v + 0x8000) >> 16); /* lis r11,sym@ha */ - ip[1] = 0x396b0000 + (v & 0xffff); /* addi r11,r11,sym@l */ - ip[2] = 0x7d6903a6; /* mtctr r11 */ - ip[3] = 0x4e800420; /* bctr */ -#endif - pe->inited = 1; - } - - /* relative distance to target */ - v -= dot; - /* if the target is too far away.... */ - if ((int)v < -0x02000000 || (int)v >= 0x02000000) { - /* go via the plt */ - v = plt + pe->offset - dot; - } - if (v & 3) - ret = obj_reloc_dangerous; - - /* merge the offset into the instruction. */ -#if defined(__arm__) - /* Convert to words. */ - v >>= 2; - - *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff); -#endif -#if defined(__powerpc__) - *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc); -#endif - break; -#endif /* BB_USE_PLT_ENTRIES */ - -#if defined(__arm__) -#elif defined(__sh__) - case R_SH_GLOB_DAT: - case R_SH_JMP_SLOT: - *loc = v; - break; -#elif defined(__i386__) - case R_386_GLOB_DAT: - case R_386_JMP_SLOT: - *loc = v; - break; -#elif defined(__mc68000__) - case R_68K_GLOB_DAT: - case R_68K_JMP_SLOT: - *loc = v; - break; -#endif - -#if defined(__arm__) -#elif defined(__sh__) - case R_SH_RELATIVE: - *loc += f->baseaddr + rel->r_addend; - break; -#elif defined(__i386__) - case R_386_RELATIVE: - *loc += f->baseaddr; - break; -#elif defined(__mc68000__) - case R_68K_RELATIVE: - *(int *)loc += f->baseaddr; - break; -#endif - -#if defined(BB_USE_GOT_ENTRIES) - -#if !defined(__68k__) -#if defined(__sh__) - case R_SH_GOTPC: -#elif defined(__arm__) - case R_ARM_GOTPC: -#elif defined(__i386__) - case R_386_GOTPC: -#endif - assert(got != 0); -#if defined(__sh__) - *loc += got - dot + rel->r_addend;; -#elif defined(__i386__) || defined(__arm__) || defined(__m68k_) - *loc += got - dot; -#endif - break; -#endif // __68k__ - -#if defined(__sh__) - case R_SH_GOT32: -#elif defined(__arm__) - case R_ARM_GOT32: -#elif defined(__i386__) - case R_386_GOT32: -#elif defined(__mc68000__) - case R_68K_GOT32: -#endif - assert(isym != NULL); - /* needs an entry in the .got: set it, once */ - if (!isym->gotent.reloc_done) { - isym->gotent.reloc_done = 1; - *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v; - } - /* make the reloc with_respect_to_.got */ -#if defined(__sh__) - *loc += isym->gotent.offset + rel->r_addend; -#elif defined(__i386__) || defined(__arm__) || defined(__mc68000__) - *loc += isym->gotent.offset; -#endif - break; - - /* address relative to the got */ -#if !defined(__mc68000__) -#if defined(__sh__) - case R_SH_GOTOFF: -#elif defined(__arm__) - case R_ARM_GOTOFF: -#elif defined(__i386__) - case R_386_GOTOFF: -#elif defined(__mc68000__) - case R_68K_GOTOFF: -#endif - assert(got != 0); - *loc += v - got; - break; -#endif // __mc68000__ - -#endif /* BB_USE_GOT_ENTRIES */ - - default: - printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info)); - ret = obj_reloc_unhandled; - break; - } - - return ret; -} - -static int arch_create_got(struct obj_file *f) -{ -#if defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES) - struct arch_file *ifile = (struct arch_file *) f; - int i; -#if defined(BB_USE_GOT_ENTRIES) - int got_offset = 0, gotneeded = 0; -#endif -#if defined(BB_USE_PLT_ENTRIES) - int plt_offset = 0, pltneeded = 0; -#endif - struct obj_section *relsec, *symsec, *strsec; - ElfW(RelM) *rel, *relend; - ElfW(Sym) *symtab, *extsym; - const char *strtab, *name; - struct arch_symbol *intsym; - - for (i = 0; i < f->header.e_shnum; ++i) { - relsec = f->sections[i]; - if (relsec->header.sh_type != SHT_RELM) - continue; - - symsec = f->sections[relsec->header.sh_link]; - strsec = f->sections[symsec->header.sh_link]; - - rel = (ElfW(RelM) *) relsec->contents; - relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM))); - symtab = (ElfW(Sym) *) symsec->contents; - strtab = (const char *) strsec->contents; - - for (; rel < relend; ++rel) { - extsym = &symtab[ELF32_R_SYM(rel->r_info)]; - - switch (ELF32_R_TYPE(rel->r_info)) { -#if defined(__arm__) - case R_ARM_GOT32: - break; -#elif defined(__sh__) - case R_SH_GOT32: - break; -#elif defined(__i386__) - case R_386_GOT32: - break; -#elif defined(__mc68000__) - case R_68K_GOT32: - break; -#endif - -#if defined(__powerpc__) - case R_PPC_REL24: - pltneeded = 1; - break; -#endif - -#if defined(__arm__) - case R_ARM_PC24: - case R_ARM_PLT32: - pltneeded = 1; - break; - - case R_ARM_GOTPC: - case R_ARM_GOTOFF: - gotneeded = 1; - if (got_offset == 0) - got_offset = 4; -#elif defined(__sh__) - case R_SH_GOTPC: - case R_SH_GOTOFF: - gotneeded = 1; -#elif defined(__i386__) - case R_386_GOTPC: - case R_386_GOTOFF: - gotneeded = 1; -#endif - - default: - continue; - } - - if (extsym->st_name != 0) { - name = strtab + extsym->st_name; - } else { - name = f->sections[extsym->st_shndx]->name; - } - intsym = (struct arch_symbol *) obj_find_symbol(f, name); -#if defined(BB_USE_GOT_ENTRIES) - if (!intsym->gotent.offset_done) { - intsym->gotent.offset_done = 1; - intsym->gotent.offset = got_offset; - got_offset += BB_GOT_ENTRY_SIZE; - } -#endif -#if defined(BB_USE_PLT_ENTRIES) - if (pltneeded && intsym->pltent.allocated == 0) { - intsym->pltent.allocated = 1; - intsym->pltent.offset = plt_offset; - plt_offset += BB_PLT_ENTRY_SIZE; - intsym->pltent.inited = 0; - pltneeded = 0; - } -#endif - } - } - -#if defined(BB_USE_GOT_ENTRIES) - if (got_offset) { - struct obj_section* myrelsec = obj_find_section(f, ".got"); - - if (myrelsec) { - obj_extend_section(myrelsec, got_offset); - } else { - myrelsec = obj_create_alloced_section(f, ".got", - BB_GOT_ENTRY_SIZE, - got_offset); - assert(myrelsec); - } - - ifile->got = myrelsec; - } -#endif - -#if defined(BB_USE_PLT_ENTRIES) - if (plt_offset) - ifile->plt = obj_create_alloced_section(f, ".plt", - BB_PLT_ENTRY_SIZE, - plt_offset); -#endif -#endif - return 1; -} - -static int arch_init_module(struct obj_file *f, struct new_module *mod) -{ - return 1; -} - - -/*======================================================================*/ - -/* Standard ELF hash function. */ -static inline unsigned long obj_elf_hash_n(const char *name, unsigned long n) -{ - unsigned long h = 0; - unsigned long g; - unsigned char ch; - - while (n > 0) { - ch = *name++; - h = (h << 4) + ch; - if ((g = (h & 0xf0000000)) != 0) { - h ^= g >> 24; - h &= ~g; - } - n--; - } - return h; -} - -static unsigned long obj_elf_hash(const char *name) -{ - return obj_elf_hash_n(name, strlen(name)); -} - -#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING -/* String comparison for non-co-versioned kernel and module. */ - -static int ncv_strcmp(const char *a, const char *b) -{ - size_t alen = strlen(a), blen = strlen(b); - - if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R') - return strncmp(a, b, alen); - else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R') - return strncmp(a, b, blen); - else - return strcmp(a, b); -} - -/* String hashing for non-co-versioned kernel and module. Here - we are simply forced to drop the crc from the hash. */ - -static unsigned long ncv_symbol_hash(const char *str) -{ - size_t len = strlen(str); - if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R') - len -= 10; - return obj_elf_hash_n(str, len); -} - -static void -obj_set_symbol_compare(struct obj_file *f, - int (*cmp) (const char *, const char *), - unsigned long (*hash) (const char *)) -{ - if (cmp) - f->symbol_cmp = cmp; - if (hash) { - struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next; - int i; - - f->symbol_hash = hash; - - memcpy(tmptab, f->symtab, sizeof(tmptab)); - memset(f->symtab, 0, sizeof(f->symtab)); - - for (i = 0; i < HASH_BUCKETS; ++i) - for (sym = tmptab[i]; sym; sym = next) { - unsigned long h = hash(sym->name) % HASH_BUCKETS; - next = sym->next; - sym->next = f->symtab[h]; - f->symtab[h] = sym; - } - } -} - -#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ - -static struct obj_symbol * -obj_add_symbol(struct obj_file *f, const char *name, - unsigned long symidx, int info, - int secidx, ElfW(Addr) value, - unsigned long size) -{ - struct obj_symbol *sym; - unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; - int n_type = ELFW(ST_TYPE) (info); - int n_binding = ELFW(ST_BIND) (info); - - for (sym = f->symtab[hash]; sym; sym = sym->next) - if (f->symbol_cmp(sym->name, name) == 0) { - int o_secidx = sym->secidx; - int o_info = sym->info; - int o_type = ELFW(ST_TYPE) (o_info); - int o_binding = ELFW(ST_BIND) (o_info); - - /* A redefinition! Is it legal? */ - - if (secidx == SHN_UNDEF) - return sym; - else if (o_secidx == SHN_UNDEF) - goto found; - else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) { - /* Cope with local and global symbols of the same name - in the same object file, as might have been created - by ld -r. The only reason locals are now seen at this - level at all is so that we can do semi-sensible things - with parameters. */ - - struct obj_symbol *nsym, **p; - - nsym = arch_new_symbol(); - nsym->next = sym->next; - nsym->ksymidx = -1; - - /* Excise the old (local) symbol from the hash chain. */ - for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next) - continue; - *p = sym = nsym; - goto found; - } else if (n_binding == STB_LOCAL) { - /* Another symbol of the same name has already been defined. - Just add this to the local table. */ - sym = arch_new_symbol(); - sym->next = NULL; - sym->ksymidx = -1; - f->local_symtab[symidx] = sym; - goto found; - } else if (n_binding == STB_WEAK) - return sym; - else if (o_binding == STB_WEAK) - goto found; - /* Don't unify COMMON symbols with object types the programmer - doesn't expect. */ - else if (secidx == SHN_COMMON - && (o_type == STT_NOTYPE || o_type == STT_OBJECT)) - return sym; - else if (o_secidx == SHN_COMMON - && (n_type == STT_NOTYPE || n_type == STT_OBJECT)) - goto found; - else { - /* Don't report an error if the symbol is coming from - the kernel or some external module. */ - if (secidx <= SHN_HIRESERVE) - error_msg("%s multiply defined", name); - return sym; - } - } - - /* Completely new symbol. */ - sym = arch_new_symbol(); - sym->next = f->symtab[hash]; - f->symtab[hash] = sym; - sym->ksymidx = -1; - - if (ELFW(ST_BIND)(info) == STB_LOCAL && symidx != -1) { - if (symidx >= f->local_symtab_size) - error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld", - name, (long) symidx, (long) f->local_symtab_size); - else - f->local_symtab[symidx] = sym; - } - - found: - sym->name = name; - sym->value = value; - sym->size = size; - sym->secidx = secidx; - sym->info = info; - - return sym; -} - -static struct obj_symbol * -obj_find_symbol(struct obj_file *f, const char *name) -{ - struct obj_symbol *sym; - unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; - - for (sym = f->symtab[hash]; sym; sym = sym->next) - if (f->symbol_cmp(sym->name, name) == 0) - return sym; - - return NULL; -} - -static ElfW(Addr) - obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym) -{ - if (sym) { - if (sym->secidx >= SHN_LORESERVE) - return sym->value; - - return sym->value + f->sections[sym->secidx]->header.sh_addr; - } else { - /* As a special case, a NULL sym has value zero. */ - return 0; - } -} - -static struct obj_section *obj_find_section(struct obj_file *f, const char *name) -{ - int i, n = f->header.e_shnum; - - for (i = 0; i < n; ++i) - if (strcmp(f->sections[i]->name, name) == 0) - return f->sections[i]; - - return NULL; -} - -static int obj_load_order_prio(struct obj_section *a) -{ - unsigned long af, ac; - - af = a->header.sh_flags; - - ac = 0; - if (a->name[0] != '.' || strlen(a->name) != 10 || - strcmp(a->name + 5, ".init")) - ac |= 32; - if (af & SHF_ALLOC) - ac |= 16; - if (!(af & SHF_WRITE)) - ac |= 8; - if (af & SHF_EXECINSTR) - ac |= 4; - if (a->header.sh_type != SHT_NOBITS) - ac |= 2; - - return ac; -} - -static void -obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec) -{ - struct obj_section **p; - int prio = obj_load_order_prio(sec); - for (p = f->load_order_search_start; *p; p = &(*p)->load_next) - if (obj_load_order_prio(*p) < prio) - break; - sec->load_next = *p; - *p = sec; -} - -static struct obj_section *obj_create_alloced_section(struct obj_file *f, - const char *name, - unsigned long align, - unsigned long size) -{ - int newidx = f->header.e_shnum++; - struct obj_section *sec; - - f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec)); - f->sections[newidx] = sec = arch_new_section(); - - memset(sec, 0, sizeof(*sec)); - sec->header.sh_type = SHT_PROGBITS; - sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; - sec->header.sh_size = size; - sec->header.sh_addralign = align; - sec->name = name; - sec->idx = newidx; - if (size) - sec->contents = xmalloc(size); - - obj_insert_section_load_order(f, sec); - - return sec; -} - -static struct obj_section *obj_create_alloced_section_first(struct obj_file *f, - const char *name, - unsigned long align, - unsigned long size) -{ - int newidx = f->header.e_shnum++; - struct obj_section *sec; - - f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec)); - f->sections[newidx] = sec = arch_new_section(); - - memset(sec, 0, sizeof(*sec)); - sec->header.sh_type = SHT_PROGBITS; - sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; - sec->header.sh_size = size; - sec->header.sh_addralign = align; - sec->name = name; - sec->idx = newidx; - if (size) - sec->contents = xmalloc(size); - - sec->load_next = f->load_order; - f->load_order = sec; - if (f->load_order_search_start == &f->load_order) - f->load_order_search_start = &sec->load_next; - - return sec; -} - -static void *obj_extend_section(struct obj_section *sec, unsigned long more) -{ - unsigned long oldsize = sec->header.sh_size; - if (more) { - sec->contents = xrealloc(sec->contents, sec->header.sh_size += more); - } - return sec->contents + oldsize; -} - - -/* Conditionally add the symbols from the given symbol set to the - new module. */ - -static int -add_symbols_from( - struct obj_file *f, - int idx, struct new_module_symbol *syms, size_t nsyms) -{ - struct new_module_symbol *s; - size_t i; - int used = 0; - - for (i = 0, s = syms; i < nsyms; ++i, ++s) { - - /* Only add symbols that are already marked external. If we - override locals we may cause problems for argument initialization. - We will also create a false dependency on the module. */ - struct obj_symbol *sym; - - sym = obj_find_symbol(f, (char *) s->name); - if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) { - sym = obj_add_symbol(f, (char *) s->name, -1, - ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), - idx, s->value, 0); - /* Did our symbol just get installed? If so, mark the - module as "used". */ - if (sym->secidx == idx) - used = 1; - } - } - - return used; -} - -static void add_kernel_symbols(struct obj_file *f) -{ - struct external_module *m; - int i, nused = 0; - - /* Add module symbols first. */ - - for (i = 0, m = ext_modules; i < n_ext_modules; ++i, ++m) - if (m->nsyms - && add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms, - m->nsyms)) m->used = 1, ++nused; - - n_ext_modules_used = nused; - - /* And finally the symbols from the kernel proper. */ - - if (nksyms) - add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms); -} - -static char *get_modinfo_value(struct obj_file *f, const char *key) -{ - struct obj_section *sec; - char *p, *v, *n, *ep; - size_t klen = strlen(key); - - sec = obj_find_section(f, ".modinfo"); - if (sec == NULL) - return NULL; - p = sec->contents; - ep = p + sec->header.sh_size; - while (p < ep) { - v = strchr(p, '='); - n = strchr(p, '\0'); - if (v) { - if (p + klen == v && strncmp(p, key, klen) == 0) - return v + 1; - } else { - if (p + klen == n && strcmp(p, key) == 0) - return n; - } - p = n + 1; - } - - return NULL; -} - - -/*======================================================================*/ -/* Functions relating to module loading in pre 2.1 kernels. */ - -static int -old_process_module_arguments(struct obj_file *f, int argc, char **argv) -{ - while (argc > 0) { - char *p, *q; - struct obj_symbol *sym; - int *loc; - - p = *argv; - if ((q = strchr(p, '=')) == NULL) { - argc--; - continue; - } - *q++ = '\0'; - - sym = obj_find_symbol(f, p); - - /* Also check that the parameter was not resolved from the kernel. */ - if (sym == NULL || sym->secidx > SHN_HIRESERVE) { - error_msg("symbol for parameter %s not found", p); - return 0; - } - - loc = (int *) (f->sections[sym->secidx]->contents + sym->value); - - /* Do C quoting if we begin with a ". */ - if (*q == '"') { - char *r, *str; - - str = alloca(strlen(q)); - for (r = str, q++; *q != '"'; ++q, ++r) { - if (*q == '\0') { - error_msg("improperly terminated string argument for %s", p); - return 0; - } else if (*q == '\\') - switch (*++q) { - case 'a': - *r = '\a'; - break; - case 'b': - *r = '\b'; - break; - case 'e': - *r = '\033'; - break; - case 'f': - *r = '\f'; - break; - case 'n': - *r = '\n'; - break; - case 'r': - *r = '\r'; - break; - case 't': - *r = '\t'; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - { - int c = *q - '0'; - if (q[1] >= '0' && q[1] <= '7') { - c = (c * 8) + *++q - '0'; - if (q[1] >= '0' && q[1] <= '7') - c = (c * 8) + *++q - '0'; - } - *r = c; - } - break; - - default: - *r = *q; - break; - } else - *r = *q; - } - *r = '\0'; - obj_string_patch(f, sym->secidx, sym->value, str); - } else if (*q >= '0' && *q <= '9') { - do - *loc++ = strtoul(q, &q, 0); - while (*q++ == ','); - } else { - char *contents = f->sections[sym->secidx]->contents; - char *myloc = contents + sym->value; - char *r; /* To search for commas */ - - /* Break the string with comas */ - while ((r = strchr(q, ',')) != (char *) NULL) { - *r++ = '\0'; - obj_string_patch(f, sym->secidx, myloc - contents, q); - myloc += sizeof(char *); - q = r; - } - - /* last part */ - obj_string_patch(f, sym->secidx, myloc - contents, q); - } - - argc--, argv++; - } - - return 1; -} - -#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING -static int old_is_module_checksummed(struct obj_file *f) -{ - return obj_find_symbol(f, "Using_Versions") != NULL; -} -/* Get the module's kernel version in the canonical integer form. */ - -static int -old_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) -{ - struct obj_symbol *sym; - char *p, *q; - int a, b, c; - - sym = obj_find_symbol(f, "kernel_version"); - if (sym == NULL) - return -1; - - p = f->sections[sym->secidx]->contents + sym->value; - strncpy(str, p, STRVERSIONLEN); - - a = strtoul(p, &p, 10); - if (*p != '.') - return -1; - b = strtoul(p + 1, &p, 10); - if (*p != '.') - return -1; - c = strtoul(p + 1, &q, 10); - if (p + 1 == q) - return -1; - - return a << 16 | b << 8 | c; -} - -#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ - -#ifdef BB_FEATURE_OLD_MODULE_INTERFACE - -/* Fetch all the symbols and divvy them up as appropriate for the modules. */ - -static int old_get_kernel_symbols(const char *m_name) -{ - struct old_kernel_sym *ks, *k; - struct new_module_symbol *s; - struct external_module *mod; - int nks, nms, nmod, i; - - nks = get_kernel_syms(NULL); - if (nks <= 0) { - if (nks) - perror_msg("get_kernel_syms: %s", m_name); - else - error_msg("No kernel symbols"); - return 0; - } - - ks = k = xmalloc(nks * sizeof(*ks)); - - if (get_kernel_syms(ks) != nks) { - perror("inconsistency with get_kernel_syms -- is someone else " - "playing with modules?"); - free(ks); - return 0; - } - - /* Collect the module information. */ - - mod = NULL; - nmod = -1; - - while (k->name[0] == '#' && k->name[1]) { - struct old_kernel_sym *k2; - - /* Find out how many symbols this module has. */ - for (k2 = k + 1; k2->name[0] != '#'; ++k2) - continue; - nms = k2 - k - 1; - - mod = xrealloc(mod, (++nmod + 1) * sizeof(*mod)); - mod[nmod].name = k->name + 1; - mod[nmod].addr = k->value; - mod[nmod].used = 0; - mod[nmod].nsyms = nms; - mod[nmod].syms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL); - - for (i = 0, ++k; i < nms; ++i, ++s, ++k) { - s->name = (unsigned long) k->name; - s->value = k->value; - } - - k = k2; - } - - ext_modules = mod; - n_ext_modules = nmod + 1; - - /* Now collect the symbols for the kernel proper. */ - - if (k->name[0] == '#') - ++k; - - nksyms = nms = nks - (k - ks); - ksyms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL); - - for (i = 0; i < nms; ++i, ++s, ++k) { - s->name = (unsigned long) k->name; - s->value = k->value; - } - - return 1; -} - -/* Return the kernel symbol checksum version, or zero if not used. */ - -static int old_is_kernel_checksummed(void) -{ - /* Using_Versions is the first symbol. */ - if (nksyms > 0 - && strcmp((char *) ksyms[0].name, - "Using_Versions") == 0) return ksyms[0].value; - else - return 0; -} - - -static int old_create_mod_use_count(struct obj_file *f) -{ - struct obj_section *sec; - - sec = obj_create_alloced_section_first(f, ".moduse", sizeof(long), - sizeof(long)); - - obj_add_symbol(f, "mod_use_count_", -1, - ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0, - sizeof(long)); - - return 1; -} - -static int -old_init_module(const char *m_name, struct obj_file *f, - unsigned long m_size) -{ - char *image; - struct old_mod_routines routines; - struct old_symbol_table *symtab; - int ret; - - /* Create the symbol table */ - { - int nsyms = 0, strsize = 0, total; - - /* Size things first... */ - if (flag_export) { - int i; - for (i = 0; i < HASH_BUCKETS; ++i) { - struct obj_symbol *sym; - for (sym = f->symtab[i]; sym; sym = sym->next) - if (ELFW(ST_BIND) (sym->info) != STB_LOCAL - && sym->secidx <= SHN_HIRESERVE) - { - sym->ksymidx = nsyms++; - strsize += strlen(sym->name) + 1; - } - } - } - - total = (sizeof(struct old_symbol_table) - + nsyms * sizeof(struct old_module_symbol) - + n_ext_modules_used * sizeof(struct old_module_ref) - + strsize); - symtab = xmalloc(total); - symtab->size = total; - symtab->n_symbols = nsyms; - symtab->n_refs = n_ext_modules_used; - - if (flag_export && nsyms) { - struct old_module_symbol *ksym; - char *str; - int i; - - ksym = symtab->symbol; - str = ((char *) ksym + nsyms * sizeof(struct old_module_symbol) - + n_ext_modules_used * sizeof(struct old_module_ref)); - - for (i = 0; i < HASH_BUCKETS; ++i) { - struct obj_symbol *sym; - for (sym = f->symtab[i]; sym; sym = sym->next) - if (sym->ksymidx >= 0) { - ksym->addr = obj_symbol_final_value(f, sym); - ksym->name = - (unsigned long) str - (unsigned long) symtab; - - strcpy(str, sym->name); - str += strlen(sym->name) + 1; - ksym++; - } - } - } - - if (n_ext_modules_used) { - struct old_module_ref *ref; - int i; - - ref = (struct old_module_ref *) - ((char *) symtab->symbol + nsyms * sizeof(struct old_module_symbol)); - - for (i = 0; i < n_ext_modules; ++i) - if (ext_modules[i].used) - ref++->module = ext_modules[i].addr; - } - } - - /* Fill in routines. */ - - routines.init = - obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); - routines.cleanup = - obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module")); - - /* Whew! All of the initialization is complete. Collect the final - module image and give it to the kernel. */ - - image = xmalloc(m_size); - obj_create_image(f, image); - - /* image holds the complete relocated module, accounting correctly for - mod_use_count. However the old module kernel support assume that - it is receiving something which does not contain mod_use_count. */ - ret = old_sys_init_module(m_name, image + sizeof(long), - m_size | (flag_autoclean ? OLD_MOD_AUTOCLEAN - : 0), &routines, symtab); - if (ret) - perror_msg("init_module: %s", m_name); - - free(image); - free(symtab); - - return ret == 0; -} - -#else - -#define old_create_mod_use_count(x) TRUE -#define old_init_module(x, y, z) TRUE - -#endif /* BB_FEATURE_OLD_MODULE_INTERFACE */ - - - -/*======================================================================*/ -/* Functions relating to module loading after 2.1.18. */ - -static int -new_process_module_arguments(struct obj_file *f, int argc, char **argv) -{ - while (argc > 0) { - char *p, *q, *key; - struct obj_symbol *sym; - char *contents, *loc; - int min, max, n; - - p = *argv; - if ((q = strchr(p, '=')) == NULL) { - argc--; - continue; - } - - key = alloca(q - p + 6); - memcpy(key, "parm_", 5); - memcpy(key + 5, p, q - p); - key[q - p + 5] = 0; - - p = get_modinfo_value(f, key); - key += 5; - if (p == NULL) { - error_msg("invalid parameter %s", key); - return 0; - } - - sym = obj_find_symbol(f, key); - - /* Also check that the parameter was not resolved from the kernel. */ - if (sym == NULL || sym->secidx > SHN_HIRESERVE) { - error_msg("symbol for parameter %s not found", key); - return 0; - } - - if (isdigit(*p)) { - min = strtoul(p, &p, 10); - if (*p == '-') - max = strtoul(p + 1, &p, 10); - else - max = min; - } else - min = max = 1; - - contents = f->sections[sym->secidx]->contents; - loc = contents + sym->value; - n = (*++q != '\0'); - - while (1) { - if ((*p == 's') || (*p == 'c')) { - char *str; - - /* Do C quoting if we begin with a ", else slurp the lot. */ - if (*q == '"') { - char *r; - - str = alloca(strlen(q)); - for (r = str, q++; *q != '"'; ++q, ++r) { - if (*q == '\0') { - error_msg("improperly terminated string argument for %s", - key); - return 0; - } else if (*q == '\\') - switch (*++q) { - case 'a': - *r = '\a'; - break; - case 'b': - *r = '\b'; - break; - case 'e': - *r = '\033'; - break; - case 'f': - *r = '\f'; - break; - case 'n': - *r = '\n'; - break; - case 'r': - *r = '\r'; - break; - case 't': - *r = '\t'; - break; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - { - int c = *q - '0'; - if (q[1] >= '0' && q[1] <= '7') { - c = (c * 8) + *++q - '0'; - if (q[1] >= '0' && q[1] <= '7') - c = (c * 8) + *++q - '0'; - } - *r = c; - } - break; - - default: - *r = *q; - break; - } else - *r = *q; - } - *r = '\0'; - ++q; - } else { - char *r; - - /* In this case, the string is not quoted. We will break - it using the coma (like for ints). If the user wants to - include comas in a string, he just has to quote it */ - - /* Search the next coma */ - r = strchr(q, ','); - - /* Found ? */ - if (r != (char *) NULL) { - /* Recopy the current field */ - str = alloca(r - q + 1); - memcpy(str, q, r - q); - - /* I don't know if it is usefull, as the previous case - doesn't null terminate the string ??? */ - str[r - q] = '\0'; - - /* Keep next fields */ - q = r; - } else { - /* last string */ - str = q; - q = ""; - } - } - - if (*p == 's') { - /* Normal string */ - obj_string_patch(f, sym->secidx, loc - contents, str); - loc += tgt_sizeof_char_p; - } else { - /* Array of chars (in fact, matrix !) */ - unsigned long charssize; /* size of each member */ - - /* Get the size of each member */ - /* Probably we should do that outside the loop ? */ - if (!isdigit(*(p + 1))) { - error_msg("parameter type 'c' for %s must be followed by" - " the maximum size", key); - return 0; - } - charssize = strtoul(p + 1, (char **) NULL, 10); - - /* Check length */ - if (strlen(str) >= charssize) { - error_msg("string too long for %s (max %ld)", key, - charssize - 1); - return 0; - } - - /* Copy to location */ - strcpy((char *) loc, str); - loc += charssize; - } - } else { - long v = strtoul(q, &q, 0); - switch (*p) { - case 'b': - *loc++ = v; - break; - case 'h': - *(short *) loc = v; - loc += tgt_sizeof_short; - break; - case 'i': - *(int *) loc = v; - loc += tgt_sizeof_int; - break; - case 'l': - *(long *) loc = v; - loc += tgt_sizeof_long; - break; - - default: - error_msg("unknown parameter type '%c' for %s", *p, key); - return 0; - } - } - - retry_end_of_value: - switch (*q) { - case '\0': - goto end_of_arg; - - case ' ': - case '\t': - case '\n': - case '\r': - ++q; - goto retry_end_of_value; - - case ',': - if (++n > max) { - error_msg("too many values for %s (max %d)", key, max); - return 0; - } - ++q; - break; - - default: - error_msg("invalid argument syntax for %s", key); - return 0; - } - } - - end_of_arg: - if (n < min) { - error_msg("too few values for %s (min %d)", key, min); - return 0; - } - - argc--, argv++; - } - - return 1; -} - -#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING -static int new_is_module_checksummed(struct obj_file *f) -{ - const char *p = get_modinfo_value(f, "using_checksums"); - if (p) - return atoi(p); - else - return 0; -} - -/* Get the module's kernel version in the canonical integer form. */ - -static int -new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) -{ - char *p, *q; - int a, b, c; - - p = get_modinfo_value(f, "kernel_version"); - if (p == NULL) - return -1; - strncpy(str, p, STRVERSIONLEN); - - a = strtoul(p, &p, 10); - if (*p != '.') - return -1; - b = strtoul(p + 1, &p, 10); - if (*p != '.') - return -1; - c = strtoul(p + 1, &q, 10); - if (p + 1 == q) - return -1; - - return a << 16 | b << 8 | c; -} - -#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ - - -#ifdef BB_FEATURE_NEW_MODULE_INTERFACE - -/* Fetch the loaded modules, and all currently exported symbols. */ - -static int new_get_kernel_symbols(void) -{ - char *module_names, *mn; - struct external_module *modules, *m; - struct new_module_symbol *syms, *s; - size_t ret, bufsize, nmod, nsyms, i, j; - - /* Collect the loaded modules. */ - - module_names = xmalloc(bufsize = 256); - retry_modules_load: - if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) { - if (errno == ENOSPC && bufsize < ret) { - module_names = xrealloc(module_names, bufsize = ret); - goto retry_modules_load; - } - perror_msg("QM_MODULES"); - return 0; - } - - n_ext_modules = nmod = ret; - - /* Collect the modules' symbols. */ - - if (nmod){ - ext_modules = modules = xmalloc(nmod * sizeof(*modules)); - memset(modules, 0, nmod * sizeof(*modules)); - for (i = 0, mn = module_names, m = modules; - i < nmod; ++i, ++m, mn += strlen(mn) + 1) { - struct new_module_info info; - - if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) { - if (errno == ENOENT) { - /* The module was removed out from underneath us. */ - continue; - } - perror_msg("query_module: QM_INFO: %s", mn); - return 0; - } - - syms = xmalloc(bufsize = 1024); - retry_mod_sym_load: - if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) { - switch (errno) { - case ENOSPC: - syms = xrealloc(syms, bufsize = ret); - goto retry_mod_sym_load; - case ENOENT: - /* The module was removed out from underneath us. */ - continue; - default: - perror_msg("query_module: QM_SYMBOLS: %s", mn); - return 0; - } - } - nsyms = ret; - - m->name = mn; - m->addr = info.addr; - m->nsyms = nsyms; - m->syms = syms; - - for (j = 0, s = syms; j < nsyms; ++j, ++s) { - s->name += (unsigned long) syms; - } - } - } - - /* Collect the kernel's symbols. */ - - syms = xmalloc(bufsize = 16 * 1024); - retry_kern_sym_load: - if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) { - if (errno == ENOSPC && bufsize < ret) { - syms = xrealloc(syms, bufsize = ret); - goto retry_kern_sym_load; - } - perror_msg("kernel: QM_SYMBOLS"); - return 0; - } - nksyms = nsyms = ret; - ksyms = syms; - - for (j = 0, s = syms; j < nsyms; ++j, ++s) { - s->name += (unsigned long) syms; - } - return 1; -} - - -/* Return the kernel symbol checksum version, or zero if not used. */ - -static int new_is_kernel_checksummed(void) -{ - struct new_module_symbol *s; - size_t i; - - /* Using_Versions is not the first symbol, but it should be in there. */ - - for (i = 0, s = ksyms; i < nksyms; ++i, ++s) - if (strcmp((char *) s->name, "Using_Versions") == 0) - return s->value; - - return 0; -} - - -static int new_create_this_module(struct obj_file *f, const char *m_name) -{ - struct obj_section *sec; - - sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long, - sizeof(struct new_module)); - memset(sec->contents, 0, sizeof(struct new_module)); - - obj_add_symbol(f, "__this_module", -1, - ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0, - sizeof(struct new_module)); - - obj_string_patch(f, sec->idx, offsetof(struct new_module, name), - m_name); - - return 1; -} - - -static int new_create_module_ksymtab(struct obj_file *f) -{ - struct obj_section *sec; - int i; - - /* We must always add the module references. */ - - if (n_ext_modules_used) { - struct new_module_ref *dep; - struct obj_symbol *tm; - - sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p, - (sizeof(struct new_module_ref) - * n_ext_modules_used)); - if (!sec) - return 0; - - tm = obj_find_symbol(f, "__this_module"); - dep = (struct new_module_ref *) sec->contents; - for (i = 0; i < n_ext_modules; ++i) - if (ext_modules[i].used) { - dep->dep = ext_modules[i].addr; - obj_symbol_patch(f, sec->idx, - (char *) &dep->ref - sec->contents, tm); - dep->next_ref = 0; - ++dep; - } - } - - if (flag_export && !obj_find_section(f, "__ksymtab")) { - size_t nsyms; - int *loaded; - - sec = - obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, - 0); - - /* We don't want to export symbols residing in sections that - aren't loaded. There are a number of these created so that - we make sure certain module options don't appear twice. */ - - loaded = alloca(sizeof(int) * (i = f->header.e_shnum)); - while (--i >= 0) - loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0; - - for (nsyms = i = 0; i < HASH_BUCKETS; ++i) { - struct obj_symbol *sym; - for (sym = f->symtab[i]; sym; sym = sym->next) - if (ELFW(ST_BIND) (sym->info) != STB_LOCAL - && sym->secidx <= SHN_HIRESERVE - && (sym->secidx >= SHN_LORESERVE - || loaded[sym->secidx])) { - ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p; - - obj_symbol_patch(f, sec->idx, ofs, sym); - obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, - sym->name); - - nsyms++; - } - } - - obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p); - } - - return 1; -} - - -static int -new_init_module(const char *m_name, struct obj_file *f, - unsigned long m_size) -{ - struct new_module *module; - struct obj_section *sec; - void *image; - int ret; - tgt_long m_addr; - - sec = obj_find_section(f, ".this"); - if (!sec || !sec->contents) { - perror_msg_and_die("corrupt module %s?",m_name); - } - module = (struct new_module *) sec->contents; - m_addr = sec->header.sh_addr; - - module->size_of_struct = sizeof(*module); - module->size = m_size; - module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0; - - sec = obj_find_section(f, "__ksymtab"); - if (sec && sec->header.sh_size) { - module->syms = sec->header.sh_addr; - module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p); - } - - if (n_ext_modules_used) { - sec = obj_find_section(f, ".kmodtab"); - module->deps = sec->header.sh_addr; - module->ndeps = n_ext_modules_used; - } - - module->init = - obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); - module->cleanup = - obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module")); - - sec = obj_find_section(f, "__ex_table"); - if (sec) { - module->ex_table_start = sec->header.sh_addr; - module->ex_table_end = sec->header.sh_addr + sec->header.sh_size; - } - - sec = obj_find_section(f, ".text.init"); - if (sec) { - module->runsize = sec->header.sh_addr - m_addr; - } - sec = obj_find_section(f, ".data.init"); - if (sec) { - if (!module->runsize || - module->runsize > sec->header.sh_addr - m_addr) - module->runsize = sec->header.sh_addr - m_addr; - } - sec = obj_find_section(f, ARCHDATA_SEC_NAME); - if (sec && sec->header.sh_size) { - module->archdata_start = (void*)sec->header.sh_addr; - module->archdata_end = module->archdata_start + sec->header.sh_size; - } - sec = obj_find_section(f, KALLSYMS_SEC_NAME); - if (sec && sec->header.sh_size) { - module->kallsyms_start = (void*)sec->header.sh_addr; - module->kallsyms_end = module->kallsyms_start + sec->header.sh_size; - } - - if (!arch_init_module(f, module)) - return 0; - - /* Whew! All of the initialization is complete. Collect the final - module image and give it to the kernel. */ - - image = xmalloc(m_size); - obj_create_image(f, image); - - ret = new_sys_init_module(m_name, (struct new_module *) image); - if (ret) - perror_msg("init_module: %s", m_name); - - free(image); - - return ret == 0; -} - -#else - -#define new_init_module(x, y, z) TRUE -#define new_create_this_module(x, y) 0 -#define new_create_module_ksymtab(x) -#define query_module(v, w, x, y, z) -1 - -#endif /* BB_FEATURE_NEW_MODULE_INTERFACE */ - - -/*======================================================================*/ - -static int -obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, - const char *string) -{ - struct obj_string_patch *p; - struct obj_section *strsec; - size_t len = strlen(string) + 1; - char *loc; - - p = xmalloc(sizeof(*p)); - p->next = f->string_patches; - p->reloc_secidx = secidx; - p->reloc_offset = offset; - f->string_patches = p; - - strsec = obj_find_section(f, ".kstrtab"); - if (strsec == NULL) { - strsec = obj_create_alloced_section(f, ".kstrtab", 1, len); - p->string_offset = 0; - loc = strsec->contents; - } else { - p->string_offset = strsec->header.sh_size; - loc = obj_extend_section(strsec, len); - } - memcpy(loc, string, len); - - return 1; -} - -static int -obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, - struct obj_symbol *sym) -{ - struct obj_symbol_patch *p; - - p = xmalloc(sizeof(*p)); - p->next = f->symbol_patches; - p->reloc_secidx = secidx; - p->reloc_offset = offset; - p->sym = sym; - f->symbol_patches = p; - - return 1; -} - -static int obj_check_undefineds(struct obj_file *f) -{ - unsigned long i; - int ret = 1; - - for (i = 0; i < HASH_BUCKETS; ++i) { - struct obj_symbol *sym; - for (sym = f->symtab[i]; sym; sym = sym->next) - if (sym->secidx == SHN_UNDEF) { - if (ELFW(ST_BIND) (sym->info) == STB_WEAK) { - sym->secidx = SHN_ABS; - sym->value = 0; - } else { - error_msg("unresolved symbol %s", sym->name); - ret = 0; - } - } - } - - return ret; -} - -static void obj_allocate_commons(struct obj_file *f) -{ - struct common_entry { - struct common_entry *next; - struct obj_symbol *sym; - } *common_head = NULL; - - unsigned long i; - - for (i = 0; i < HASH_BUCKETS; ++i) { - struct obj_symbol *sym; - for (sym = f->symtab[i]; sym; sym = sym->next) - if (sym->secidx == SHN_COMMON) { - /* Collect all COMMON symbols and sort them by size so as to - minimize space wasted by alignment requirements. */ - { - struct common_entry **p, *n; - for (p = &common_head; *p; p = &(*p)->next) - if (sym->size <= (*p)->sym->size) - break; - - n = alloca(sizeof(*n)); - n->next = *p; - n->sym = sym; - *p = n; - } - } - } - - for (i = 1; i < f->local_symtab_size; ++i) { - struct obj_symbol *sym = f->local_symtab[i]; - if (sym && sym->secidx == SHN_COMMON) { - struct common_entry **p, *n; - for (p = &common_head; *p; p = &(*p)->next) - if (sym == (*p)->sym) - break; - else if (sym->size < (*p)->sym->size) { - n = alloca(sizeof(*n)); - n->next = *p; - n->sym = sym; - *p = n; - break; - } - } - } - - if (common_head) { - /* Find the bss section. */ - for (i = 0; i < f->header.e_shnum; ++i) - if (f->sections[i]->header.sh_type == SHT_NOBITS) - break; - - /* If for some reason there hadn't been one, create one. */ - if (i == f->header.e_shnum) { - struct obj_section *sec; - - f->sections = xrealloc(f->sections, (i + 1) * sizeof(sec)); - f->sections[i] = sec = arch_new_section(); - f->header.e_shnum = i + 1; - - memset(sec, 0, sizeof(*sec)); - sec->header.sh_type = SHT_PROGBITS; - sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; - sec->name = ".bss"; - sec->idx = i; - } - - /* Allocate the COMMONS. */ - { - ElfW(Addr) bss_size = f->sections[i]->header.sh_size; - ElfW(Addr) max_align = f->sections[i]->header.sh_addralign; - struct common_entry *c; - - for (c = common_head; c; c = c->next) { - ElfW(Addr) align = c->sym->value; - - if (align > max_align) - max_align = align; - if (bss_size & (align - 1)) - bss_size = (bss_size | (align - 1)) + 1; - - c->sym->secidx = i; - c->sym->value = bss_size; - - bss_size += c->sym->size; - } - - f->sections[i]->header.sh_size = bss_size; - f->sections[i]->header.sh_addralign = max_align; - } - } - - /* For the sake of patch relocation and parameter initialization, - allocate zeroed data for NOBITS sections now. Note that after - this we cannot assume NOBITS are really empty. */ - for (i = 0; i < f->header.e_shnum; ++i) { - struct obj_section *s = f->sections[i]; - if (s->header.sh_type == SHT_NOBITS) { - if (s->header.sh_size != 0) - s->contents = memset(xmalloc(s->header.sh_size), - 0, s->header.sh_size); - else - s->contents = NULL; - - s->header.sh_type = SHT_PROGBITS; - } - } -} - -static unsigned long obj_load_size(struct obj_file *f) -{ - unsigned long dot = 0; - struct obj_section *sec; - - /* Finalize the positions of the sections relative to one another. */ - - for (sec = f->load_order; sec; sec = sec->load_next) { - ElfW(Addr) align; - - align = sec->header.sh_addralign; - if (align && (dot & (align - 1))) - dot = (dot | (align - 1)) + 1; - - sec->header.sh_addr = dot; - dot += sec->header.sh_size; - } - - return dot; -} - -static int obj_relocate(struct obj_file *f, ElfW(Addr) base) -{ - int i, n = f->header.e_shnum; - int ret = 1; - - /* Finalize the addresses of the sections. */ - - f->baseaddr = base; - for (i = 0; i < n; ++i) - f->sections[i]->header.sh_addr += base; - - /* And iterate over all of the relocations. */ - - for (i = 0; i < n; ++i) { - struct obj_section *relsec, *symsec, *targsec, *strsec; - ElfW(RelM) * rel, *relend; - ElfW(Sym) * symtab; - const char *strtab; - - relsec = f->sections[i]; - if (relsec->header.sh_type != SHT_RELM) - continue; - - symsec = f->sections[relsec->header.sh_link]; - targsec = f->sections[relsec->header.sh_info]; - strsec = f->sections[symsec->header.sh_link]; - - rel = (ElfW(RelM) *) relsec->contents; - relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM))); - symtab = (ElfW(Sym) *) symsec->contents; - strtab = (const char *) strsec->contents; - - for (; rel < relend; ++rel) { - ElfW(Addr) value = 0; - struct obj_symbol *intsym = NULL; - unsigned long symndx; - ElfW(Sym) * extsym = 0; - const char *errmsg; - - /* Attempt to find a value to use for this relocation. */ - - symndx = ELFW(R_SYM) (rel->r_info); - if (symndx) { - /* Note we've already checked for undefined symbols. */ - - extsym = &symtab[symndx]; - if (ELFW(ST_BIND) (extsym->st_info) == STB_LOCAL) { - /* Local symbols we look up in the local table to be sure - we get the one that is really intended. */ - intsym = f->local_symtab[symndx]; - } else { - /* Others we look up in the hash table. */ - const char *name; - if (extsym->st_name) - name = strtab + extsym->st_name; - else - name = f->sections[extsym->st_shndx]->name; - intsym = obj_find_symbol(f, name); - } - - value = obj_symbol_final_value(f, intsym); - intsym->referenced = 1; - } -#if SHT_RELM == SHT_RELA -#if defined(__alpha__) && defined(AXP_BROKEN_GAS) - /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9. */ - if (!extsym || !extsym->st_name || - ELFW(ST_BIND) (extsym->st_info) != STB_LOCAL) -#endif - value += rel->r_addend; -#endif - - /* Do it! */ - switch (arch_apply_relocation - (f, targsec, symsec, intsym, rel, value)) { - case obj_reloc_ok: - break; - - case obj_reloc_overflow: - errmsg = "Relocation overflow"; - goto bad_reloc; - case obj_reloc_dangerous: - errmsg = "Dangerous relocation"; - goto bad_reloc; - case obj_reloc_unhandled: - errmsg = "Unhandled relocation"; - bad_reloc: - if (extsym) { - error_msg("%s of type %ld for %s", errmsg, - (long) ELFW(R_TYPE) (rel->r_info), - strtab + extsym->st_name); - } else { - error_msg("%s of type %ld", errmsg, - (long) ELFW(R_TYPE) (rel->r_info)); - } - ret = 0; - break; - } - } - } - - /* Finally, take care of the patches. */ - - if (f->string_patches) { - struct obj_string_patch *p; - struct obj_section *strsec; - ElfW(Addr) strsec_base; - strsec = obj_find_section(f, ".kstrtab"); - strsec_base = strsec->header.sh_addr; - - for (p = f->string_patches; p; p = p->next) { - struct obj_section *targsec = f->sections[p->reloc_secidx]; - *(ElfW(Addr) *) (targsec->contents + p->reloc_offset) - = strsec_base + p->string_offset; - } - } - - if (f->symbol_patches) { - struct obj_symbol_patch *p; - - for (p = f->symbol_patches; p; p = p->next) { - struct obj_section *targsec = f->sections[p->reloc_secidx]; - *(ElfW(Addr) *) (targsec->contents + p->reloc_offset) - = obj_symbol_final_value(f, p->sym); - } - } - - return ret; -} - -static int obj_create_image(struct obj_file *f, char *image) -{ - struct obj_section *sec; - ElfW(Addr) base = f->baseaddr; - - for (sec = f->load_order; sec; sec = sec->load_next) { - char *secimg; - - if (sec->contents == 0 || sec->header.sh_size == 0) - continue; - - secimg = image + (sec->header.sh_addr - base); - - /* Note that we allocated data for NOBITS sections earlier. */ - memcpy(secimg, sec->contents, sec->header.sh_size); - } - - return 1; -} - -/*======================================================================*/ - -static struct obj_file *obj_load(FILE * fp, int loadprogbits) -{ - struct obj_file *f; - ElfW(Shdr) * section_headers; - int shnum, i; - char *shstrtab; - - /* Read the file header. */ - - f = arch_new_file(); - memset(f, 0, sizeof(*f)); - f->symbol_cmp = strcmp; - f->symbol_hash = obj_elf_hash; - f->load_order_search_start = &f->load_order; - - fseek(fp, 0, SEEK_SET); - if (fread(&f->header, sizeof(f->header), 1, fp) != 1) { - perror_msg("error reading ELF header"); - return NULL; - } - - if (f->header.e_ident[EI_MAG0] != ELFMAG0 - || f->header.e_ident[EI_MAG1] != ELFMAG1 - || f->header.e_ident[EI_MAG2] != ELFMAG2 - || f->header.e_ident[EI_MAG3] != ELFMAG3) { - error_msg("not an ELF file"); - return NULL; - } - if (f->header.e_ident[EI_CLASS] != ELFCLASSM - || f->header.e_ident[EI_DATA] != ELFDATAM - || f->header.e_ident[EI_VERSION] != EV_CURRENT - || !MATCH_MACHINE(f->header.e_machine)) { - error_msg("ELF file not for this architecture"); - return NULL; - } - if (f->header.e_type != ET_REL) { - error_msg("ELF file not a relocatable object"); - return NULL; - } - - /* Read the section headers. */ - - if (f->header.e_shentsize != sizeof(ElfW(Shdr))) { - error_msg("section header size mismatch: %lu != %lu", - (unsigned long) f->header.e_shentsize, - (unsigned long) sizeof(ElfW(Shdr))); - return NULL; - } - - shnum = f->header.e_shnum; - f->sections = xmalloc(sizeof(struct obj_section *) * shnum); - memset(f->sections, 0, sizeof(struct obj_section *) * shnum); - - section_headers = alloca(sizeof(ElfW(Shdr)) * shnum); - fseek(fp, f->header.e_shoff, SEEK_SET); - if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) { - perror_msg("error reading ELF section headers"); - return NULL; - } - - /* Read the section data. */ - - for (i = 0; i < shnum; ++i) { - struct obj_section *sec; - - f->sections[i] = sec = arch_new_section(); - memset(sec, 0, sizeof(*sec)); - - sec->header = section_headers[i]; - sec->idx = i; - - if(sec->header.sh_size) switch (sec->header.sh_type) { - case SHT_NULL: - case SHT_NOTE: - case SHT_NOBITS: - /* ignore */ - break; - - case SHT_PROGBITS: -#if LOADBITS - if (!loadprogbits) { - sec->contents = NULL; - break; - } -#endif - case SHT_SYMTAB: - case SHT_STRTAB: - case SHT_RELM: - if (sec->header.sh_size > 0) { - sec->contents = xmalloc(sec->header.sh_size); - fseek(fp, sec->header.sh_offset, SEEK_SET); - if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) { - perror_msg("error reading ELF section data"); - return NULL; - } - } else { - sec->contents = NULL; - } - break; - -#if SHT_RELM == SHT_REL - case SHT_RELA: - error_msg("RELA relocations not supported on this architecture"); - return NULL; -#else - case SHT_REL: - error_msg("REL relocations not supported on this architecture"); - return NULL; -#endif - - default: - if (sec->header.sh_type >= SHT_LOPROC) { - /* Assume processor specific section types are debug - info and can safely be ignored. If this is ever not - the case (Hello MIPS?), don't put ifdefs here but - create an arch_load_proc_section(). */ - break; - } - - error_msg("can't handle sections of type %ld", - (long) sec->header.sh_type); - return NULL; - } - } - - /* Do what sort of interpretation as needed by each section. */ - - shstrtab = f->sections[f->header.e_shstrndx]->contents; - - for (i = 0; i < shnum; ++i) { - struct obj_section *sec = f->sections[i]; - sec->name = shstrtab + sec->header.sh_name; - } - - for (i = 0; i < shnum; ++i) { - struct obj_section *sec = f->sections[i]; - - /* .modinfo should be contents only but gcc has no attribute for that. - * The kernel may have marked .modinfo as ALLOC, ignore this bit. - */ - if (strcmp(sec->name, ".modinfo") == 0) - sec->header.sh_flags &= ~SHF_ALLOC; - - if (sec->header.sh_flags & SHF_ALLOC) - obj_insert_section_load_order(f, sec); - - switch (sec->header.sh_type) { - case SHT_SYMTAB: - { - unsigned long nsym, j; - char *strtab; - ElfW(Sym) * sym; - - if (sec->header.sh_entsize != sizeof(ElfW(Sym))) { - error_msg("symbol size mismatch: %lu != %lu", - (unsigned long) sec->header.sh_entsize, - (unsigned long) sizeof(ElfW(Sym))); - return NULL; - } - - nsym = sec->header.sh_size / sizeof(ElfW(Sym)); - strtab = f->sections[sec->header.sh_link]->contents; - sym = (ElfW(Sym) *) sec->contents; - - /* Allocate space for a table of local symbols. */ - j = f->local_symtab_size = sec->header.sh_info; - f->local_symtab = xcalloc(j, sizeof(struct obj_symbol *)); - - /* Insert all symbols into the hash table. */ - for (j = 1, ++sym; j < nsym; ++j, ++sym) { - const char *name; - if (sym->st_name) - name = strtab + sym->st_name; - else - name = f->sections[sym->st_shndx]->name; - - obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx, - sym->st_value, sym->st_size); - } - } - break; - - case SHT_RELM: - if (sec->header.sh_entsize != sizeof(ElfW(RelM))) { - error_msg("relocation entry size mismatch: %lu != %lu", - (unsigned long) sec->header.sh_entsize, - (unsigned long) sizeof(ElfW(RelM))); - return NULL; - } - break; - /* XXX Relocation code from modutils-2.3.19 is not here. - * Why? That's about 20 lines of code from obj/obj_load.c, - * which gets done in a second pass through the sections. - * This BusyBox insmod does similar work in obj_relocate(). */ - } - } - - return f; -} - -#ifdef BB_FEATURE_INSMOD_LOADINKMEM -/* - * load the unloaded sections directly into the memory allocated by - * kernel for the module - */ - -static int obj_load_progbits(FILE * fp, struct obj_file* f, char* imagebase) -{ - ElfW(Addr) base = f->baseaddr; - struct obj_section* sec; - - for (sec = f->load_order; sec; sec = sec->load_next) { - - /* section already loaded? */ - if (sec->contents != NULL) - continue; - - if (sec->header.sh_size == 0) - continue; - - sec->contents = imagebase + (sec->header.sh_addr - base); - fseek(fp, sec->header.sh_offset, SEEK_SET); - if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) { - error_msg("error reading ELF section data: %s\n", strerror(errno)); - return 0; - } - - } - return 1; -} -#endif - -static void hide_special_symbols(struct obj_file *f) -{ - static const char *const specials[] = { - "cleanup_module", - "init_module", - "kernel_version", - NULL - }; - - struct obj_symbol *sym; - const char *const *p; - - for (p = specials; *p; ++p) - if ((sym = obj_find_symbol(f, *p)) != NULL) - sym->info = - ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info)); -} - - - -extern int insmod_main( int argc, char **argv) -{ - int opt; - int k_crcs; - int k_new_syscalls; - int len; - char *tmp; - unsigned long m_size; - ElfW(Addr) m_addr; - FILE *fp; - struct obj_file *f; - struct stat st; - char m_name[FILENAME_MAX + 1] = "\0"; - int exit_status = EXIT_FAILURE; - int m_has_modinfo; -#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING - struct utsname uts_info; - char m_strversion[STRVERSIONLEN]; - int m_version; - int m_crcs; -#endif - - /* Parse any options */ - while ((opt = getopt(argc, argv, "fkvxLo:")) > 0) { - switch (opt) { - case 'f': /* force loading */ - flag_force_load = 1; - break; - case 'k': /* module loaded by kerneld, auto-cleanable */ - flag_autoclean = 1; - break; - case 'v': /* verbose output */ - flag_verbose = 1; - break; - case 'x': /* do not export externs */ - flag_export = 0; - break; - case 'o': /* name the output module */ - strncpy(m_name, optarg, FILENAME_MAX); - break; - case 'L': /* Stub warning */ - /* This is needed for compatibility with modprobe. - * In theory, this does locking, but we don't do - * that. So be careful and plan your life around not - * loading the same module 50 times concurrently. */ - break; - default: - show_usage(); - } - } - - if (argv[optind] == NULL) { - show_usage(); - } - - /* Grab the module name */ - if ((tmp = strrchr(argv[optind], '/')) != NULL) { - tmp++; - } else { - tmp = argv[optind]; - } - len = strlen(tmp); - - if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') - len -= 2; - memcpy(m_fullName, tmp, len); - m_fullName[len]='\0'; - if (*m_name == '\0') { - strcpy(m_name, m_fullName); - } - strcat(m_fullName, ".o"); - - /* Get a filedesc for the module. Check we we have a complete path */ - if (stat(argv[optind], &st) < 0 || !S_ISREG(st.st_mode) || - (fp = fopen(argv[optind], "r")) == NULL) { - struct utsname myuname; - - /* Hmm. Could not open it. First search under /lib/modules/`uname -r`, - * but do not error out yet if we fail to find it... */ - if (uname(&myuname) == 0) { - char module_dir[FILENAME_MAX]; - char real_module_dir[FILENAME_MAX]; - snprintf (module_dir, sizeof(module_dir), "%s/%s", - _PATH_MODULES, myuname.release); - /* Jump through hoops in case /lib/modules/`uname -r` - * is a symlink. We do not want recursive_action to - * follow symlinks, but we do want to follow the - * /lib/modules/`uname -r` dir, So resolve it ourselves - * if it is a link... */ - if (realpath (module_dir, real_module_dir) == NULL) - strcpy(real_module_dir, module_dir); - recursive_action(real_module_dir, TRUE, FALSE, FALSE, - check_module_name_match, 0, m_fullName); - } - - /* Check if we have found anything yet */ - if (m_filename[0] == '\0' || ((fp = fopen(m_filename, "r")) == NULL)) - { - char module_dir[FILENAME_MAX]; - if (realpath (_PATH_MODULES, module_dir) == NULL) - strcpy(module_dir, _PATH_MODULES); - /* No module found under /lib/modules/`uname -r`, this - * time cast the net a bit wider. Search /lib/modules/ */ - if (recursive_action(module_dir, TRUE, FALSE, FALSE, - check_module_name_match, 0, m_fullName) == FALSE) - { - if (m_filename[0] == '\0' - || ((fp = fopen(m_filename, "r")) == NULL)) - { - error_msg("%s: no module by that name found", m_fullName); - return EXIT_FAILURE; - } - } else - error_msg_and_die("%s: no module by that name found", m_fullName); - } - } else - safe_strncpy(m_filename, argv[optind], sizeof(m_filename)); - - printf("Using %s\n", m_filename); - - if ((f = obj_load(fp, LOADBITS)) == NULL) - perror_msg_and_die("Could not load the module"); - - if (get_modinfo_value(f, "kernel_version") == NULL) - m_has_modinfo = 0; - else - m_has_modinfo = 1; - -#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING - /* Version correspondence? */ - - if (uname(&uts_info) < 0) - uts_info.release[0] = '\0'; - if (m_has_modinfo) { - m_version = new_get_module_version(f, m_strversion); - } else { - m_version = old_get_module_version(f, m_strversion); - if (m_version == -1) { - error_msg("couldn't find the kernel version the module was " - "compiled for"); - goto out; - } - } - - if (strncmp(uts_info.release, m_strversion, STRVERSIONLEN) != 0) { - if (flag_force_load) { - error_msg("Warning: kernel-module version mismatch\n" - "\t%s was compiled for kernel version %s\n" - "\twhile this kernel is version %s", - m_filename, m_strversion, uts_info.release); - } else { - error_msg("kernel-module version mismatch\n" - "\t%s was compiled for kernel version %s\n" - "\twhile this kernel is version %s.", - m_filename, m_strversion, uts_info.release); - goto out; - } - } - k_crcs = 0; -#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ - - k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL); - - if (k_new_syscalls) { -#ifdef BB_FEATURE_NEW_MODULE_INTERFACE - if (!new_get_kernel_symbols()) - goto out; - k_crcs = new_is_kernel_checksummed(); -#else - error_msg("Not configured to support new kernels"); - goto out; -#endif - } else { -#ifdef BB_FEATURE_OLD_MODULE_INTERFACE - if (!old_get_kernel_symbols(m_name)) - goto out; - k_crcs = old_is_kernel_checksummed(); -#else - error_msg("Not configured to support old kernels"); - goto out; -#endif - } - -#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING - if (m_has_modinfo) - m_crcs = new_is_module_checksummed(f); - else - m_crcs = old_is_module_checksummed(f); - - if (m_crcs != k_crcs) - obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash); -#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ - - /* Let the module know about the kernel symbols. */ - add_kernel_symbols(f); - - /* Allocate common symbols, symbol tables, and string tables. */ - - if (k_new_syscalls - ? !new_create_this_module(f, m_name) - : !old_create_mod_use_count(f)) - { - goto out; - } - - if (!obj_check_undefineds(f)) { - goto out; - } - obj_allocate_commons(f); - - /* done with the module name, on to the optional var=value arguments */ - ++optind; - - if (optind < argc) { - if (m_has_modinfo - ? !new_process_module_arguments(f, argc - optind, argv + optind) - : !old_process_module_arguments(f, argc - optind, argv + optind)) - { - goto out; - } - } - - arch_create_got(f); - hide_special_symbols(f); - - if (k_new_syscalls) - new_create_module_ksymtab(f); - - /* Find current size of the module */ - m_size = obj_load_size(f); - - - m_addr = create_module(m_name, m_size); - if (m_addr==-1) switch (errno) { - case EEXIST: - error_msg("A module named %s already exists", m_name); - goto out; - case ENOMEM: - error_msg("Can't allocate kernel memory for module; needed %lu bytes", - m_size); - goto out; - default: - perror_msg("create_module: %s", m_name); - goto out; - } - -#if !LOADBITS - /* - * the PROGBITS section was not loaded by the obj_load - * now we can load them directly into the kernel memory - */ - if (!obj_load_progbits(fp, f, (char*)m_addr)) { - delete_module(m_name); - goto out; - } -#endif - - if (!obj_relocate(f, m_addr)) { - delete_module(m_name); - goto out; - } - - if (k_new_syscalls - ? !new_init_module(m_name, f, m_size) - : !old_init_module(m_name, f, m_size)) - { - delete_module(m_name); - goto out; - } - - exit_status = EXIT_SUCCESS; - -out: - fclose(fp); - return(exit_status); -} diff --git a/busybox/modutils/lsmod.c b/busybox/modutils/lsmod.c deleted file mode 100644 index 76ed2fdd8..000000000 --- a/busybox/modutils/lsmod.c +++ /dev/null @@ -1,166 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini lsmod implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * - * Modified by Alcove, Julien Gaulmin and - * Nicolas Ferre to support pre 2.1 kernels - * (which lack the query_module() interface). - * - * 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 -#include -#include -#include "busybox.h" - - - -#ifdef BB_FEATURE_NEW_MODULE_INTERFACE - -struct module_info -{ - unsigned long addr; - unsigned long size; - unsigned long flags; - long usecount; -}; - - -int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret); - -/* Values for query_module's which. */ -static const int QM_MODULES = 1; -static const int QM_DEPS = 2; -static const int QM_REFS = 3; -static const int QM_SYMBOLS = 4; -static const int QM_INFO = 5; - -/* Bits of module.flags. */ -static const int NEW_MOD_RUNNING = 1; -static const int NEW_MOD_DELETED = 2; -static const int NEW_MOD_AUTOCLEAN = 4; -static const int NEW_MOD_VISITED = 8; -static const int NEW_MOD_USED_ONCE = 16; -static const int NEW_MOD_INITIALIZING = 64; - -static int my_query_module(const char *name, int which, void **buf, - size_t *bufsize, size_t *ret) -{ - int my_ret; - - my_ret = query_module(name, which, *buf, *bufsize, ret); - - if (my_ret == -1 && errno == ENOSPC) { - *buf = xrealloc(*buf, *ret); - *bufsize = *ret; - - my_ret = query_module(name, which, *buf, *bufsize, ret); - } - - return my_ret; -} - -extern int lsmod_main(int argc, char **argv) -{ - struct module_info info; - char *module_names, *mn, *deps, *dn; - size_t bufsize, depsize, nmod, count, i, j; - - module_names = xmalloc(bufsize = 256); - if (my_query_module(NULL, QM_MODULES, (void **)&module_names, &bufsize, - &nmod)) { - perror_msg_and_die("QM_MODULES"); - } - - deps = xmalloc(depsize = 256); - printf("Module Size Used by\n"); - for (i = 0, mn = module_names; i < nmod; mn += strlen(mn) + 1, i++) { - if (query_module(mn, QM_INFO, &info, sizeof(info), &count)) { - if (errno == ENOENT) { - /* The module was removed out from underneath us. */ - continue; - } - /* else choke */ - perror_msg_and_die("module %s: QM_INFO", mn); - } - if (my_query_module(mn, QM_REFS, (void **)&deps, &depsize, &count)) { - if (errno == ENOENT) { - /* The module was removed out from underneath us. */ - continue; - } - perror_msg_and_die("module %s: QM_REFS", mn); - } - printf("%-20s%8lu%4ld ", mn, info.size, info.usecount); - if (info.flags & NEW_MOD_DELETED) - printf("(deleted)"); - else if (info.flags & NEW_MOD_INITIALIZING) - printf("(initializing)"); - else if (!(info.flags & NEW_MOD_RUNNING)) - printf("(uninitialized)"); - else { - if (info.flags & NEW_MOD_AUTOCLEAN) - printf("(autoclean) "); - if (!(info.flags & NEW_MOD_USED_ONCE)) - printf("(unused)"); - } - if (count) printf("["); - for (j = 0, dn = deps; j < count; dn += strlen(dn) + 1, j++) { - printf("%s%s", dn, (j==count-1)? "":" "); - } - if (count) printf("] "); - - printf("\n"); - } - - - return( 0); -} - -#else /*BB_FEATURE_OLD_MODULE_INTERFACE*/ - -extern int lsmod_main(int argc, char **argv) -{ - int fd, i; - char line[128]; - - puts("Module Size Used by"); - fflush(stdout); - - if ((fd = open("/proc/modules", O_RDONLY)) >= 0 ) { - while ((i = read(fd, line, sizeof(line))) > 0) { - write(fileno(stdout), line, i); - } - close(fd); - return 0; - } - perror_msg_and_die("/proc/modules"); - return 1; -} - -#endif /*BB_FEATURE_OLD_MODULE_INTERFACE*/ diff --git a/busybox/modutils/modprobe.c b/busybox/modutils/modprobe.c deleted file mode 100644 index 05b40c53f..000000000 --- a/busybox/modutils/modprobe.c +++ /dev/null @@ -1,121 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * really dumb modprobe implementation for busybox - * Copyright (C) 2001 Lineo, davidm@lineo.com - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -static char cmd[128]; - -extern int modprobe_main(int argc, char** argv) -{ - int ch, rc = 0; - int loadall = 0, showconfig = 0, debug = 0, autoclean = 0, list = 0; - int show_only = 0, quiet = 0, remove_opt = 0, do_syslog = 0, verbose = 0; - char *load_type = NULL, *config = NULL; - - while ((ch = getopt(argc, argv, "acdklnqrst:vVC:")) != -1) - switch(ch) { - case 'a': - loadall++; - break; - case 'c': - showconfig++; - break; - case 'd': - debug++; - break; - case 'k': - autoclean++; - break; - case 'l': - list++; - break; - case 'n': - show_only++; - break; - case 'q': - quiet++; - break; - case 'r': - remove_opt++; - break; - case 's': - do_syslog++; - break; - case 't': - load_type = optarg; - break; - case 'v': - verbose++; - break; - case 'C': - config = optarg; - break; - case 'V': - default: - show_usage(); - break; - } - - if (load_type || config) { - fprintf(stderr, "-t and -C not supported\n"); - exit(EXIT_FAILURE); - } - - if (showconfig) - exit(EXIT_SUCCESS); - - if (list) - exit(EXIT_SUCCESS); - - if (remove_opt) { - do { - sprintf(cmd, "rmmod %s %s %s", - optind >= argc ? "-a" : "", - do_syslog ? "-s" : "", - optind < argc ? argv[optind] : ""); - if (do_syslog) - syslog(LOG_INFO, "%s", cmd); - if (show_only || verbose) - printf("%s\n", cmd); - if (!show_only) - rc = system(cmd); - } while (++optind < argc); - exit(EXIT_SUCCESS); - } - - if (optind >= argc) { - fprintf(stderr, "No module or pattern provided\n"); - exit(EXIT_FAILURE); - } - - sprintf(cmd, "insmod %s %s %s", - do_syslog ? "-s" : "", - quiet ? "-q" : "", - autoclean ? "-k" : ""); - while (optind < argc) { - strcat(cmd, argv[optind]); - strcat(cmd, " "); - optind++; - } - if (do_syslog) - syslog(LOG_INFO, "%s", cmd); - if (show_only || verbose) - printf("%s\n", cmd); - if (!show_only) - rc = system(cmd); - else - rc = 0; - - exit(rc ? EXIT_FAILURE : EXIT_SUCCESS); -} - - diff --git a/busybox/modutils/rmmod.c b/busybox/modutils/rmmod.c deleted file mode 100644 index 7596d0232..000000000 --- a/busybox/modutils/rmmod.c +++ /dev/null @@ -1,62 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini rmmod implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -extern int delete_module(const char * name); - - -extern int rmmod_main(int argc, char **argv) -{ - int n, ret = EXIT_SUCCESS; - - /* Parse command line. */ - while ((n = getopt(argc, argv, "a")) != EOF) { - switch (n) { - case 'a': - /* Unload _all_ unused modules via NULL delete_module() call */ - if (delete_module(NULL)) - perror_msg_and_die("rmmod"); - return EXIT_SUCCESS; - default: - show_usage(); - } - } - - if (optind == argc) - show_usage(); - - for (n = optind; n < argc; n++) { - if (delete_module(argv[n]) < 0) { - perror_msg("%s", argv[n]); - ret = EXIT_FAILURE; - } - } - - return(ret); -} diff --git a/busybox/more.c b/busybox/more.c deleted file mode 100644 index 780cddf66..000000000 --- a/busybox/more.c +++ /dev/null @@ -1,217 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini more implementation for busybox - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * - * Latest version blended together by Erik Andersen , - * based on the original more implementation by Bruce, and code from the - * Debian boot-floppies team. - * - * Termios corrects by Vladimir Oleynik - * - * 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 "busybox.h" - -static FILE *cin; - -#ifdef BB_FEATURE_USE_TERMIOS -#include -#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp) -#define getTermSettings(fd,argp) tcgetattr(fd, argp); - -static struct termios initial_settings, new_settings; - -static void set_tty_to_initial_mode(void) -{ - setTermSettings(fileno(cin), &initial_settings); -} - -static void gotsig(int sig) -{ - putchar('\n'); - exit(EXIT_FAILURE); -} -#endif /* BB_FEATURE_USE_TERMIOS */ - - -static int terminal_width = 79; /* not 80 in case terminal has linefold bug */ -static int terminal_height = 24; - - -extern int more_main(int argc, char **argv) -{ - int c, lines, input = 0; - int please_display_more_prompt = -1; - struct stat st; - FILE *file; - int len, page_height; - -#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS - struct winsize win = { 0, 0, 0, 0 }; -#endif - - argc--; - argv++; - - - /* not use inputing from terminal if usage: more > outfile */ - if(isatty(fileno(stdout))) { - cin = fopen(CURRENT_TTY, "r"); - if (!cin) - cin = xfopen(CONSOLE_DEV, "r"); - please_display_more_prompt = 0; -#ifdef BB_FEATURE_USE_TERMIOS - getTermSettings(fileno(cin), &initial_settings); - new_settings = initial_settings; - new_settings.c_lflag &= ~ICANON; - new_settings.c_lflag &= ~ECHO; -#ifndef linux - /* Hmm, in linux c_cc[] not parsed if set ~ICANON */ - new_settings.c_cc[VMIN] = 1; - new_settings.c_cc[VTIME] = 0; -#endif - setTermSettings(fileno(cin), &new_settings); - atexit(set_tty_to_initial_mode); - (void) signal(SIGINT, gotsig); - (void) signal(SIGQUIT, gotsig); - (void) signal(SIGTERM, gotsig); -#endif - } - - do { - if (argc == 0) { - file = stdin; - } else - file = wfopen(*argv, "r"); - if(file==0) - goto loop; - - fstat(fileno(file), &st); - - if(please_display_more_prompt>0) - please_display_more_prompt = 0; - -#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS - ioctl(fileno(stdout), TIOCGWINSZ, &win); - if (win.ws_row > 4) - terminal_height = win.ws_row - 2; - if (win.ws_col > 0) - terminal_width = win.ws_col - 1; -#endif - len=0; - lines = 0; - page_height = terminal_height; - while ((c = getc(file)) != EOF) { - - if (please_display_more_prompt>0) { - len = printf("--More-- "); - if (file != stdin) { -#if _FILE_OFFSET_BITS == 64 - len += printf("(%d%% of %lld bytes)", - (int) (100 * ((double) ftell(file) / - (double) st.st_size)), (long long)st.st_size); -#else - len += printf("(%d%% of %ld bytes)", - (int) (100 * ((double) ftell(file) / - (double) st.st_size)), (long)st.st_size); -#endif - } - - fflush(stdout); - - /* - * We've just displayed the "--More--" prompt, so now we need - * to get input from the user. - */ - input = getc(cin); -#ifndef BB_FEATURE_USE_TERMIOS - printf("\033[A"); /* up cursor */ -#endif - /* Erase the "More" message */ - putc('\r', stdout); - while (--len >= 0) - putc(' ', stdout); - putc('\r', stdout); - fflush(stdout); - len=0; - lines = 0; - page_height = terminal_height; - please_display_more_prompt = 0; - - if (input == 'q') - goto end; - } - - /* - * There are two input streams to worry about here: - * - * c : the character we are reading from the file being "mored" - * input : a character received from the keyboard - * - * If we hit a newline in the _file_ stream, we want to test and - * see if any characters have been hit in the _input_ stream. This - * allows the user to quit while in the middle of a file. - */ - if (c == '\n') { - /* increment by just one line if we are at - * the end of this line */ - if (input == '\n') - if(please_display_more_prompt==0) - please_display_more_prompt = 1; - /* Adjust the terminal height for any overlap, so that - * no lines get lost off the top. */ - if (len >= terminal_width) { - int quot, rem; - quot = len / terminal_width; - rem = len - (quot * terminal_width); - if (quot) { - if (rem) - page_height-=quot; - else - page_height-=(quot-1); - } - } - if (++lines >= page_height) { - if(please_display_more_prompt==0) - please_display_more_prompt = 1; - } - len=0; - } - /* - * If we just read a newline from the file being 'mored' and any - * key other than a return is hit, scroll by one page - */ - putc(c, stdout); - len++; - } - fclose(file); - fflush(stdout); -loop: - argv++; - } while (--argc > 0); - end: - return 0; -} diff --git a/busybox/mount.c b/busybox/mount.c deleted file mode 100644 index af57a7623..000000000 --- a/busybox/mount.c +++ /dev/null @@ -1,498 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mount implementation for busybox - * - * 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 - * - * 3/21/1999 Charles P. Wright - * searches through fstab when -a is passed - * will try mounting stuff with all fses when passed -t auto - * - * 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab. - * - * 1999-10-07 Erik Andersen , . - * Rewrite of a lot of code. Removed mtab usage (I plan on - * putting it back as a compile-time option some time), - * major adjustments to option parsing, and some serious - * dieting all around. - * - * 1999-11-06 mtab suppport is back - andersee - * - * 2000-01-12 Ben Collins , Borrowed utils-linux's - * mount to add loop support. - * - * 2000-04-30 Dave Cinege - * Rewrote fstab while loop and lower mount section. Can now do - * single mounts from fstab. Can override fstab options for single - * mount. Common mount_one call for single mounts and 'all'. Fixed - * mtab updating and stale entries. Removed 'remount' default. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" -#if defined BB_FEATURE_USE_DEVPS_PATCH -# include /* For Erik's nifty devmtab device driver */ -#endif - -enum { - MS_MGC_VAL = 0xc0ed0000, /* Magic number indicatng "new" flags */ - MS_RDONLY = 1, /* Mount read-only */ - MS_NOSUID = 2, /* Ignore suid and sgid bits */ - MS_NODEV = 4, /* Disallow access to device special files */ - MS_NOEXEC = 8, /* Disallow program execution */ - MS_SYNCHRONOUS = 16, /* Writes are synced at once */ - MS_REMOUNT = 32, /* Alter flags of a mounted FS */ - MS_MANDLOCK = 64, /* Allow mandatory locks on an FS */ - S_QUOTA = 128, /* Quota initialized for file/directory/symlink */ - S_APPEND = 256, /* Append-only file */ - S_IMMUTABLE = 512, /* Immutable file */ - MS_NOATIME = 1024, /* Do not update access times. */ - MS_NODIRATIME = 2048, /* Do not update directory access times */ - MS_BIND = 4096, /* Use the new linux 2.4.x "mount --bind" feature */ -}; - - -#if defined BB_FEATURE_MOUNT_LOOP -#include -#include -static int use_loop = FALSE; -#endif - -extern int mount (__const char *__special_file, __const char *__dir, - __const char *__fstype, unsigned long int __rwflag, - __const void *__data); -extern int umount (__const char *__special_file); -extern int umount2 (__const char *__special_file, int __flags); - -extern int sysfs( int option, unsigned int fs_index, char * buf); - -extern const char mtab_file[]; /* Defined in utility.c */ - -struct mount_options { - const char *name; - unsigned long and; - unsigned long or; -}; - -static const struct mount_options mount_options[] = { - {"async", ~MS_SYNCHRONOUS, 0}, - {"atime", ~0, ~MS_NOATIME}, - {"defaults", ~0, 0}, - {"dev", ~MS_NODEV, 0}, - {"diratime", ~0, ~MS_NODIRATIME}, - {"exec", ~MS_NOEXEC, 0}, - {"noatime", ~0, MS_NOATIME}, - {"nodev", ~0, MS_NODEV}, - {"nodiratime", ~0, MS_NODIRATIME}, - {"noexec", ~0, MS_NOEXEC}, - {"nosuid", ~0, MS_NOSUID}, - {"remount", ~0, MS_REMOUNT}, - {"ro", ~0, MS_RDONLY}, - {"rw", ~MS_RDONLY, 0}, - {"suid", ~MS_NOSUID, 0}, - {"sync", ~0, MS_SYNCHRONOUS}, - {"bind", ~0, MS_BIND}, - {0, 0, 0} -}; - -static int -do_mount(char *specialfile, char *dir, char *filesystemtype, - long flags, void *string_flags, int useMtab, int fakeIt, - char *mtab_opts, int mount_all) -{ - int status = 0; -#if defined BB_FEATURE_MOUNT_LOOP - char *lofile = NULL; -#endif - - if (fakeIt == FALSE) - { -#if defined BB_FEATURE_MOUNT_LOOP - if (use_loop==TRUE) { - int loro = flags & MS_RDONLY; - - lofile = specialfile; - - specialfile = find_unused_loop_device(); - if (specialfile == NULL) { - error_msg_and_die("Could not find a spare loop device"); - } - if (set_loop(specialfile, lofile, 0, &loro)) { - error_msg_and_die("Could not setup loop device"); - } - if (!(flags & MS_RDONLY) && loro) { /* loop is ro, but wanted rw */ - error_msg("WARNING: loop device is read-only"); - flags |= MS_RDONLY; - } - } -#endif - status = mount(specialfile, dir, filesystemtype, flags, string_flags); - if (status < 0 && errno == EROFS) { - error_msg("%s is write-protected, mounting read-only", specialfile); - status = mount(specialfile, dir, filesystemtype, flags |= MS_RDONLY, string_flags); - } - /* Don't whine about already mounted filesystems when mounting all. */ - if (status < 0 && errno == EBUSY && mount_all) - return TRUE; - } - - - /* If the mount was sucessful, do anything needed, then return TRUE */ - if (status == 0 || fakeIt==TRUE) { - -#if defined BB_FEATURE_MTAB_SUPPORT - if (useMtab == TRUE) { - erase_mtab(specialfile); // Clean any stale entries - write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts); - } -#endif - return (TRUE); - } - - /* Bummer. mount failed. Clean up */ -#if defined BB_FEATURE_MOUNT_LOOP - if (lofile != NULL) { - del_loop(specialfile); - } -#endif - - if (errno == EPERM) { - error_msg_and_die("permission denied. Are you root?"); - } - - return (FALSE); -} - - - -/* Seperate standard mount options from the nonstandard string options */ -static void -parse_mount_options(char *options, int *flags, char *strflags) -{ - while (options) { - int gotone = FALSE; - char *comma = strchr(options, ','); - const struct mount_options *f = mount_options; - - if (comma) - *comma = '\0'; - - while (f->name != 0) { - if (strcasecmp(f->name, options) == 0) { - - *flags &= f->and; - *flags |= f->or; - gotone = TRUE; - break; - } - f++; - } -#if defined BB_FEATURE_MOUNT_LOOP - if (gotone == FALSE && !strcasecmp("loop", options)) { /* loop device support */ - use_loop = TRUE; - gotone = TRUE; - } -#endif - if (*strflags && strflags != '\0' && gotone == FALSE) { - char *temp = strflags; - - temp += strlen(strflags); - *temp++ = ','; - *temp++ = '\0'; - } - if (gotone == FALSE) - strcat(strflags, options); - if (comma) { - *comma = ','; - options = ++comma; - } else { - break; - } - } -} - -static int -mount_one(char *blockDevice, char *directory, char *filesystemType, - unsigned long flags, char *string_flags, int useMtab, int fakeIt, - char *mtab_opts, int whineOnErrors, int mount_all) -{ - int status = 0; - -#if defined BB_FEATURE_USE_DEVPS_PATCH - if (strcmp(filesystemType, "auto") == 0) { - static const char *noauto_array[] = { "tmpfs", "shm", "proc", "ramfs", "devpts", "devfs", "usbdevfs", 0 }; - const char **noauto_fstype; - const int num_of_filesystems = sysfs(3, 0, 0); - char buf[255]; - int i=0; - - filesystemType=buf; - - while(i < num_of_filesystems) { - sysfs(2, i++, filesystemType); - for (noauto_fstype = noauto_array; *noauto_fstype; noauto_fstype++) { - if (!strcmp(filesystemType, *noauto_fstype)) { - break; - } - } - if (!*noauto_fstype) { - status = do_mount(blockDevice, directory, filesystemType, - flags | MS_MGC_VAL, string_flags, - useMtab, fakeIt, mtab_opts, mount_all); - if (status == TRUE) - break; - } - } - } -#else - if (strcmp(filesystemType, "auto") == 0) { - char buf[255]; - FILE *f = xfopen("/proc/filesystems", "r"); - - while (fgets(buf, sizeof(buf), f) != NULL) { - filesystemType = buf; - if (*filesystemType == '\t') { // Not a nodev filesystem - - // Add NULL termination to each line - while (*filesystemType && *filesystemType != '\n') - filesystemType++; - *filesystemType = '\0'; - - filesystemType = buf; - filesystemType++; // hop past tab - - status = do_mount(blockDevice, directory, filesystemType, - flags | MS_MGC_VAL, string_flags, - useMtab, fakeIt, mtab_opts, mount_all); - if (status == TRUE) - break; - } - } - fclose(f); - } -#endif - else { - status = do_mount(blockDevice, directory, filesystemType, - flags | MS_MGC_VAL, string_flags, useMtab, - fakeIt, mtab_opts, mount_all); - } - - if (status == FALSE) { - if (whineOnErrors == TRUE) { - perror_msg("Mounting %s on %s failed", blockDevice, directory); - } - return (FALSE); - } - return (TRUE); -} - -void show_mounts(void) -{ -#if defined BB_FEATURE_USE_DEVPS_PATCH - int fd, i, numfilesystems; - char device[] = "/dev/mtab"; - struct k_mntent *mntentlist; - - /* open device */ - fd = open(device, O_RDONLY); - if (fd < 0) - perror_msg_and_die("open failed for `%s'", device); - - /* How many mounted filesystems? We need to know to - * allocate enough space for later... */ - numfilesystems = ioctl (fd, DEVMTAB_COUNT_MOUNTS); - if (numfilesystems<0) - perror_msg_and_die( "\nDEVMTAB_COUNT_MOUNTS"); - mntentlist = (struct k_mntent *) xcalloc ( numfilesystems, sizeof(struct k_mntent)); - - /* Grab the list of mounted filesystems */ - if (ioctl (fd, DEVMTAB_GET_MOUNTS, mntentlist)<0) - perror_msg_and_die( "\nDEVMTAB_GET_MOUNTS"); - - for( i = 0 ; i < numfilesystems ; i++) { - printf( "%s %s %s %s %d %d\n", mntentlist[i].mnt_fsname, - mntentlist[i].mnt_dir, mntentlist[i].mnt_type, - mntentlist[i].mnt_opts, mntentlist[i].mnt_freq, - mntentlist[i].mnt_passno); - } -#ifdef BB_FEATURE_CLEAN_UP - /* Don't bother to close files or free memory. Exit - * does that automagically, so we can save a few bytes */ - free( mntentlist); - close(fd); -#endif - exit(EXIT_SUCCESS); -#else - FILE *mountTable = setmntent(mtab_file, "r"); - - if (mountTable) { - struct mntent *m; - - while ((m = getmntent(mountTable)) != 0) { - char *blockDevice = m->mnt_fsname; - if (strcmp(blockDevice, "/dev/root") == 0) { - blockDevice = find_real_root_device_name(blockDevice); - } - printf("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir, - m->mnt_type, m->mnt_opts); -#ifdef BB_FEATURE_CLEAN_UP - if(blockDevice != m->mnt_fsname) - free(blockDevice); -#endif - } - endmntent(mountTable); - } else { - perror_msg_and_die("%s", mtab_file); - } - exit(EXIT_SUCCESS); -#endif -} - -extern int mount_main(int argc, char **argv) -{ - struct stat statbuf; - char string_flags_buf[1024] = ""; - char *string_flags = string_flags_buf; - char *extra_opts = string_flags_buf; - int flags = 0; - char *filesystemType = "auto"; - char *device = xmalloc(PATH_MAX); - char *directory = xmalloc(PATH_MAX); - int all = FALSE; - int fakeIt = FALSE; - int useMtab = TRUE; - int rc = EXIT_FAILURE; - int fstabmount = FALSE; - int opt; - - /* Parse options */ - while ((opt = getopt(argc, argv, "o:rt:wafnv")) > 0) { - switch (opt) { - case 'o': - parse_mount_options(optarg, &flags, string_flags); - break; - case 'r': - flags |= MS_RDONLY; - break; - case 't': - filesystemType = optarg; - break; - case 'w': - flags &= ~MS_RDONLY; - break; - case 'a': - all = TRUE; - break; - case 'f': - fakeIt = TRUE; - break; -#ifdef BB_FEATURE_MTAB_SUPPORT - case 'n': - useMtab = FALSE; - break; -#endif - case 'v': - break; /* ignore -v */ - } - } - - if (!all && optind == argc) - show_mounts(); - - if (optind < argc) { - /* if device is a filename get its real path */ - if (stat(argv[optind], &statbuf) == 0) { - device = simplify_path(argv[optind]); - } else { - safe_strncpy(device, argv[optind], PATH_MAX); - } - } - - if (optind + 1 < argc) - directory = simplify_path(argv[optind + 1]); - - if (all == TRUE || optind + 1 == argc) { - struct mntent *m = NULL; - FILE *f = setmntent("/etc/fstab", "r"); - fstabmount = TRUE; - - if (f == NULL) - perror_msg_and_die( "\nCannot read /etc/fstab"); - - while ((m = getmntent(f)) != NULL) { - if (all == FALSE && optind + 1 == argc && ( - (strcmp(device, m->mnt_fsname) != 0) && - (strcmp(device, m->mnt_dir) != 0) ) ) { - continue; - } - - if (all == TRUE && ( // If we're mounting 'all' - (strstr(m->mnt_opts, "noauto")) || // and the file system isn't noauto, - (strstr(m->mnt_type, "swap")) || // and isn't swap or nfs, then mount it - (strstr(m->mnt_type, "nfs")) ) ) { - continue; - } - - if (all == TRUE || flags == 0) { // Allow single mount to override fstab flags - flags = 0; - *string_flags = '\0'; - parse_mount_options(m->mnt_opts, &flags, string_flags); - } - - strcpy(device, m->mnt_fsname); - strcpy(directory, m->mnt_dir); - filesystemType = strdup(m->mnt_type); -singlemount: - string_flags = strdup(string_flags); - rc = EXIT_SUCCESS; -#ifdef BB_NFSMOUNT - if (strchr(device, ':') != NULL) - filesystemType = "nfs"; - if (strcmp(filesystemType, "nfs") == 0) { - if (nfsmount (device, directory, &flags, &extra_opts, - &string_flags, 1)) { - perror_msg("nfsmount failed"); - rc = EXIT_FAILURE; - } - } -#endif - if (!mount_one(device, directory, filesystemType, flags, - string_flags, useMtab, fakeIt, extra_opts, TRUE, all)) - rc = EXIT_FAILURE; - - if (all == FALSE) - break; - } - if (fstabmount == TRUE) - endmntent(f); - - if (all == FALSE && fstabmount == TRUE && m == NULL) - fprintf(stderr, "Can't find %s in /etc/fstab\n", device); - - return rc; - } - - goto singlemount; -} diff --git a/busybox/msh.c b/busybox/msh.c deleted file mode 100644 index e16d6f304..000000000 --- a/busybox/msh.c +++ /dev/null @@ -1,4868 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Minix shell port for busybox - * - * This version of the Minix shell was adapted for use in busybox - * 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 - * - * Original copyright notice is retained at the end of this file. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cmdedit.h" -#include "busybox.h" - - -/* -------- sh.h -------- */ -/* - * shell - */ - -#define LINELIM 2100 -#define NPUSH 8 /* limit to input nesting */ - -#define NOFILE 20 /* Number of open files */ -#define NUFILE 10 /* Number of user-accessible files */ -#define FDBASE 10 /* First file usable by Shell */ - -/* - * values returned by wait - */ -#define WAITSIG(s) ((s)&0177) -#define WAITVAL(s) (((s)>>8)&0377) -#define WAITCORE(s) (((s)&0200)!=0) - -/* - * library and system defintions - */ -typedef void xint; /* base type of jmp_buf, for not broken compilers */ - -/* - * shell components - */ - -#define QUOTE 0200 - -#define NOBLOCK ((struct op *)NULL) -#define NOWORD ((char *)NULL) -#define NOWORDS ((char **)NULL) -#define NOPIPE ((int *)NULL) - -/* - * Description of a command or an operation on commands. - * Might eventually use a union. - */ -struct op { - int type; /* operation type, see below */ - char **words; /* arguments to a command */ - struct ioword **ioact; /* IO actions (eg, < > >>) */ - struct op *left; - struct op *right; - char *str; /* identifier for case and for */ -}; - -#define TCOM 1 /* command */ -#define TPAREN 2 /* (c-list) */ -#define TPIPE 3 /* a | b */ -#define TLIST 4 /* a [&;] b */ -#define TOR 5 /* || */ -#define TAND 6 /* && */ -#define TFOR 7 -#define TDO 8 -#define TCASE 9 -#define TIF 10 -#define TWHILE 11 -#define TUNTIL 12 -#define TELIF 13 -#define TPAT 14 /* pattern in case */ -#define TBRACE 15 /* {c-list} */ -#define TASYNC 16 /* c & */ - -/* - * actions determining the environment of a process - */ -#define BIT(i) (1<<(i)) -#define FEXEC BIT(0) /* execute without forking */ - -/* - * flags to control evaluation of words - */ -#define DOSUB 1 /* interpret $, `, and quotes */ -#define DOBLANK 2 /* perform blank interpretation */ -#define DOGLOB 4 /* interpret [?* */ -#define DOKEY 8 /* move words with `=' to 2nd arg. list */ -#define DOTRIM 16 /* trim resulting string */ - -#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM) - -static char **dolv; -static int dolc; -static int exstat; -static char gflg; -static int interactive; /* Is this an interactive shell */ -static int execflg; -static int multiline; /* \n changed to ; */ -static struct op *outtree; /* result from parser */ - -static xint *failpt; -static xint *errpt; -static struct brkcon *brklist; -static int isbreak; -static int newfile(char *s); -static char *findeq(char *cp); -static char *cclass(char *p, int sub); -static void initarea(void); -extern int msh_main(int argc, char **argv); - - -struct brkcon { - jmp_buf brkpt; - struct brkcon *nextlev; -} ; - -/* - * redirection - */ -struct ioword { - short io_unit; /* unit affected */ - short io_flag; /* action (below) */ - char *io_name; /* file name */ -}; -#define IOREAD 1 /* < */ -#define IOHERE 2 /* << (here file) */ -#define IOWRITE 4 /* > */ -#define IOCAT 8 /* >> */ -#define IOXHERE 16 /* ${}, ` in << */ -#define IODUP 32 /* >&digit */ -#define IOCLOSE 64 /* >&- */ - -#define IODEFAULT (-1) /* token for default IO unit */ - -static struct wdblock *wdlist; -static struct wdblock *iolist; - -/* - * parsing & execution environment - */ -static struct env { - char *linep; - struct io *iobase; - struct io *iop; - xint *errpt; - int iofd; - struct env *oenv; -} e; - -/* - * flags: - * -e: quit on error - * -k: look for name=value everywhere on command line - * -n: no execution - * -t: exit after reading and executing one command - * -v: echo as read - * -x: trace - * -u: unset variables net diagnostic - */ -static char *flag; - -static char *null; /* null value for variable */ -static int intr; /* interrupt pending */ - -static char *trap[_NSIG+1]; -static char ourtrap[_NSIG+1]; -static int trapset; /* trap pending */ - -static int heedint; /* heed interrupt signals */ - -static int yynerrs; /* yacc */ - -static char line[LINELIM]; -static char *elinep; - -/* - * other functions - */ -static int (*inbuilt(char *s ))(void); - -static char *rexecve (char *c , char **v, char **envp ); -static char *space (int n ); -static char *strsave (char *s, int a ); -static char *evalstr (char *cp, int f ); -static char *putn (int n ); -static char *itoa (unsigned u, int n ); -static char *unquote (char *as ); -static struct var *lookup (char *n ); -static int rlookup (char *n ); -static struct wdblock *glob (char *cp, struct wdblock *wb ); -static int my_getc( int ec); -static int subgetc (int ec, int quoted ); -static char **makenv (void); -static char **eval (char **ap, int f ); -static int setstatus (int s ); -static int waitfor (int lastpid, int canintr ); - -static void onintr (int s ); /* SIGINT handler */ - -static int newenv (int f ); -static void quitenv (void); -static void err (char *s ); -static int anys (char *s1, char *s2 ); -static int any (int c, char *s ); -static void next (int f ); -static void setdash (void); -static void onecommand (void); -static void runtrap (int i ); -static int gmatch (char *s, char *p ); - -/* - * error handling - */ -static void leave (void); /* abort shell (or fail in subshell) */ -static void fail (void); /* fail but return to process next command */ -static void warn (char *s ); -static void sig (int i ); /* default signal handler */ - - - -/* -------- area stuff -------- */ - -#define REGSIZE sizeof(struct region) -#define GROWBY 256 -//#define SHRINKBY 64 -#undef SHRINKBY -#define FREE 32767 -#define BUSY 0 -#define ALIGN (sizeof(int)-1) - - -struct region { - struct region *next; - int area; -}; - - - -/* -------- grammar stuff -------- */ -typedef union { - char *cp; - char **wp; - int i; - struct op *o; -} YYSTYPE; -#define WORD 256 -#define LOGAND 257 -#define LOGOR 258 -#define BREAK 259 -#define IF 260 -#define THEN 261 -#define ELSE 262 -#define ELIF 263 -#define FI 264 -#define CASE 265 -#define ESAC 266 -#define FOR 267 -#define WHILE 268 -#define UNTIL 269 -#define DO 270 -#define DONE 271 -#define IN 272 -#define YYERRCODE 300 - -/* flags to yylex */ -#define CONTIN 01 /* skip new lines to complete command */ - -#define SYNTAXERR zzerr() -static struct op *pipeline(int cf ); -static struct op *andor(void); -static struct op *c_list(void); -static int synio(int cf ); -static void musthave (int c, int cf ); -static struct op *simple(void); -static struct op *nested(int type, int mark ); -static struct op *command(int cf ); -static struct op *dogroup(int onlydone ); -static struct op *thenpart(void); -static struct op *elsepart(void); -static struct op *caselist(void); -static struct op *casepart(void); -static char **pattern(void); -static char **wordlist(void); -static struct op *list(struct op *t1, struct op *t2 ); -static struct op *block(int type, struct op *t1, struct op *t2, char **wp ); -static struct op *newtp(void); -static struct op *namelist(struct op *t ); -static char **copyw(void); -static void word(char *cp ); -static struct ioword **copyio(void); -static struct ioword *io (int u, int f, char *cp ); -static void zzerr(void); -static void yyerror(char *s ); -static int yylex(int cf ); -static int collect(int c, int c1 ); -static int dual(int c ); -static void diag(int ec ); -static char *tree(unsigned size ); - -/* -------- var.h -------- */ - -struct var { - char *value; - char *name; - struct var *next; - char status; -}; -#define COPYV 1 /* flag to setval, suggesting copy */ -#define RONLY 01 /* variable is read-only */ -#define EXPORT 02 /* variable is to be exported */ -#define GETCELL 04 /* name & value space was got with getcell */ - -static struct var *vlist; /* dictionary */ - -static struct var *homedir; /* home directory */ -static struct var *prompt; /* main prompt */ -static struct var *cprompt; /* continuation prompt */ -static struct var *path; /* search path for commands */ -static struct var *shell; /* shell to interpret command files */ -static struct var *ifs; /* field separators */ - -static int yyparse (void); -static struct var *lookup (char *n ); -static void setval (struct var *vp, char *val ); -static void nameval (struct var *vp, char *val, char *name ); -static void export (struct var *vp ); -static void ronly (struct var *vp ); -static int isassign (char *s ); -static int checkname (char *cp ); -static int assign (char *s, int cf ); -static void putvlist (int f, int out ); -static int eqname (char *n1, char *n2 ); - -static int execute (struct op *t, int *pin, int *pout, int act ); - -/* -------- io.h -------- */ -/* io buffer */ -struct iobuf { - unsigned id; /* buffer id */ - char buf[512]; /* buffer */ - char *bufp; /* pointer into buffer */ - char *ebufp; /* pointer to end of buffer */ -}; - -/* possible arguments to an IO function */ -struct ioarg { - char *aword; - char **awordlist; - int afile; /* file descriptor */ - unsigned afid; /* buffer id */ - long afpos; /* file position */ - struct iobuf *afbuf; /* buffer for this file */ -}; -//static struct ioarg ioargstack[NPUSH]; -#define AFID_NOBUF (~0) -#define AFID_ID 0 - -/* an input generator's state */ -struct io { - int (*iofn)(); - struct ioarg *argp; - int peekc; - char prev; /* previous character read by readc() */ - char nlcount; /* for `'s */ - char xchar; /* for `'s */ - char task; /* reason for pushed IO */ -}; -//static struct io iostack[NPUSH]; -#define XOTHER 0 /* none of the below */ -#define XDOLL 1 /* expanding ${} */ -#define XGRAVE 2 /* expanding `'s */ -#define XIO 3 /* file IO */ - -/* in substitution */ -#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL) - -/* - * input generators for IO structure - */ -static int nlchar (struct ioarg *ap ); -static int strchar (struct ioarg *ap ); -static int qstrchar (struct ioarg *ap ); -static int filechar (struct ioarg *ap ); -static int herechar (struct ioarg *ap ); -static int linechar (struct ioarg *ap ); -static int gravechar (struct ioarg *ap, struct io *iop ); -static int qgravechar (struct ioarg *ap, struct io *iop ); -static int dolchar (struct ioarg *ap ); -static int wdchar (struct ioarg *ap ); -static void scraphere (void); -static void freehere (int area ); -static void gethere (void); -static void markhere (char *s, struct ioword *iop ); -static int herein (char *hname, int xdoll ); -static int run (struct ioarg *argp, int (*f)()); - -/* - * IO functions - */ -static int eofc (void); -static int readc (void); -static void unget (int c ); -static void ioecho (int c ); -static void prs (char *s ); -static void prn (unsigned u ); -static void closef (int i ); -static void closeall (void); - -/* - * IO control - */ -static void pushio (struct ioarg *argp, int (*fn)()); -static int remap (int fd ); -static int openpipe (int *pv ); -static void closepipe (int *pv ); -static struct io *setbase (struct io *ip ); - -static struct ioarg temparg; /* temporary for PUSHIO */ -#define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen))) -#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen))) - -/* -------- word.h -------- */ - -#define NSTART 16 /* default number of words to allow for initially */ - -struct wdblock { - short w_bsize; - short w_nword; - /* bounds are arbitrary */ - char *w_words[1]; -}; - -static struct wdblock *addword (char *wd, struct wdblock *wb ); -static struct wdblock *newword (int nw ); -static char **getwords (struct wdblock *wb ); - -/* -------- area.h -------- */ - -/* - * storage allocation - */ -static char *getcell (unsigned nbytes ); -static void garbage (void); -static void setarea (char *cp, int a ); -static int getarea (char *cp ); -static void freearea (int a ); -static void freecell (char *cp ); -static int areanum; /* current allocation area */ - -#define NEW(type) (type *)getcell(sizeof(type)) -#define DELETE(obj) freecell((char *)obj) - - -/* -------- misc stuff -------- */ - -static int forkexec (struct op *t, int *pin, int *pout, int act, char **wp, int *pforked ); -static int iosetup (struct ioword *iop, int pipein, int pipeout ); -static void echo(char **wp ); -static struct op **find1case (struct op *t, char *w ); -static struct op *findcase (struct op *t, char *w ); -static void brkset(struct brkcon *bc ); -static int dolabel(void); -static int dohelp(void); -static int dochdir(struct op *t ); -static int doshift(struct op *t ); -static int dologin(struct op *t ); -static int doumask(struct op *t ); -static int doexec(struct op *t ); -static int dodot(struct op *t ); -static int dowait(struct op *t ); -static int doread(struct op *t ); -static int doeval(struct op *t ); -static int dotrap(struct op *t ); -static int getsig(char *s ); -static void setsig (int n, void (*f)()); -static int getn(char *as ); -static int dobreak(struct op *t ); -static int docontinue(struct op *t ); -static int brkcontin (char *cp, int val ); -static int doexit(struct op *t ); -static int doexport(struct op *t ); -static int doreadonly(struct op *t ); -static void rdexp (char **wp, void (*f)(), int key); -static void badid(char *s ); -static int doset(struct op *t ); -static void varput (char *s, int out ); -static int dotimes(void); -static int expand (char *cp, struct wdblock **wbp, int f ); -static char *blank(int f ); -static int dollar(int quoted ); -static int grave(int quoted ); -static void globname (char *we, char *pp ); -static char *generate (char *start1, char *end1, char *middle, char *end ); -static int anyspcl(struct wdblock *wb ); -static int xstrcmp (char *p1, char *p2 ); -static void glob0 (char *a0, unsigned int a1, int a2, int (*a3)(char *, char *)); -static void glob1 (char *base, char *lim ); -static void glob2 (char *i, char *j ); -static void glob3 (char *i, char *j, char *k ); -static void readhere (char **name, char *s, int ec ); -static void pushio(struct ioarg *argp, int (*fn)()); -static int xxchar(struct ioarg *ap ); - -struct here { - char *h_tag; - int h_dosub; - struct ioword *h_iop; - struct here *h_next; -}; - -static char *signame[] = { - "Signal 0", - "Hangup", - (char *)NULL, /* interrupt */ - "Quit", - "Illegal instruction", - "Trace/BPT trap", - "Abort", - "Bus error", - "Floating Point Exception", - "Killed", - "SIGUSR1", - "SIGSEGV", - "SIGUSR2", - (char *)NULL, /* broken pipe */ - "Alarm clock", - "Terminated", -}; -#define NSIGNAL (sizeof(signame)/sizeof(signame[0])) - -struct res { - char *r_name; - int r_val; -}; -static struct res restab[] = { - {"for", FOR}, - {"case", CASE}, - {"esac", ESAC}, - {"while", WHILE}, - {"do", DO}, - {"done", DONE}, - {"if", IF}, - {"in", IN}, - {"then", THEN}, - {"else", ELSE}, - {"elif", ELIF}, - {"until", UNTIL}, - {"fi", FI}, - - {";;", BREAK}, - {"||", LOGOR}, - {"&&", LOGAND}, - {"{", '{'}, - {"}", '}'}, - {0, 0}, -}; - - -struct builtincmd { - const char *name; - int (*builtinfunc)(); -}; -static const struct builtincmd builtincmds[] = { - {".", dodot}, - {":", dolabel}, - {"break", dobreak}, - {"cd", dochdir}, - {"continue",docontinue}, - {"eval", doeval}, - {"exec", doexec}, - {"exit", doexit}, - {"export", doexport}, - {"help", dohelp}, - {"login", dologin}, - {"newgrp", dologin}, - {"read", doread}, - {"readonly",doreadonly}, - {"set", doset}, - {"shift", doshift}, - {"times", dotimes}, - {"trap", dotrap}, - {"umask", doumask}, - {"wait", dowait}, - {0,0} -}; - -/* Globals */ -extern char **environ; /* environment pointer */ -static char **dolv; -static int dolc; -static int exstat; -static char gflg; -static int interactive; /* Is this an interactive shell */ -static int execflg; -static int multiline; /* \n changed to ; */ -static struct op *outtree; /* result from parser */ -static xint *failpt; -static xint *errpt; -static struct brkcon *brklist; -static int isbreak; -static struct wdblock *wdlist; -static struct wdblock *iolist; -static char *trap[_NSIG+1]; -static char ourtrap[_NSIG+1]; -static int trapset; /* trap pending */ -static int yynerrs; /* yacc */ -static char line[LINELIM]; -static struct var *vlist; /* dictionary */ -static struct var *homedir; /* home directory */ -static struct var *prompt; /* main prompt */ -static struct var *cprompt; /* continuation prompt */ -static struct var *path; /* search path for commands */ -static struct var *shell; /* shell to interpret command files */ -static struct var *ifs; /* field separators */ -static struct ioarg ioargstack[NPUSH]; -static struct io iostack[NPUSH]; -static int areanum; /* current allocation area */ -static int intr; -static int inparse; -static char flags['z'-'a'+1]; -static char *flag = flags-'a'; -static char *elinep = line+sizeof(line)-5; -static char *null = ""; -static int heedint =1; -static struct env e ={line, iostack, iostack-1, (xint *)NULL, FDBASE, (struct env *)NULL}; -static void (*qflag)(int) = SIG_IGN; -static char shellname[] = "/bin/sh"; -static char search[] = ":/bin:/usr/bin"; -static int startl; -static int peeksym; -static int nlseen; -static int iounit = IODEFAULT; -static YYSTYPE yylval; -static struct iobuf sharedbuf = {AFID_NOBUF}; -static struct iobuf mainbuf = {AFID_NOBUF}; -static unsigned bufid = AFID_ID; /* buffer id counter */ -static struct ioarg temparg = {0, 0, 0, AFID_NOBUF, 0}; -static struct here *inhere; /* list of hear docs while parsing */ -static struct here *acthere; /* list of active here documents */ -static struct region *areabot; /* bottom of area */ -static struct region *areatop; /* top of area */ -static struct region *areanxt; /* starting point of scan */ -static void * brktop; -static void * brkaddr; - - -#ifdef BB_FEATURE_COMMAND_EDITING -static char * current_prompt; -#endif - - -/* -------- sh.c -------- */ -/* - * shell - */ - - -extern int msh_main(int argc, char **argv) -{ - register int f; - register char *s; - int cflag; - char *name, **ap; - int (*iof)(); - - initarea(); - if ((ap = environ) != NULL) { - while (*ap) - assign(*ap++, !COPYV); - for (ap = environ; *ap;) - export(lookup(*ap++)); - } - closeall(); - areanum = 1; - - shell = lookup("SHELL"); - if (shell->value == null) - setval(shell, shellname); - export(shell); - - homedir = lookup("HOME"); - if (homedir->value == null) - setval(homedir, "/"); - export(homedir); - - setval(lookup("$"), itoa(getpid(), 5)); - - path = lookup("PATH"); - if (path->value == null) - setval(path, search); - export(path); - - ifs = lookup("IFS"); - if (ifs->value == null) - setval(ifs, " \t\n"); - - prompt = lookup("PS1"); -#ifdef BB_FEATURE_SH_FANCY_PROMPT - if (prompt->value == null) -#endif - setval(prompt, "$ "); - if (geteuid() == 0) { - setval(prompt, "# "); - prompt->status &= ~EXPORT; - } - cprompt = lookup("PS2"); -#ifdef BB_FEATURE_SH_FANCY_PROMPT - if (cprompt->value == null) -#endif - setval(cprompt, "> "); - - iof = filechar; - cflag = 0; - name = *argv++; - if (--argc >= 1) { - if(argv[0][0] == '-' && argv[0][1] != '\0') { - for (s = argv[0]+1; *s; s++) - switch (*s) { - case 'c': - prompt->status &= ~EXPORT; - cprompt->status &= ~EXPORT; - setval(prompt, ""); - setval(cprompt, ""); - cflag = 1; - if (--argc > 0) - PUSHIO(aword, *++argv, iof = nlchar); - break; - - case 'q': - qflag = SIG_DFL; - break; - - case 's': - /* standard input */ - break; - - case 't': - prompt->status &= ~EXPORT; - setval(prompt, ""); - iof = linechar; - break; - - case 'i': - interactive++; - default: - if (*s>='a' && *s<='z') - flag[(int)*s]++; - } - } else { - argv--; - argc++; - } - if (iof == filechar && --argc > 0) { - setval(prompt, ""); - setval(cprompt, ""); - prompt->status &= ~EXPORT; - cprompt->status &= ~EXPORT; - if (newfile(name = *++argv)) - exit(1); - } - } - setdash(); - if (e.iop < iostack) { - PUSHIO(afile, 0, iof); - if (isatty(0) && isatty(1) && !cflag) { - interactive++; - printf( "\n\n" BB_BANNER " Built-in shell (msh)\n"); - printf( "Enter 'help' for a list of built-in commands.\n\n"); - } - } - signal(SIGQUIT, qflag); - if (name && name[0] == '-') { - interactive++; - if ((f = open(".profile", 0)) >= 0) - next(remap(f)); - if ((f = open("/etc/profile", 0)) >= 0) - next(remap(f)); - } - if (interactive) - signal(SIGTERM, sig); - if (signal(SIGINT, SIG_IGN) != SIG_IGN) - signal(SIGINT, onintr); - dolv = argv; - dolc = argc; - dolv[0] = name; - if (dolc > 1) { - for (ap = ++argv; --argc > 0;) { - if (assign(*ap = *argv++, !COPYV)) { - dolc--; /* keyword */ - } else { - ap++; - } - } - } - setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc)); - - for (;;) { - if (interactive && e.iop <= iostack) { -#ifdef BB_FEATURE_COMMAND_EDITING - current_prompt=prompt->value; -#else - prs(prompt->value); -#endif - } - onecommand(); - } -} - -static void -setdash() -{ - register char *cp; - register int c; - char m['z'-'a'+1]; - - cp = m; - for (c='a'; c<='z'; c++) - if (flag[c]) - *cp++ = c; - *cp = 0; - setval(lookup("-"), m); -} - -static int -newfile(s) -register char *s; -{ - register int f; - - if (strcmp(s, "-") != 0) { - f = open(s, 0); - if (f < 0) { - prs(s); - err(": cannot open"); - return(1); - } - } else - f = 0; - next(remap(f)); - return(0); -} - -static void -onecommand() -{ - register int i; - jmp_buf m1; - - while (e.oenv) - quitenv(); - areanum = 1; - freehere(areanum); - freearea(areanum); - garbage(); - wdlist = 0; - iolist = 0; - e.errpt = 0; - e.linep = line; - yynerrs = 0; - multiline = 0; - inparse = 1; - intr = 0; - execflg = 0; - setjmp(failpt = m1); /* Bruce Evans' fix */ - if (setjmp(failpt = m1) || yyparse() || intr) { - while (e.oenv) - quitenv(); - scraphere(); - if (!interactive && intr) - leave(); - inparse = 0; - intr = 0; - return; - } - inparse = 0; - brklist = 0; - intr = 0; - execflg = 0; - if (!flag['n']) - execute(outtree, NOPIPE, NOPIPE, 0); - if (!interactive && intr) { - execflg = 0; - leave(); - } - if ((i = trapset) != 0) { - trapset = 0; - runtrap(i); - } -} - -static void -fail() -{ - longjmp(failpt, 1); - /* NOTREACHED */ -} - -static void -leave() -{ - if (execflg) - fail(); - scraphere(); - freehere(1); - runtrap(0); - exit(exstat); - /* NOTREACHED */ -} - -static void -warn(s) -register char *s; -{ - if(*s) { - prs(s); - exstat = -1; - } - prs("\n"); - if (flag['e']) - leave(); -} - -static void -err(s) -char *s; -{ - warn(s); - if (flag['n']) - return; - if (!interactive) - leave(); - if (e.errpt) - longjmp(e.errpt, 1); - closeall(); - e.iop = e.iobase = iostack; -} - -static int -newenv(f) -int f; -{ - register struct env *ep; - - if (f) { - quitenv(); - return(1); - } - ep = (struct env *) space(sizeof(*ep)); - if (ep == NULL) { - while (e.oenv) - quitenv(); - fail(); - } - *ep = e; - e.oenv = ep; - e.errpt = errpt; - return(0); -} - -static void -quitenv() -{ - register struct env *ep; - register int fd; - - if ((ep = e.oenv) != NULL) { - fd = e.iofd; - e = *ep; - /* should close `'d files */ - DELETE(ep); - while (--fd >= e.iofd) - close(fd); - } -} - -/* - * Is any character from s1 in s2? - */ -static int -anys(s1, s2) -register char *s1, *s2; -{ - while (*s1) - if (any(*s1++, s2)) - return(1); - return(0); -} - -/* - * Is character c in s? - */ -static int -any(c, s) -register int c; -register char *s; -{ - while (*s) - if (*s++ == c) - return(1); - return(0); -} - -static char * -putn(n) -register int n; -{ - return(itoa(n, -1)); -} - -static char * -itoa(u, n) -register unsigned u; -int n; -{ - register char *cp; - static char s[20]; - int m; - - m = 0; - if (n < 0 && (int) u < 0) { - m++; - u = -u; - } - cp = s+sizeof(s); - *--cp = 0; - do { - *--cp = u%10 + '0'; - u /= 10; - } while (--n > 0 || u); - if (m) - *--cp = '-'; - return(cp); -} - -static void -next(f) -int f; -{ - PUSHIO(afile, f, filechar); -} - -static void -onintr(s) -int s; /* ANSI C requires a parameter */ -{ - signal(SIGINT, onintr); - intr = 1; - if (interactive) { - if (inparse) { - prs("\n"); - fail(); - } - } - else if (heedint) { - execflg = 0; - leave(); - } -} - -static char * -space(n) -int n; -{ - register char *cp; - - if ((cp = getcell(n)) == 0) - err("out of string space"); - return(cp); -} - -static char * -strsave(s, a) -register char *s; -int a; -{ - register char *cp, *xp; - - if ((cp = space(strlen(s)+1)) != NULL) { - setarea((char *)cp, a); - for (xp = cp; (*xp++ = *s++) != '\0';) - ; - return(cp); - } - return(""); -} - -/* - * trap handling - */ -static void -sig(i) -register int i; -{ - trapset = i; - signal(i, sig); -} - -static void runtrap(i) -int i; -{ - char *trapstr; - - if ((trapstr = trap[i]) == NULL) - return; - if (i == 0) - trap[i] = 0; - RUN(aword, trapstr, nlchar); -} - -/* -------- var.c -------- */ - -/* - * Find the given name in the dictionary - * and return its value. If the name was - * not previously there, enter it now and - * return a null value. - */ -static struct var * -lookup(n) -register char *n; -{ - register struct var *vp; - register char *cp; - register int c; - static struct var dummy; - - if (isdigit(*n)) { - dummy.name = n; - for (c = 0; isdigit(*n) && c < 1000; n++) - c = c*10 + *n-'0'; - dummy.status = RONLY; - dummy.value = c <= dolc? dolv[c]: null; - return(&dummy); - } - for (vp = vlist; vp; vp = vp->next) - if (eqname(vp->name, n)) - return(vp); - cp = findeq(n); - vp = (struct var *)space(sizeof(*vp)); - if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) { - dummy.name = dummy.value = ""; - return(&dummy); - } - for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++) - ; - if (*cp == 0) - *cp = '='; - *++cp = 0; - setarea((char *)vp, 0); - setarea((char *)vp->name, 0); - vp->value = null; - vp->next = vlist; - vp->status = GETCELL; - vlist = vp; - return(vp); -} - -/* - * give variable at `vp' the value `val'. - */ -static void -setval(vp, val) -struct var *vp; -char *val; -{ - nameval(vp, val, (char *)NULL); -} - -/* - * if name is not NULL, it must be - * a prefix of the space `val', - * and end with `='. - * this is all so that exporting - * values is reasonably painless. - */ -static void -nameval(vp, val, name) -register struct var *vp; -char *val, *name; -{ - register char *cp, *xp; - char *nv; - int fl; - - if (vp->status & RONLY) { - for (xp = vp->name; *xp && *xp != '=';) - putc(*xp++, stderr); - err(" is read-only"); - return; - } - fl = 0; - if (name == NULL) { - xp = space(strlen(vp->name)+strlen(val)+2); - if (xp == 0) - return; - /* make string: name=value */ - setarea((char *)xp, 0); - name = xp; - for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++) - ; - if (*xp++ == 0) - xp[-1] = '='; - nv = xp; - for (cp = val; (*xp++ = *cp++) != '\0';) - ; - val = nv; - fl = GETCELL; - } - if (vp->status & GETCELL) - freecell(vp->name); /* form new string `name=value' */ - vp->name = name; - vp->value = val; - vp->status |= fl; -} - -static void -export(vp) -struct var *vp; -{ - vp->status |= EXPORT; -} - -static void -ronly(vp) -struct var *vp; -{ - if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */ - vp->status |= RONLY; -} - -static int -isassign(s) -register char *s; -{ - if (!isalpha((int)*s) && *s != '_') - return(0); - for (; *s != '='; s++) - if (*s == 0 || (!isalnum(*s) && *s != '_')) - return(0); - return(1); -} - -static int -assign(s, cf) -register char *s; -int cf; -{ - register char *cp; - struct var *vp; - - if (!isalpha(*s) && *s != '_') - return(0); - for (cp = s; *cp != '='; cp++) - if (*cp == 0 || (!isalnum(*cp) && *cp != '_')) - return(0); - vp = lookup(s); - nameval(vp, ++cp, cf == COPYV? (char *)NULL: s); - if (cf != COPYV) - vp->status &= ~GETCELL; - return(1); -} - -static int -checkname(cp) -register char *cp; -{ - if (!isalpha(*cp++) && *(cp-1) != '_') - return(0); - while (*cp) - if (!isalnum(*cp++) && *(cp-1) != '_') - return(0); - return(1); -} - -static void -putvlist(f, out) -register int f, out; -{ - register struct var *vp; - - for (vp = vlist; vp; vp = vp->next) - if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) { - if (vp->status & EXPORT) - write(out, "export ", 7); - if (vp->status & RONLY) - write(out, "readonly ", 9); - write(out, vp->name, (int)(findeq(vp->name) - vp->name)); - write(out, "\n", 1); - } -} - -static int -eqname(n1, n2) -register char *n1, *n2; -{ - for (; *n1 != '=' && *n1 != 0; n1++) - if (*n2++ != *n1) - return(0); - return(*n2 == 0 || *n2 == '='); -} - -static char * -findeq(cp) -register char *cp; -{ - while (*cp != '\0' && *cp != '=') - cp++; - return(cp); -} - -/* -------- gmatch.c -------- */ -/* - * int gmatch(string, pattern) - * char *string, *pattern; - * - * Match a pattern as in sh(1). - */ - -#define CMASK 0377 -#define QUOTE 0200 -#define QMASK (CMASK&~QUOTE) -#define NOT '!' /* might use ^ */ - -static int -gmatch(s, p) -register char *s, *p; -{ - register int sc, pc; - - if (s == NULL || p == NULL) - return(0); - while ((pc = *p++ & CMASK) != '\0') { - sc = *s++ & QMASK; - switch (pc) { - case '[': - if ((p = cclass(p, sc)) == NULL) - return(0); - break; - - case '?': - if (sc == 0) - return(0); - break; - - case '*': - s--; - do { - if (*p == '\0' || gmatch(s, p)) - return(1); - } while (*s++ != '\0'); - return(0); - - default: - if (sc != (pc&~QUOTE)) - return(0); - } - } - return(*s == 0); -} - -static char * -cclass(p, sub) -register char *p; -register int sub; -{ - register int c, d, not, found; - - if ((not = *p == NOT) != 0) - p++; - found = not; - do { - if (*p == '\0') - return((char *)NULL); - c = *p & CMASK; - if (p[1] == '-' && p[2] != ']') { - d = p[2] & CMASK; - p++; - } else - d = c; - if (c == sub || (c <= sub && sub <= d)) - found = !not; - } while (*++p != ']'); - return(found? p+1: (char *)NULL); -} - - -/* -------- area.c -------- */ - -/* - * All memory between (char *)areabot and (char *)(areatop+1) is - * exclusively administered by the area management routines. - * It is assumed that sbrk() and brk() manipulate the high end. - */ - -#define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;}) - -static void -initarea() -{ - brkaddr = malloc(65000); - brktop = brkaddr + 65000; - - while ((int)sbrk(0) & ALIGN) - sbrk(1); - areabot = (struct region *)sbrk(REGSIZE); - - areabot->next = areabot; - areabot->area = BUSY; - areatop = areabot; - areanxt = areabot; -} - -char * -getcell(nbytes) -unsigned nbytes; -{ - register int nregio; - register struct region *p, *q; - register int i; - - if (nbytes == 0) { - puts("getcell(0)"); - abort(); - } /* silly and defeats the algorithm */ - /* - * round upwards and add administration area - */ - nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1; - for (p = areanxt;;) { - if (p->area > areanum) { - /* - * merge free cells - */ - while ((q = p->next)->area > areanum && q != areanxt) - p->next = q->next; - /* - * exit loop if cell big enough - */ - if (q >= p + nregio) - goto found; - } - p = p->next; - if (p == areanxt) - break; - } - i = nregio >= GROWBY ? nregio : GROWBY; - p = (struct region *)sbrk(i * REGSIZE); - if (p == (struct region *)-1) - return((char *)NULL); - p--; - if (p != areatop) { - puts("not contig"); - abort(); /* allocated areas are contiguous */ - } - q = p + i; - p->next = q; - p->area = FREE; - q->next = areabot; - q->area = BUSY; - areatop = q; -found: - /* - * we found a FREE area big enough, pointed to by 'p', and up to 'q' - */ - areanxt = p + nregio; - if (areanxt < q) { - /* - * split into requested area and rest - */ - if (areanxt+1 > q) { - puts("OOM"); - abort(); /* insufficient space left for admin */ - } - areanxt->next = q; - areanxt->area = FREE; - p->next = areanxt; - } - p->area = areanum; - return((char *)(p+1)); -} - -static void -freecell(cp) -char *cp; -{ - register struct region *p; - - if ((p = (struct region *)cp) != NULL) { - p--; - if (p < areanxt) - areanxt = p; - p->area = FREE; - } -} - -static void -freearea(a) -register int a; -{ - register struct region *p, *top; - - top = areatop; - for (p = areabot; p != top; p = p->next) - if (p->area >= a) - p->area = FREE; -} - -static void -setarea(cp,a) -char *cp; -int a; -{ - register struct region *p; - - if ((p = (struct region *)cp) != NULL) - (p-1)->area = a; -} - -int -getarea(cp) -char *cp; -{ - return ((struct region*)cp-1)->area; -} - -static void -garbage() -{ - register struct region *p, *q, *top; - - top = areatop; - for (p = areabot; p != top; p = p->next) { - if (p->area > areanum) { - while ((q = p->next)->area > areanum) - p->next = q->next; - areanxt = p; - } - } -#ifdef SHRINKBY - if (areatop >= q + SHRINKBY && q->area > areanum) { - brk((char *)(q+1)); - q->next = areabot; - q->area = BUSY; - areatop = q; - } -#endif -} - -/* -------- csyn.c -------- */ -/* - * shell: syntax (C version) - */ - - -int -yyparse() -{ - startl = 1; - peeksym = 0; - yynerrs = 0; - outtree = c_list(); - musthave('\n', 0); - return(yynerrs!=0); -} - -static struct op * -pipeline(cf) -int cf; -{ - register struct op *t, *p; - register int c; - - t = command(cf); - if (t != NULL) { - while ((c = yylex(0)) == '|') { - if ((p = command(CONTIN)) == NULL) - SYNTAXERR; - if (t->type != TPAREN && t->type != TCOM) { - /* shell statement */ - t = block(TPAREN, t, NOBLOCK, NOWORDS); - } - t = block(TPIPE, t, p, NOWORDS); - } - peeksym = c; - } - return(t); -} - -static struct op * -andor() -{ - register struct op *t, *p; - register int c; - - t = pipeline(0); - if (t != NULL) { - while ((c = yylex(0)) == LOGAND || c == LOGOR) { - if ((p = pipeline(CONTIN)) == NULL) - SYNTAXERR; - t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS); - } - peeksym = c; - } - return(t); -} - -static struct op * -c_list() -{ - register struct op *t, *p; - register int c; - - t = andor(); - if (t != NULL) { - if((peeksym = yylex(0)) == '&') - t = block(TASYNC, t, NOBLOCK, NOWORDS); - while ((c = yylex(0)) == ';' || c == '&' || (multiline && c == '\n')) { - if ((p = andor()) == NULL) - return(t); - if((peeksym = yylex(0)) == '&') - p = block(TASYNC, p, NOBLOCK, NOWORDS); - t = list(t, p); - } - peeksym = c; - } - return(t); -} - - -static int -synio(cf) -int cf; -{ - register struct ioword *iop; - register int i; - register int c; - - if ((c = yylex(cf)) != '<' && c != '>') { - peeksym = c; - return(0); - } - i = yylval.i; - musthave(WORD, 0); - iop = io(iounit, i, yylval.cp); - iounit = IODEFAULT; - if (i & IOHERE) - markhere(yylval.cp, iop); - return(1); -} - -static void -musthave(c, cf) -int c, cf; -{ - if ((peeksym = yylex(cf)) != c) - SYNTAXERR; - peeksym = 0; -} - -static struct op * -simple() -{ - register struct op *t; - - t = NULL; - for (;;) { - switch (peeksym = yylex(0)) { - case '<': - case '>': - (void) synio(0); - break; - - case WORD: - if (t == NULL) { - t = newtp(); - t->type = TCOM; - } - peeksym = 0; - word(yylval.cp); - break; - - default: - return(t); - } - } -} - -static struct op * -nested(type, mark) -int type, mark; -{ - register struct op *t; - - multiline++; - t = c_list(); - musthave(mark, 0); - multiline--; - return(block(type, t, NOBLOCK, NOWORDS)); -} - -static struct op * -command(cf) -int cf; -{ - register struct op *t; - struct wdblock *iosave; - register int c; - - iosave = iolist; - iolist = NULL; - if (multiline) - cf |= CONTIN; - while (synio(cf)) - cf = 0; - switch (c = yylex(cf)) { - default: - peeksym = c; - if ((t = simple()) == NULL) { - if (iolist == NULL) - return((struct op *)NULL); - t = newtp(); - t->type = TCOM; - } - break; - - case '(': - t = nested(TPAREN, ')'); - break; - - case '{': - t = nested(TBRACE, '}'); - break; - - case FOR: - t = newtp(); - t->type = TFOR; - musthave(WORD, 0); - startl = 1; - t->str = yylval.cp; - multiline++; - t->words = wordlist(); - if ((c = yylex(0)) != '\n' && c != ';') - peeksym = c; - t->left = dogroup(0); - multiline--; - break; - - case WHILE: - case UNTIL: - multiline++; - t = newtp(); - t->type = c == WHILE? TWHILE: TUNTIL; - t->left = c_list(); - t->right = dogroup(1); - t->words = NULL; - multiline--; - break; - - case CASE: - t = newtp(); - t->type = TCASE; - musthave(WORD, 0); - t->str = yylval.cp; - startl++; - multiline++; - musthave(IN, CONTIN); - startl++; - t->left = caselist(); - musthave(ESAC, 0); - multiline--; - break; - - case IF: - multiline++; - t = newtp(); - t->type = TIF; - t->left = c_list(); - t->right = thenpart(); - musthave(FI, 0); - multiline--; - break; - } - while (synio(0)) - ; - t = namelist(t); - iolist = iosave; - return(t); -} - -static struct op * -dogroup(onlydone) -int onlydone; -{ - register int c; - register struct op *mylist; - - c = yylex(CONTIN); - if (c == DONE && onlydone) - return((struct op *)NULL); - if (c != DO) - SYNTAXERR; - mylist = c_list(); - musthave(DONE, 0); - return(mylist); -} - -static struct op * -thenpart() -{ - register int c; - register struct op *t; - - if ((c = yylex(0)) != THEN) { - peeksym = c; - return((struct op *)NULL); - } - t = newtp(); - t->type = 0; - t->left = c_list(); - if (t->left == NULL) - SYNTAXERR; - t->right = elsepart(); - return(t); -} - -static struct op * -elsepart() -{ - register int c; - register struct op *t; - - switch (c = yylex(0)) { - case ELSE: - if ((t = c_list()) == NULL) - SYNTAXERR; - return(t); - - case ELIF: - t = newtp(); - t->type = TELIF; - t->left = c_list(); - t->right = thenpart(); - return(t); - - default: - peeksym = c; - return((struct op *)NULL); - } -} - -static struct op * -caselist() -{ - register struct op *t; - - t = NULL; - while ((peeksym = yylex(CONTIN)) != ESAC) - t = list(t, casepart()); - return(t); -} - -static struct op * -casepart() -{ - register struct op *t; - - t = newtp(); - t->type = TPAT; - t->words = pattern(); - musthave(')', 0); - t->left = c_list(); - if ((peeksym = yylex(CONTIN)) != ESAC) - musthave(BREAK, CONTIN); - return(t); -} - -static char ** -pattern() -{ - register int c, cf; - - cf = CONTIN; - do { - musthave(WORD, cf); - word(yylval.cp); - cf = 0; - } while ((c = yylex(0)) == '|'); - peeksym = c; - word(NOWORD); - return(copyw()); -} - -static char ** -wordlist() -{ - register int c; - - if ((c = yylex(0)) != IN) { - peeksym = c; - return((char **)NULL); - } - startl = 0; - while ((c = yylex(0)) == WORD) - word(yylval.cp); - word(NOWORD); - peeksym = c; - return(copyw()); -} - -/* - * supporting functions - */ -static struct op * -list(t1, t2) -register struct op *t1, *t2; -{ - if (t1 == NULL) - return(t2); - if (t2 == NULL) - return(t1); - return(block(TLIST, t1, t2, NOWORDS)); -} - -static struct op * -block(type, t1, t2, wp) -int type; -struct op *t1, *t2; -char **wp; -{ - register struct op *t; - - t = newtp(); - t->type = type; - t->left = t1; - t->right = t2; - t->words = wp; - return(t); -} - -static int -rlookup(n) -register char *n; -{ - register struct res *rp; - - for (rp = restab; rp->r_name; rp++) - if (strcmp(rp->r_name, n) == 0) - return(rp->r_val); - return(0); -} - -static struct op * -newtp() -{ - register struct op *t; - - t = (struct op *)tree(sizeof(*t)); - t->type = 0; - t->words = NULL; - t->ioact = NULL; - t->left = NULL; - t->right = NULL; - t->str = NULL; - return(t); -} - -static struct op * -namelist(t) -register struct op *t; -{ - if (iolist) { - iolist = addword((char *)NULL, iolist); - t->ioact = copyio(); - } else - t->ioact = NULL; - if (t->type != TCOM) { - if (t->type != TPAREN && t->ioact != NULL) { - t = block(TPAREN, t, NOBLOCK, NOWORDS); - t->ioact = t->left->ioact; - t->left->ioact = NULL; - } - return(t); - } - word(NOWORD); - t->words = copyw(); - return(t); -} - -static char ** -copyw() -{ - register char **wd; - - wd = getwords(wdlist); - wdlist = 0; - return(wd); -} - -static void -word(cp) -char *cp; -{ - wdlist = addword(cp, wdlist); -} - -static struct ioword ** -copyio() -{ - register struct ioword **iop; - - iop = (struct ioword **) getwords(iolist); - iolist = 0; - return(iop); -} - -static struct ioword * -io(u, f, cp) -int u; -int f; -char *cp; -{ - register struct ioword *iop; - - iop = (struct ioword *) tree(sizeof(*iop)); - iop->io_unit = u; - iop->io_flag = f; - iop->io_name = cp; - iolist = addword((char *)iop, iolist); - return(iop); -} - -static void -zzerr() -{ - yyerror("syntax error"); -} - -static void -yyerror(s) -char *s; -{ - yynerrs++; - if (interactive && e.iop <= iostack) { - multiline = 0; - while (eofc() == 0 && yylex(0) != '\n') - ; - } - err(s); - fail(); -} - -static int -yylex(cf) -int cf; -{ - register int c, c1; - int atstart; - - if ((c = peeksym) > 0) { - peeksym = 0; - if (c == '\n') - startl = 1; - return(c); - } - nlseen = 0; - e.linep = line; - atstart = startl; - startl = 0; - yylval.i = 0; - -loop: - while ((c = my_getc(0)) == ' ' || c == '\t') - ; - switch (c) { - default: - if (any(c, "0123456789")) { - unget(c1 = my_getc(0)); - if (c1 == '<' || c1 == '>') { - iounit = c - '0'; - goto loop; - } - *e.linep++ = c; - c = c1; - } - break; - - case '#': - while ((c = my_getc(0)) != 0 && c != '\n') - ; - unget(c); - goto loop; - - case 0: - return(c); - - case '$': - *e.linep++ = c; - if ((c = my_getc(0)) == '{') { - if ((c = collect(c, '}')) != '\0') - return(c); - goto pack; - } - break; - - case '`': - case '\'': - case '"': - if ((c = collect(c, c)) != '\0') - return(c); - goto pack; - - case '|': - case '&': - case ';': - if ((c1 = dual(c)) != '\0') { - startl = 1; - return(c1); - } - startl = 1; - return(c); - case '^': - startl = 1; - return('|'); - case '>': - case '<': - diag(c); - return(c); - - case '\n': - nlseen++; - gethere(); - startl = 1; - if (multiline || cf & CONTIN) { - if (interactive && e.iop <= iostack) { -#ifdef BB_FEATURE_COMMAND_EDITING - current_prompt=cprompt->value; -#else - prs(cprompt->value); -#endif - } - if (cf & CONTIN) - goto loop; - } - return(c); - - case '(': - case ')': - startl = 1; - return(c); - } - - unget(c); - -pack: - while ((c = my_getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n")) - if (e.linep >= elinep) - err("word too long"); - else - *e.linep++ = c; - unget(c); - if(any(c, "\"'`$")) - goto loop; - *e.linep++ = '\0'; - if (atstart && (c = rlookup(line))!=0) { - startl = 1; - return(c); - } - yylval.cp = strsave(line, areanum); - return(WORD); -} - -static int -collect(c, c1) -register int c, c1; -{ - char s[2]; - - *e.linep++ = c; - while ((c = my_getc(c1)) != c1) { - if (c == 0) { - unget(c); - s[0] = c1; - s[1] = 0; - prs("no closing "); yyerror(s); - return(YYERRCODE); - } - if (interactive && c == '\n' && e.iop <= iostack) { -#ifdef BB_FEATURE_COMMAND_EDITING - current_prompt=cprompt->value; -#else - prs(cprompt->value); -#endif - } - *e.linep++ = c; - } - *e.linep++ = c; - return(0); -} - -static int -dual(c) -register int c; -{ - char s[3]; - register char *cp = s; - - *cp++ = c; - *cp++ = my_getc(0); - *cp = 0; - if ((c = rlookup(s)) == 0) - unget(*--cp); - return(c); -} - -static void -diag(ec) -register int ec; -{ - register int c; - - c = my_getc(0); - if (c == '>' || c == '<') { - if (c != ec) - zzerr(); - yylval.i = ec == '>'? IOWRITE|IOCAT: IOHERE; - c = my_getc(0); - } else - yylval.i = ec == '>'? IOWRITE: IOREAD; - if (c != '&' || yylval.i == IOHERE) - unget(c); - else - yylval.i |= IODUP; -} - -static char * -tree(size) -unsigned size; -{ - register char *t; - - if ((t = getcell(size)) == NULL) { - prs("command line too complicated\n"); - fail(); - /* NOTREACHED */ - } - return(t); -} - -/* VARARGS1 */ -/* ARGSUSED */ - -/* -------- exec.c -------- */ - -/* - * execute tree - */ - - -static int -execute(t, pin, pout, act) -register struct op *t; -int *pin, *pout; -int act; -{ - register struct op *t1; - volatile int i, rv, a; - char *cp, **wp, **wp2; - struct var *vp; - struct brkcon bc; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) ℘ -#endif - - - if (t == NULL) - return(0); - rv = 0; - a = areanum++; - wp = (wp2 = t->words) != NULL - ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY) - : NULL; - - switch(t->type) { - case TPAREN: - case TCOM: - { - int child; - rv = forkexec(t, pin, pout, act, wp, &child); - if (child) { - exstat = rv; - leave(); - } - } - break; - - case TPIPE: - { - int pv[2]; - if ((rv = openpipe(pv)) < 0) - break; - pv[0] = remap(pv[0]); - pv[1] = remap(pv[1]); - (void) execute(t->left, pin, pv, 0); - rv = execute(t->right, pv, pout, 0); - } - break; - - case TLIST: - (void) execute(t->left, pin, pout, 0); - rv = execute(t->right, pin, pout, 0); - break; - - case TASYNC: - { - int hinteractive = interactive; - - i = vfork(); - if (i != 0) { - interactive = hinteractive; - if (i != -1) { - setval(lookup("!"), putn(i)); - if (pin != NULL) - closepipe(pin); - if (interactive) { - prs(putn(i)); - prs("\n"); - } - } else - rv = -1; - setstatus(rv); - } else { - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - if (interactive) - signal(SIGTERM, SIG_DFL); - interactive = 0; - if (pin == NULL) { - close(0); - open("/dev/null", 0); - } - exit(execute(t->left, pin, pout, FEXEC)); - } - } - break; - - case TOR: - case TAND: - rv = execute(t->left, pin, pout, 0); - if ((t1 = t->right)!=NULL && (rv == 0) == (t->type == TAND)) - rv = execute(t1, pin, pout, 0); - break; - - case TFOR: - if (wp == NULL) { - wp = dolv+1; - if ((i = dolc) < 0) - i = 0; - } else { - i = -1; - while (*wp++ != NULL) - ; - } - vp = lookup(t->str); - while (setjmp(bc.brkpt)) - if (isbreak) - goto broken; - brkset(&bc); - for (t1 = t->left; i-- && *wp != NULL;) { - setval(vp, *wp++); - rv = execute(t1, pin, pout, 0); - } - brklist = brklist->nextlev; - break; - - case TWHILE: - case TUNTIL: - while (setjmp(bc.brkpt)) - if (isbreak) - goto broken; - brkset(&bc); - t1 = t->left; - while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE)) - rv = execute(t->right, pin, pout, 0); - brklist = brklist->nextlev; - break; - - case TIF: - case TELIF: - if (t->right != NULL) { - rv = !execute(t->left, pin, pout, 0) ? - execute(t->right->left, pin, pout, 0): - execute(t->right->right, pin, pout, 0); - } - break; - - case TCASE: - if ((cp = evalstr(t->str, DOSUB|DOTRIM)) == 0) - cp = ""; - if ((t1 = findcase(t->left, cp)) != NULL) - rv = execute(t1, pin, pout, 0); - break; - - case TBRACE: -/* - if (iopp = t->ioact) - while (*iopp) - if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) { - rv = -1; - break; - } -*/ - if (rv >= 0 && (t1 = t->left)) - rv = execute(t1, pin, pout, 0); - break; - } - -broken: - t->words = wp2; - isbreak = 0; - freehere(areanum); - freearea(areanum); - areanum = a; - if (interactive && intr) { - closeall(); - fail(); - } - if ((i = trapset) != 0) { - trapset = 0; - runtrap(i); - } - return(rv); -} - -static int -forkexec( register struct op *t, int *pin, int *pout, int act, char **wp, int *pforked) -{ - int i, rv; - int (*shcom)() = NULL; - register int f; - char *cp = NULL; - struct ioword **iopp; - int resetsig; - char **owp; - - int *hpin = pin; - int *hpout = pout; - int hforked; - char *hwp; - int hinteractive; - int hintr; - struct brkcon * hbrklist; - int hexecflg; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &pin; - (void) &pout; - (void) ℘ - (void) &shcom; - (void) &cp; - (void) &resetsig; - (void) &owp; -#endif - - owp = wp; - resetsig = 0; - *pforked = 0; - rv = -1; /* system-detected error */ - if (t->type == TCOM) { - while ((cp = *wp++) != NULL) - ; - cp = *wp; - - /* strip all initial assignments */ - /* not correct wrt PATH=yyy command etc */ - if (flag['x']) - echo (cp ? wp: owp); - if (cp == NULL && t->ioact == NULL) { - while ((cp = *owp++) != NULL && assign(cp, COPYV)) - ; - return(setstatus(0)); - } - else if (cp != NULL) - shcom = inbuilt(cp); - } - t->words = wp; - f = act; - if (shcom == NULL && (f & FEXEC) == 0) { - - hpin = pin; - hpout = pout; - hforked = *pforked; - hwp = *wp; - hinteractive = interactive; - hintr = intr; - hbrklist = brklist; - hexecflg = execflg; - - i = vfork(); - if (i != 0) { - /* who wrote this crappy non vfork safe shit? */ - pin = hpin; - pout = hpout; - *pforked = hforked; - *wp = hwp; - interactive = hinteractive; - intr = hintr; - brklist = hbrklist; - execflg = hexecflg; - - *pforked = 0; - if (i == -1) - return(rv); - if (pin != NULL) - closepipe(pin); - return(pout==NULL? setstatus(waitfor(i,0)): 0); - } - - if (interactive) { - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - resetsig = 1; - } - interactive = 0; - intr = 0; - (*pforked)++; - brklist = 0; - execflg = 0; - } - if (owp != NULL) - while ((cp = *owp++) != NULL && assign(cp, COPYV)) - if (shcom == NULL) - export(lookup(cp)); -#ifdef COMPIPE - if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) { - err("piping to/from shell builtins not yet done"); - return(-1); - } -#endif - if (pin != NULL) { - dup2(pin[0], 0); - closepipe(pin); - } - if (pout != NULL) { - dup2(pout[1], 1); - closepipe(pout); - } - if ((iopp = t->ioact) != NULL) { - if (shcom != NULL && shcom != doexec) { - prs(cp); - err(": cannot redirect shell command"); - return(-1); - } - while (*iopp) - if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) - return(rv); - } - if (shcom) - return(setstatus((*shcom)(t))); - /* should use FIOCEXCL */ - for (i=FDBASE; itype == TPAREN) - exit(execute(t->left, NOPIPE, NOPIPE, FEXEC)); - if (wp[0] == NULL) - exit(0); - - cp = rexecve(wp[0], wp, makenv()); - prs(wp[0]); prs(": "); warn(cp); - if (!execflg) - trap[0] = NULL; - leave(); - /* NOTREACHED */ - exit(1); -} - -/* - * 0< 1> are ignored as required - * within pipelines. - */ -static int -iosetup(iop, pipein, pipeout) -register struct ioword *iop; -int pipein, pipeout; -{ - register int u = -1; - char *cp=NULL, *msg; - - if (iop->io_unit == IODEFAULT) /* take default */ - iop->io_unit = iop->io_flag&(IOREAD|IOHERE)? 0: 1; - if (pipein && iop->io_unit == 0) - return(0); - if (pipeout && iop->io_unit == 1) - return(0); - msg = iop->io_flag&(IOREAD|IOHERE)? "open": "create"; - if ((iop->io_flag & IOHERE) == 0) { - cp = iop->io_name; - if ((cp = evalstr(cp, DOSUB|DOTRIM)) == NULL) - return(1); - } - if (iop->io_flag & IODUP) { - if (cp[1] || (!isdigit(*cp) && *cp != '-')) { - prs(cp); - err(": illegal >& argument"); - return(1); - } - if (*cp == '-') - iop->io_flag = IOCLOSE; - iop->io_flag &= ~(IOREAD|IOWRITE); - } - switch (iop->io_flag) { - case IOREAD: - u = open(cp, 0); - break; - - case IOHERE: - case IOHERE|IOXHERE: - u = herein(iop->io_name, iop->io_flag&IOXHERE); - cp = "here file"; - break; - - case IOWRITE|IOCAT: - if ((u = open(cp, 1)) >= 0) { - lseek(u, (long)0, 2); - break; - } - case IOWRITE: - u = creat(cp, 0666); - break; - - case IODUP: - u = dup2(*cp-'0', iop->io_unit); - break; - - case IOCLOSE: - close(iop->io_unit); - return(0); - } - if (u < 0) { - prs(cp); - prs(": cannot "); - warn(msg); - return(1); - } else { - if (u != iop->io_unit) { - dup2(u, iop->io_unit); - close(u); - } - } - return(0); -} - -static void -echo(wp) -register char **wp; -{ - register int i; - - prs("+"); - for (i=0; wp[i]; i++) { - if (i) - prs(" "); - prs(wp[i]); - } - prs("\n"); -} - -static struct op ** -find1case(t, w) -struct op *t; -char *w; -{ - register struct op *t1; - struct op **tp; - register char **wp, *cp; - - if (t == NULL) - return((struct op **)NULL); - if (t->type == TLIST) { - if ((tp = find1case(t->left, w)) != NULL) - return(tp); - t1 = t->right; /* TPAT */ - } else - t1 = t; - for (wp = t1->words; *wp;) - if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp)) - return(&t1->left); - return((struct op **)NULL); -} - -static struct op * -findcase(t, w) -struct op *t; -char *w; -{ - register struct op **tp; - - return((tp = find1case(t, w)) != NULL? *tp: (struct op *)NULL); -} - -/* - * Enter a new loop level (marked for break/continue). - */ -static void -brkset(bc) -struct brkcon *bc; -{ - bc->nextlev = brklist; - brklist = bc; -} - -/* - * Wait for the last process created. - * Print a message for each process found - * that was killed by a signal. - * Ignore interrupt signals while waiting - * unless `canintr' is true. - */ -static int -waitfor(lastpid, canintr) -register int lastpid; -int canintr; -{ - register int pid, rv; - int s; - int oheedint = heedint; - - heedint = 0; - rv = 0; - do { - pid = wait(&s); - if (pid == -1) { - if (errno != EINTR || canintr) - break; - } else { - if ((rv = WAITSIG(s)) != 0) { - if (rv < NSIGNAL) { - if (signame[rv] != NULL) { - if (pid != lastpid) { - prn(pid); - prs(": "); - } - prs(signame[rv]); - } - } else { - if (pid != lastpid) { - prn(pid); - prs(": "); - } - prs("Signal "); prn(rv); prs(" "); - } - if (WAITCORE(s)) - prs(" - core dumped"); - if (rv >= NSIGNAL || signame[rv]) - prs("\n"); - rv = -1; - } else - rv = WAITVAL(s); - } - } while (pid != lastpid); - heedint = oheedint; - if (intr) { - if (interactive) { - if (canintr) - intr = 0; - } else { - if (exstat == 0) exstat = rv; - onintr(0); - } - } - return(rv); -} - -static int -setstatus(s) -register int s; -{ - exstat = s; - setval(lookup("?"), putn(s)); - return(s); -} - -/* - * PATH-searching interface to execve. - * If getenv("PATH") were kept up-to-date, - * execvp might be used. - */ -static char * -rexecve(c, v, envp) -char *c, **v, **envp; -{ - register int i; - register char *sp, *tp; - int eacces = 0, asis = 0; - -#ifdef BB_FEATURE_SH_STANDALONE_SHELL - char *name = c; -#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN - name = get_last_path_component(name); -#endif - optind = 1; - if (find_applet_by_name(name)) { - /* We have to exec here since we vforked. Running - * run_applet_by_name() won't work and bad things - * will happen. */ - execve("/proc/self/exe", v, envp); - execve("busybox", v, envp); - } -#endif - - sp = any('/', c)? "": path->value; - asis = *sp == '\0'; - while (asis || *sp != '\0') { - asis = 0; - tp = e.linep; - for (; *sp != '\0'; tp++) - if ((*tp = *sp++) == ':') { - asis = *sp == '\0'; - break; - } - if (tp != e.linep) - *tp++ = '/'; - for (i = 0; (*tp++ = c[i++]) != '\0';) - ; - - execve(e.linep, v, envp); - switch (errno) { - case ENOEXEC: - *v = e.linep; - tp = *--v; - *v = e.linep; - execve("/bin/sh", v, envp); - *v = tp; - return("no Shell"); - - case ENOMEM: - return("program too big"); - - case E2BIG: - return("argument list too long"); - - case EACCES: - eacces++; - break; - } - } - return(errno==ENOENT ? "not found" : "cannot execute"); -} - -/* - * Run the command produced by generator `f' - * applied to stream `arg'. - */ -static int -run(argp, f) -struct ioarg *argp; -int (*f)(); -{ - struct op *otree; - struct wdblock *swdlist; - struct wdblock *siolist; - jmp_buf ev, rt; - xint *ofail; - int rv; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &rv; -#endif - - areanum++; - swdlist = wdlist; - siolist = iolist; - otree = outtree; - ofail = failpt; - rv = -1; - if (newenv(setjmp(errpt = ev)) == 0) { - wdlist = 0; - iolist = 0; - pushio(argp, f); - e.iobase = e.iop; - yynerrs = 0; - if (setjmp(failpt = rt) == 0 && yyparse() == 0) - rv = execute(outtree, NOPIPE, NOPIPE, 0); - quitenv(); - } - wdlist = swdlist; - iolist = siolist; - failpt = ofail; - outtree = otree; - freearea(areanum--); - return(rv); -} - -/* -------- do.c -------- */ - -/* - * built-in commands: doX - */ - -static int dohelp() -{ - int col; - const struct builtincmd *x; - - printf("\nBuilt-in commands:\n"); - printf("-------------------\n"); - - for (col=0, x = builtincmds; x->builtinfunc != NULL; x++) { - if (!x->name) - continue; - col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name); - if (col > 60) { - printf("\n"); - col = 0; - } - } -#ifdef BB_FEATURE_SH_STANDALONE_SHELL - { - int i; - const struct BB_applet *applet; - extern const struct BB_applet applets[]; - extern const size_t NUM_APPLETS; - - for (i=0, applet = applets; i < NUM_APPLETS; applet++, i++) { - if (!applet->name) - continue; - - col += printf("%s%s", ((col == 0) ? "\t" : " "), - applet->name); - if (col > 60) { - printf("\n"); - col = 0; - } - } - } -#endif - printf("\n\n"); - return EXIT_SUCCESS; -} - - - -static int -dolabel() -{ - return(0); -} - -static int -dochdir(t) -register struct op *t; -{ - register char *cp, *er; - - if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL) - er = ": no home directory"; - else if(chdir(cp) < 0) - er = ": bad directory"; - else - return(0); - prs(cp != NULL? cp: "cd"); - err(er); - return(1); -} - -static int -doshift(t) -register struct op *t; -{ - register int n; - - n = t->words[1]? getn(t->words[1]): 1; - if(dolc < n) { - err("nothing to shift"); - return(1); - } - dolv[n] = dolv[0]; - dolv += n; - dolc -= n; - setval(lookup("#"), putn(dolc)); - return(0); -} - -/* - * execute login and newgrp directly - */ -static int -dologin(t) -struct op *t; -{ - register char *cp; - - if (interactive) { - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - } - cp = rexecve(t->words[0], t->words, makenv()); - prs(t->words[0]); prs(": "); err(cp); - return(1); -} - -static int -doumask(t) -register struct op *t; -{ - register int i, n; - register char *cp; - - if ((cp = t->words[1]) == NULL) { - i = umask(0); - umask(i); - for (n=3*4; (n-=3) >= 0;) - putc('0'+((i>>n)&07), stderr); - putc('\n', stderr); - } else { - for (n=0; *cp>='0' && *cp<='9'; cp++) - n = n*8 + (*cp-'0'); - umask(n); - } - return(0); -} - -static int -doexec(t) -register struct op *t; -{ - register int i; - jmp_buf ex; - xint *ofail; - - t->ioact = NULL; - for(i = 0; (t->words[i]=t->words[i+1]) != NULL; i++) - ; - if (i == 0) - return(1); - execflg = 1; - ofail = failpt; - if (setjmp(failpt = ex) == 0) - execute(t, NOPIPE, NOPIPE, FEXEC); - failpt = ofail; - execflg = 0; - return(1); -} - -static int -dodot(t) -struct op *t; -{ - register int i; - register char *sp, *tp; - char *cp; - - if ((cp = t->words[1]) == NULL) - return(0); - sp = any('/', cp)? ":": path->value; - while (*sp) { - tp = e.linep; - while (*sp && (*tp = *sp++) != ':') - tp++; - if (tp != e.linep) - *tp++ = '/'; - for (i = 0; (*tp++ = cp[i++]) != '\0';) - ; - if ((i = open(e.linep, 0)) >= 0) { - exstat = 0; - next(remap(i)); - return(exstat); - } - } - prs(cp); - err(": not found"); - return(-1); -} - -static int -dowait(t) -struct op *t; -{ - register int i; - register char *cp; - - if ((cp = t->words[1]) != NULL) { - i = getn(cp); - if (i == 0) - return(0); - } else - i = -1; - setstatus(waitfor(i, 1)); - return(0); -} - -static int -doread(t) -struct op *t; -{ - register char *cp, **wp; - register int nb = 0; - register int nl = 0; - - if (t->words[1] == NULL) { - err("Usage: read name ..."); - return(1); - } - for (wp = t->words+1; *wp; wp++) { - for (cp = e.linep; !nl && cp < elinep-1; cp++) - if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) || - (nl = (*cp == '\n')) || - (wp[1] && any(*cp, ifs->value))) - break; - *cp = 0; - if (nb <= 0) - break; - setval(lookup(*wp), e.linep); - } - return(nb <= 0); -} - -static int -doeval(t) -register struct op *t; -{ - return(RUN(awordlist, t->words+1, wdchar)); -} - -static int -dotrap(t) -register struct op *t; -{ - register int n, i; - register int resetsig; - - if (t->words[1] == NULL) { - for (i=0; i<=_NSIG; i++) - if (trap[i]) { - prn(i); - prs(": "); - prs(trap[i]); - prs("\n"); - } - return(0); - } - resetsig = isdigit(*t->words[1]); - for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) { - n = getsig(t->words[i]); - freecell(trap[n]); - trap[n] = 0; - if (!resetsig) { - if (*t->words[1] != '\0') { - trap[n] = strsave(t->words[1], 0); - setsig(n, sig); - } else - setsig(n, SIG_IGN); - } else { - if (interactive) - if (n == SIGINT) - setsig(n, onintr); - else - setsig(n, n == SIGQUIT ? SIG_IGN - : SIG_DFL); - else - setsig(n, SIG_DFL); - } - } - return(0); -} - -static int -getsig(s) -char *s; -{ - register int n; - - if ((n = getn(s)) < 0 || n > _NSIG) { - err("trap: bad signal number"); - n = 0; - } - return(n); -} - -static void -setsig( register int n, void (*f)(int)) -{ - if (n == 0) - return; - if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) { - ourtrap[n] = 1; - signal(n, f); - } -} - -static int -getn(as) -char *as; -{ - register char *s; - register int n, m; - - s = as; - m = 1; - if (*s == '-') { - m = -1; - s++; - } - for (n = 0; isdigit(*s); s++) - n = (n*10) + (*s-'0'); - if (*s) { - prs(as); - err(": bad number"); - } - return(n*m); -} - -static int -dobreak(t) -struct op *t; -{ - return(brkcontin(t->words[1], 1)); -} - -static int -docontinue(t) -struct op *t; -{ - return(brkcontin(t->words[1], 0)); -} - -static int -brkcontin(cp, val) -register char *cp; -int val; -{ - register struct brkcon *bc; - register int nl; - - nl = cp == NULL? 1: getn(cp); - if (nl <= 0) - nl = 999; - do { - if ((bc = brklist) == NULL) - break; - brklist = bc->nextlev; - } while (--nl); - if (nl) { - err("bad break/continue level"); - return(1); - } - isbreak = val; - longjmp(bc->brkpt, 1); - /* NOTREACHED */ -} - -static int -doexit(t) -struct op *t; -{ - register char *cp; - - execflg = 0; - if ((cp = t->words[1]) != NULL) - setstatus(getn(cp)); - leave(); - /* NOTREACHED */ - return(0); -} - -static int -doexport(t) -struct op *t; -{ - rdexp(t->words+1, export, EXPORT); - return(0); -} - -static int -doreadonly(t) -struct op *t; -{ - rdexp(t->words+1, ronly, RONLY); - return(0); -} - -static void -rdexp(wp, f, key) -register char **wp; -void (*f)(); -int key; -{ - if (*wp != NULL) { - for (; *wp != NULL; wp++) { - if (isassign(*wp)) { - char *cp; - assign(*wp, COPYV); - for (cp = *wp; *cp != '='; cp++) - ; - *cp = '\0'; - } - if (checkname(*wp)) - (*f)(lookup(*wp)); - else - badid(*wp); - } - } else - putvlist(key, 1); -} - -static void -badid(s) -register char *s; -{ - prs(s); - err(": bad identifier"); -} - -static int -doset(t) -register struct op *t; -{ - register struct var *vp; - register char *cp; - register int n; - - if ((cp = t->words[1]) == NULL) { - for (vp = vlist; vp; vp = vp->next) - varput(vp->name, 1); - return(0); - } - if (*cp == '-') { - /* bad: t->words++; */ - for(n = 0; (t->words[n]=t->words[n+1]) != NULL; n++) - ; - if (*++cp == 0) - flag['x'] = flag['v'] = 0; - else - for (; *cp; cp++) - switch (*cp) { - case 'e': - if (!interactive) - flag['e']++; - break; - - default: - if (*cp>='a' && *cp<='z') - flag[(int)*cp]++; - break; - } - setdash(); - } - if (t->words[1]) { - t->words[0] = dolv[0]; - for (n=1; t->words[n]; n++) - setarea((char *)t->words[n], 0); - dolc = n-1; - dolv = t->words; - setval(lookup("#"), putn(dolc)); - setarea((char *)(dolv-1), 0); - } - return(0); -} - -static void -varput(s, out) -register char *s; -int out; -{ - if (isalnum(*s) || *s == '_') { - write(out, s, strlen(s)); - write(out, "\n", 1); - } -} - - -/* - * Copyright (c) 1999 Herbert Xu - * This file contains code for the times builtin. - */ -static int dotimes () -{ - struct tms buf; - long int clk_tck = sysconf(_SC_CLK_TCK); - - times(&buf); - printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", - (int) (buf.tms_utime / clk_tck / 60), - ((double) buf.tms_utime) / clk_tck, - (int) (buf.tms_stime / clk_tck / 60), - ((double) buf.tms_stime) / clk_tck, - (int) (buf.tms_cutime / clk_tck / 60), - ((double) buf.tms_cutime) / clk_tck, - (int) (buf.tms_cstime / clk_tck / 60), - ((double) buf.tms_cstime) / clk_tck); - return 0; -} - - -static int (*inbuilt(char *s))() -{ - const struct builtincmd *bp; - - for (bp = builtincmds; bp->name != NULL; bp++) - if (strcmp(bp->name, s) == 0) - return(bp->builtinfunc); - - return((int(*)())NULL); -} - -/* -------- eval.c -------- */ - -/* - * ${} - * `command` - * blank interpretation - * quoting - * glob - */ - -static char ** eval( char **ap, int f) -{ - struct wdblock *wb; - char **wp; - char **wf; - jmp_buf ev; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) ℘ - (void) ≈ -#endif - wp = NULL; - wb = NULL; - wf = NULL; - if (newenv(setjmp(errpt = ev)) == 0) { - while (*ap && isassign(*ap)) - expand(*ap++, &wb, f & ~DOGLOB); - if (flag['k']) { - for (wf = ap; *wf; wf++) { - if (isassign(*wf)) - expand(*wf, &wb, f & ~DOGLOB); - } - } - for (wb = addword((char *)0, wb); *ap; ap++) { - if (!flag['k'] || !isassign(*ap)) - expand(*ap, &wb, f & ~DOKEY); - } - wb = addword((char *)0, wb); - wp = getwords(wb); - quitenv(); - } else - gflg = 1; - return(gflg? (char **)NULL: wp); -} - -/* - * Make the exported environment from the exported - * names in the dictionary. Keyword assignments - * will already have been done. - */ -static char ** -makenv() - -{ - register struct wdblock *wb; - register struct var *vp; - - wb = NULL; - for (vp = vlist; vp; vp = vp->next) - if (vp->status & EXPORT) - wb = addword(vp->name, wb); - wb = addword((char *)0, wb); - return(getwords(wb)); -} - -static char * -evalstr(cp, f) -register char *cp; -int f; -{ - struct wdblock *wb; - - wb = NULL; - if (expand(cp, &wb, f)) { - if (wb == NULL || wb->w_nword == 0 || (cp = wb->w_words[0]) == NULL) - cp = ""; - DELETE(wb); - } else - cp = NULL; - return(cp); -} - -static int -expand( char *cp, register struct wdblock **wbp, int f) -{ - jmp_buf ev; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &cp; -#endif - gflg = 0; - if (cp == NULL) - return(0); - if (!anys("$`'\"", cp) && - !anys(ifs->value, cp) && - ((f&DOGLOB)==0 || !anys("[*?", cp))) { - cp = strsave(cp, areanum); - if (f & DOTRIM) - unquote(cp); - *wbp = addword(cp, *wbp); - return(1); - } - if (newenv(setjmp(errpt = ev)) == 0) { - PUSHIO(aword, cp, strchar); - e.iobase = e.iop; - while ((cp = blank(f)) && gflg == 0) { - e.linep = cp; - cp = strsave(cp, areanum); - if ((f&DOGLOB) == 0) { - if (f & DOTRIM) - unquote(cp); - *wbp = addword(cp, *wbp); - } else - *wbp = glob(cp, *wbp); - } - quitenv(); - } else - gflg = 1; - return(gflg == 0); -} - -/* - * Blank interpretation and quoting - */ -static char * -blank(f) -int f; -{ - register int c, c1; - register char *sp; - int scanequals, foundequals; - - sp = e.linep; - scanequals = f & DOKEY; - foundequals = 0; - -loop: - switch (c = subgetc('"', foundequals)) { - case 0: - if (sp == e.linep) - return(0); - *e.linep++ = 0; - return(sp); - - default: - if (f & DOBLANK && any(c, ifs->value)) - goto loop; - break; - - case '"': - case '\'': - scanequals = 0; - if (INSUB()) - break; - for (c1 = c; (c = subgetc(c1, 1)) != c1;) { - if (c == 0) - break; - if (c == '\'' || !any(c, "$`\"")) - c |= QUOTE; - *e.linep++ = c; - } - c = 0; - } - unget(c); - if (!isalpha(c) && c != '_') - scanequals = 0; - for (;;) { - c = subgetc('"', foundequals); - if (c == 0 || - f & (DOBLANK && any(c, ifs->value)) || - (!INSUB() && any(c, "\"'"))) { - scanequals = 0; - unget(c); - if (any(c, "\"'")) - goto loop; - break; - } - if (scanequals) { - if (c == '=') { - foundequals = 1; - scanequals = 0; - } - else if (!isalnum(c) && c != '_') - scanequals = 0; - } - *e.linep++ = c; - } - *e.linep++ = 0; - return(sp); -} - -/* - * Get characters, substituting for ` and $ - */ -static int -subgetc(ec, quoted) -register int ec; -int quoted; -{ - register char c; - -again: - c = my_getc(ec); - if (!INSUB() && ec != '\'') { - if (c == '`') { - if (grave(quoted) == 0) - return(0); - e.iop->task = XGRAVE; - goto again; - } - if (c == '$' && (c = dollar(quoted)) == 0) { - e.iop->task = XDOLL; - goto again; - } - } - return(c); -} - -/* - * Prepare to generate the string returned by ${} substitution. - */ -static int -dollar(quoted) -int quoted; -{ - int otask; - struct io *oiop; - char *dolp; - register char *s, c, *cp=NULL; - struct var *vp; - - c = readc(); - s = e.linep; - if (c != '{') { - *e.linep++ = c; - if (isalpha(c) || c == '_') { - while ((c = readc())!=0 && (isalnum(c) || c == '_')) - if (e.linep < elinep) - *e.linep++ = c; - unget(c); - } - c = 0; - } else { - oiop = e.iop; - otask = e.iop->task; - e.iop->task = XOTHER; - while ((c = subgetc('"', 0))!=0 && c!='}' && c!='\n') - if (e.linep < elinep) - *e.linep++ = c; - if (oiop == e.iop) - e.iop->task = otask; - if (c != '}') { - err("unclosed ${"); - gflg++; - return(c); - } - } - if (e.linep >= elinep) { - err("string in ${} too long"); - gflg++; - e.linep -= 10; - } - *e.linep = 0; - if (*s) - for (cp = s+1; *cp; cp++) - if (any(*cp, "=-+?")) { - c = *cp; - *cp++ = 0; - break; - } - if (s[1] == 0 && (*s == '*' || *s == '@')) { - if (dolc > 1) { - /* currently this does not distinguish $* and $@ */ - /* should check dollar */ - e.linep = s; - PUSHIO(awordlist, dolv+1, dolchar); - return(0); - } else { /* trap the nasty ${=} */ - s[0] = '1'; - s[1] = 0; - } - } - vp = lookup(s); - if ((dolp = vp->value) == null) { - switch (c) { - case '=': - if (isdigit(*s)) { - err("cannot use ${...=...} with $n"); - gflg++; - break; - } - setval(vp, cp); - dolp = vp->value; - break; - - case '-': - dolp = strsave(cp, areanum); - break; - - case '?': - if (*cp == 0) { - prs("missing value for "); - err(s); - } else - err(cp); - gflg++; - break; - } - } else if (c == '+') - dolp = strsave(cp, areanum); - if (flag['u'] && dolp == null) { - prs("unset variable: "); - err(s); - gflg++; - } - e.linep = s; - PUSHIO(aword, dolp, quoted ? qstrchar : strchar); - return(0); -} - -/* - * Run the command in `...` and read its output. - */ -static int -grave(quoted) -int quoted; -{ - register int i; - char *cp; - int pf[2]; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &cp; -#endif - for (cp = e.iop->argp->aword; *cp != '`'; cp++) - if (*cp == 0) { - err("no closing `"); - return(0); - } - if (openpipe(pf) < 0) - return(0); - if ((i = vfork()) == -1) { - closepipe(pf); - err("try again"); - return(0); - } - if (i != 0) { - e.iop->argp->aword = ++cp; - close(pf[1]); - PUSHIO(afile, remap(pf[0]), quoted? qgravechar: gravechar); - return(1); - } - *cp = 0; - /* allow trapped signals */ - for (i=0; i<=_NSIG; i++) - if (ourtrap[i] && signal(i, SIG_IGN) != SIG_IGN) - signal(i, SIG_DFL); - dup2(pf[1], 1); - closepipe(pf); - flag['e'] = 0; - flag['v'] = 0; - flag['n'] = 0; - cp = strsave(e.iop->argp->aword, 0); - areanum = 1; - freehere(areanum); - freearea(areanum); /* free old space */ - e.oenv = NULL; - e.iop = (e.iobase = iostack) - 1; - unquote(cp); - interactive = 0; - PUSHIO(aword, cp, nlchar); - onecommand(); - exit(1); -} - -static char * -unquote(as) -register char *as; -{ - register char *s; - - if ((s = as) != NULL) - while (*s) - *s++ &= ~QUOTE; - return(as); -} - -/* -------- glob.c -------- */ - -/* - * glob - */ - -#define scopy(x) strsave((x), areanum) -#define BLKSIZ 512 -#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent)) - -static struct wdblock *cl, *nl; -static char spcl[] = "[?*"; - -static struct wdblock * -glob(cp, wb) -char *cp; -struct wdblock *wb; -{ - register int i; - register char *pp; - - if (cp == 0) - return(wb); - i = 0; - for (pp = cp; *pp; pp++) - if (any(*pp, spcl)) - i++; - else if (!any(*pp & ~QUOTE, spcl)) - *pp &= ~QUOTE; - if (i != 0) { - for (cl = addword(scopy(cp), (struct wdblock *)0); anyspcl(cl); cl = nl) { - nl = newword(cl->w_nword*2); - for(i=0; iw_nword; i++) { /* for each argument */ - for (pp = cl->w_words[i]; *pp; pp++) - if (any(*pp, spcl)) { - globname(cl->w_words[i], pp); - break; - } - if (*pp == '\0') - nl = addword(scopy(cl->w_words[i]), nl); - } - for(i=0; iw_nword; i++) - DELETE(cl->w_words[i]); - DELETE(cl); - } - for(i=0; iw_nword; i++) - unquote(cl->w_words[i]); - glob0((char *)cl->w_words, cl->w_nword, sizeof(char *), xstrcmp); - if (cl->w_nword) { - for (i=0; iw_nword; i++) - wb = addword(cl->w_words[i], wb); - DELETE(cl); - return(wb); - } - } - wb = addword(unquote(cp), wb); - return(wb); -} - -static void -globname(we, pp) -char *we; -register char *pp; -{ - register char *np, *cp; - char *name, *gp, *dp; - int k; - DIR *dirp; - struct dirent *de; - char dname[NAME_MAX+1]; - struct stat dbuf; - - for (np = we; np != pp; pp--) - if (pp[-1] == '/') - break; - for (dp = cp = space((int)(pp-np)+3); np < pp;) - *cp++ = *np++; - *cp++ = '.'; - *cp = '\0'; - for (gp = cp = space(strlen(pp)+1); *np && *np != '/';) - *cp++ = *np++; - *cp = '\0'; - dirp = opendir(dp); - if (dirp == 0) { - DELETE(dp); - DELETE(gp); - return; - } - dname[NAME_MAX] = '\0'; - while ((de=readdir(dirp))!=NULL) { - /* XXX Hmmm... What this could be? (abial) */ - /* - if (ent[j].d_ino == 0) - continue; - */ - strncpy(dname, de->d_name, NAME_MAX); - if (dname[0] == '.') - if (*gp != '.') - continue; - for(k=0; kw_words; - for (i=0; iw_nword; i++) - if (anys(spcl, *wd++)) - return(1); - return(0); -} - -static int -xstrcmp(p1, p2) -char *p1, *p2; -{ - return(strcmp(*(char **)p1, *(char **)p2)); -} - -/* -------- word.c -------- */ - -static struct wdblock * -newword(nw) -register int nw; -{ - register struct wdblock *wb; - - wb = (struct wdblock *) space(sizeof(*wb) + nw*sizeof(char *)); - wb->w_bsize = nw; - wb->w_nword = 0; - return(wb); -} - -static struct wdblock * -addword(wd, wb) -char *wd; -register struct wdblock *wb; -{ - register struct wdblock *wb2; - register int nw; - - if (wb == NULL) - wb = newword(NSTART); - if ((nw = wb->w_nword) >= wb->w_bsize) { - wb2 = newword(nw * 2); - memcpy((char *)wb2->w_words, (char *)wb->w_words, nw*sizeof(char *)); - wb2->w_nword = nw; - DELETE(wb); - wb = wb2; - } - wb->w_words[wb->w_nword++] = wd; - return(wb); -} -static -char ** -getwords(wb) -register struct wdblock *wb; -{ - register char **wd; - register int nb; - - if (wb == NULL) - return((char **)NULL); - if (wb->w_nword == 0) { - DELETE(wb); - return((char **)NULL); - } - wd = (char **) space(nb = sizeof(*wd) * wb->w_nword); - memcpy((char *)wd, (char *)wb->w_words, nb); - DELETE(wb); /* perhaps should done by caller */ - return(wd); -} - -int (*func)(char *, char *); -int globv; - -static void -glob0(a0, a1, a2, a3) -char *a0; -unsigned a1; -int a2; -int (*a3) (char *, char *); -{ - func = a3; - globv = a2; - glob1(a0, a0 + a1 * a2); -} - -static void -glob1(base, lim) -char *base, *lim; -{ - register char *i, *j; - int v2; - char *lptr, *hptr; - int c; - unsigned n; - - - v2 = globv; - -top: - if ((n=(int)(lim-base)) <= v2) - return; - n = v2 * (n / (2*v2)); - hptr = lptr = base+n; - i = base; - j = lim-v2; - for(;;) { - if (i < lptr) { - if ((c = (*func)(i, lptr)) == 0) { - glob2(i, lptr -= v2); - continue; - } - if (c < 0) { - i += v2; - continue; - } - } - -begin: - if (j > hptr) { - if ((c = (*func)(hptr, j)) == 0) { - glob2(hptr += v2, j); - goto begin; - } - if (c > 0) { - if (i == lptr) { - glob3(i, hptr += v2, j); - i = lptr += v2; - goto begin; - } - glob2(i, j); - j -= v2; - i += v2; - continue; - } - j -= v2; - goto begin; - } - - - if (i == lptr) { - if (lptr-base >= lim-hptr) { - glob1(hptr+v2, lim); - lim = lptr; - } else { - glob1(base, lptr); - base = hptr+v2; - } - goto top; - } - - - glob3(j, lptr -= v2, i); - j = hptr -= v2; - } -} - -static void -glob2(i, j) -char *i, *j; -{ - register char *index1, *index2, c; - int m; - - m = globv; - index1 = i; - index2 = j; - do { - c = *index1; - *index1++ = *index2; - *index2++ = c; - } while(--m); -} - -static void -glob3(i, j, k) -char *i, *j, *k; -{ - register char *index1, *index2, *index3; - int c; - int m; - - m = globv; - index1 = i; - index2 = j; - index3 = k; - do { - c = *index1; - *index1++ = *index3; - *index3++ = *index2; - *index2++ = c; - } while(--m); -} - -/* -------- io.c -------- */ - -/* - * shell IO - */ - -static int my_getc( int ec) -{ - register int c; - - if(e.linep > elinep) { - while((c=readc()) != '\n' && c) - ; - err("input line too long"); - gflg++; - return(c); - } - c = readc(); - if (ec != '\'' && e.iop->task != XGRAVE) { - if(c == '\\') { - c = readc(); - if (c == '\n' && ec != '\"') - return(my_getc(ec)); - c |= QUOTE; - } - } - return(c); -} - -static void -unget(c) -int c; -{ - if (e.iop >= e.iobase) - e.iop->peekc = c; -} - -static int -eofc() - -{ - return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0); -} - -static int -readc() -{ - register int c; - - for (; e.iop >= e.iobase; e.iop--) - if ((c = e.iop->peekc) != '\0') { - e.iop->peekc = 0; - return(c); - } - else { - if (e.iop->prev != 0) { - if ((c = (*e.iop->iofn)(e.iop->argp, e.iop)) != '\0') { - if (c == -1) { - e.iop++; - continue; - } - if (e.iop == iostack) - ioecho(c); - return(e.iop->prev = c); - } - else if (e.iop->task == XIO && e.iop->prev != '\n') { - e.iop->prev = 0; - if (e.iop == iostack) - ioecho('\n'); - return '\n'; - } - } - if (e.iop->task == XIO) { - if (multiline) - return e.iop->prev = 0; - if (interactive && e.iop == iostack+1) { -#ifdef BB_FEATURE_COMMAND_EDITING - current_prompt=prompt->value; -#else - prs(prompt->value); -#endif - } - } - } - if (e.iop >= iostack) - return(0); - leave(); - /* NOTREACHED */ - return(0); -} - -static void -ioecho(c) -char c; -{ - if (flag['v']) - write(2, &c, sizeof c); -} - -static void -pushio(argp, fn) -struct ioarg *argp; -int (*fn)(); -{ - if (++e.iop >= &iostack[NPUSH]) { - e.iop--; - err("Shell input nested too deeply"); - gflg++; - return; - } - e.iop->iofn = fn; - - if (argp->afid != AFID_NOBUF) - e.iop->argp = argp; - else { - e.iop->argp = ioargstack + (e.iop - iostack); - *e.iop->argp = *argp; - e.iop->argp->afbuf = e.iop == &iostack[0] ? &mainbuf : &sharedbuf; - if (isatty(e.iop->argp->afile) == 0 && - (e.iop == &iostack[0] || - lseek(e.iop->argp->afile, 0L, 1) != -1)) { - if (++bufid == AFID_NOBUF) - bufid = AFID_ID; - e.iop->argp->afid = bufid; - } - } - - e.iop->prev = ~'\n'; - e.iop->peekc = 0; - e.iop->xchar = 0; - e.iop->nlcount = 0; - if (fn == filechar || fn == linechar) - e.iop->task = XIO; - else if (fn == gravechar || fn == qgravechar) - e.iop->task = XGRAVE; - else - e.iop->task = XOTHER; -} - -static struct io * -setbase(ip) -struct io *ip; -{ - register struct io *xp; - - xp = e.iobase; - e.iobase = ip; - return(xp); -} - -/* - * Input generating functions - */ - -/* - * Produce the characters of a string, then a newline, then EOF. - */ -static int -nlchar(ap) -register struct ioarg *ap; -{ - register int c; - - if (ap->aword == NULL) - return(0); - if ((c = *ap->aword++) == 0) { - ap->aword = NULL; - return('\n'); - } - return(c); -} - -/* - * Given a list of words, produce the characters - * in them, with a space after each word. - */ -static int -wdchar(ap) -register struct ioarg *ap; -{ - register char c; - register char **wl; - - if ((wl = ap->awordlist) == NULL) - return(0); - if (*wl != NULL) { - if ((c = *(*wl)++) != 0) - return(c & 0177); - ap->awordlist++; - return(' '); - } - ap->awordlist = NULL; - return('\n'); -} - -/* - * Return the characters of a list of words, - * producing a space between them. - */ -static int -dolchar(ap) -register struct ioarg *ap; -{ - register char *wp; - - if ((wp = *ap->awordlist++) != NULL) { - PUSHIO(aword, wp, *ap->awordlist == NULL? strchar: xxchar); - return(-1); - } - return(0); -} - -static int -xxchar(ap) -register struct ioarg *ap; -{ - register int c; - - if (ap->aword == NULL) - return(0); - if ((c = *ap->aword++) == '\0') { - ap->aword = NULL; - return(' '); - } - return(c); -} - -/* - * Produce the characters from a single word (string). - */ -static int -strchar(ap) -register struct ioarg *ap; -{ - register int c; - - if (ap->aword == NULL || (c = *ap->aword++) == 0) - return(0); - return(c); -} - -/* - * Produce quoted characters from a single word (string). - */ -static int -qstrchar(ap) -register struct ioarg *ap; -{ - register int c; - - if (ap->aword == NULL || (c = *ap->aword++) == 0) - return(0); - return(c|QUOTE); -} - -/* - * Return the characters from a file. - */ -static int -filechar(ap) -register struct ioarg *ap; -{ - register int i; - char c; - struct iobuf *bp = ap->afbuf; - - if (ap->afid != AFID_NOBUF) { - if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) { - if (i) - lseek(ap->afile, ap->afpos, 0); - i = safe_read(ap->afile, bp->buf, sizeof(bp->buf)); - if (i <= 0) { - closef(ap->afile); - return 0; - } - bp->id = ap->afid; - bp->ebufp = (bp->bufp = bp->buf) + i; - } - ap->afpos++; - return *bp->bufp++ & 0177; - } - -#ifdef BB_FEATURE_COMMAND_EDITING - if (interactive) { - static char mycommand[BUFSIZ]; - static int position = 0, size = 0; - - while (size == 0 || position >= size) { - cmdedit_read_input(current_prompt, mycommand); - size = strlen(mycommand); - position = 0; - } - c = mycommand[position]; - position++; - return(c); - } else -#endif - { - i = safe_read(ap->afile, &c, sizeof(c)); - return(i == sizeof(c)? c&0177: (closef(ap->afile), 0)); - } -} - -/* - * Return the characters from a here temp file. - */ -static int -herechar(ap) -register struct ioarg *ap; -{ - char c; - - - if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) { - close(ap->afile); - c = 0; - } - return (c); - -} - -/* - * Return the characters produced by a process (`...`). - * Quote them if required, and remove any trailing newline characters. - */ -static int -gravechar(ap, iop) -struct ioarg *ap; -struct io *iop; -{ - register int c; - - if ((c = qgravechar(ap, iop)&~QUOTE) == '\n') - c = ' '; - return(c); -} - -static int -qgravechar(ap, iop) -register struct ioarg *ap; -struct io *iop; -{ - register int c; - - if (iop->xchar) { - if (iop->nlcount) { - iop->nlcount--; - return('\n'|QUOTE); - } - c = iop->xchar; - iop->xchar = 0; - } else if ((c = filechar(ap)) == '\n') { - iop->nlcount = 1; - while ((c = filechar(ap)) == '\n') - iop->nlcount++; - iop->xchar = c; - if (c == 0) - return(c); - iop->nlcount--; - c = '\n'; - } - return(c!=0? c|QUOTE: 0); -} - -/* - * Return a single command (usually the first line) from a file. - */ -static int -linechar(ap) -register struct ioarg *ap; -{ - register int c; - - if ((c = filechar(ap)) == '\n') { - if (!multiline) { - closef(ap->afile); - ap->afile = -1; /* illegal value */ - } - } - return(c); -} - -static void -prs(s) -register char *s; -{ - if (*s) - write(2, s, strlen(s)); -} - -static void -prn(u) -unsigned u; -{ - prs(itoa(u, 0)); -} - -static void -closef(i) -register int i; -{ - if (i > 2) - close(i); -} - -static void -closeall() -{ - register int u; - - for (u=NUFILE; u= 0 && fd < e.iofd); - for (i=0; ih_tag = evalstr(s, DOSUB); - if (h->h_tag == 0) - return; - h->h_iop = iop; - iop->io_name = 0; - h->h_next = NULL; - if (inhere == 0) - inhere = h; - else - for (lh = inhere; lh!=NULL; lh = lh->h_next) - if (lh->h_next == 0) { - lh->h_next = h; - break; - } - iop->io_flag |= IOHERE|IOXHERE; - for (s = h->h_tag; *s; s++) - if (*s & QUOTE) { - iop->io_flag &= ~ IOXHERE; - *s &= ~ QUOTE; - } - h->h_dosub = iop->io_flag & IOXHERE; -} - -static void -gethere() -{ - register struct here *h, *hp; - - /* Scan here files first leaving inhere list in place */ - for (hp = h = inhere; h != NULL; hp = h, h = h->h_next) - readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub? 0: '\''); - - /* Make inhere list active - keep list intact for scraphere */ - if (hp != NULL) { - hp->h_next = acthere; - acthere = inhere; - inhere = NULL; - } -} - -static void -readhere(name, s, ec) -char **name; -register char *s; -int ec; -{ - int tf; - char tname[30] = ".msh_XXXXXX"; - register int c; - jmp_buf ev; - char myline [LINELIM+1]; - char *thenext; - - tf = mkstemp(tname); - if (tf < 0) - return; - *name = strsave(tname, areanum); - if (newenv(setjmp(errpt = ev)) != 0) - unlink(tname); - else { - pushio(e.iop->argp, e.iop->iofn); - e.iobase = e.iop; - for (;;) { - if (interactive && e.iop <= iostack) { -#ifdef BB_FEATURE_COMMAND_EDITING - current_prompt=cprompt->value; -#else - prs(cprompt->value); -#endif - } - thenext = myline; - while ((c = my_getc(ec)) != '\n' && c) { - if (ec == '\'') - c &= ~ QUOTE; - if (thenext >= &myline[LINELIM]) { - c = 0; - break; - } - *thenext++ = c; - } - *thenext = 0; - if (strcmp(s, myline) == 0 || c == 0) - break; - *thenext++ = '\n'; - write (tf, myline, (int)(thenext-myline)); - } - if (c == 0) { - prs("here document `"); prs(s); err("' unclosed"); - } - quitenv(); - } - close(tf); -} - -/* - * open here temp file. - * if unquoted here, expand here temp file into second temp file. - */ -static int -herein(hname, xdoll) -char *hname; -int xdoll; -{ - register int hf; - int tf; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &tf; -#endif - if (hname == 0) - return(-1); - hf = open(hname, 0); - if (hf < 0) - return (-1); - if (xdoll) { - char c; - char tname[30] = ".msh_XXXXXX"; - jmp_buf ev; - - tf = mkstemp(tname); - if (tf < 0) - return (-1); - if (newenv(setjmp(errpt = ev)) == 0) { - PUSHIO(afile, hf, herechar); - setbase(e.iop); - while ((c = subgetc(0, 0)) != 0) { - c &= ~ QUOTE; - write(tf, &c, sizeof c); - } - quitenv(); - } else - unlink(tname); - close(tf); - tf = open(tname, 0); - unlink(tname); - return (tf); - } else - return (hf); -} - -static void -scraphere() -{ - register struct here *h; - - for (h = inhere; h != NULL; h = h->h_next) { - if (h->h_iop && h->h_iop->io_name) - unlink(h->h_iop->io_name); - } - inhere = NULL; -} - -/* unlink here temp files before a freearea(area) */ -static void -freehere(area) -int area; -{ - register struct here *h, *hl; - - hl = NULL; - for (h = acthere; h != NULL; h = h->h_next) - if (getarea((char *) h) >= area) { - if (h->h_iop->io_name != NULL) - unlink(h->h_iop->io_name); - if (hl == NULL) - acthere = h->h_next; - else - hl->h_next = h->h_next; - } else - hl = h; -} - - - -/* - * 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. - * - */ - diff --git a/busybox/mt.c b/busybox/mt.c deleted file mode 100644 index 49dc70ac6..000000000 --- a/busybox/mt.c +++ /dev/null @@ -1,121 +0,0 @@ -/* vi: set sw=4 ts=4: */ -#include -#include -#include -#include -#include -#include "busybox.h" - -struct mt_opcodes { - char *name; - short value; -}; - -/* missing: eod/seod, stoptions, stwrthreshold, densities */ -static const struct mt_opcodes opcodes[] = { - {"bsf", MTBSF}, - {"bsfm", MTBSFM}, - {"bsr", MTBSR}, - {"bss", MTBSS}, - {"datacompression", MTCOMPRESSION}, - {"eom", MTEOM}, - {"erase", MTERASE}, - {"fsf", MTFSF}, - {"fsfm", MTFSFM}, - {"fsr", MTFSR}, - {"fss", MTFSS}, - {"load", MTLOAD}, - {"lock", MTLOCK}, - {"mkpart", MTMKPART}, - {"nop", MTNOP}, - {"offline", MTOFFL}, - {"rewoffline", MTOFFL}, - {"ras1", MTRAS1}, - {"ras2", MTRAS2}, - {"ras3", MTRAS3}, - {"reset", MTRESET}, - {"retension", MTRETEN}, - {"rewind", MTREW}, - {"seek", MTSEEK}, - {"setblk", MTSETBLK}, - {"setdensity", MTSETDENSITY}, - {"drvbuffer", MTSETDRVBUFFER}, - {"setpart", MTSETPART}, - {"tell", MTTELL}, - {"wset", MTWSM}, - {"unload", MTUNLOAD}, - {"unlock", MTUNLOCK}, - {"eof", MTWEOF}, - {"weof", MTWEOF}, - {0, 0} -}; - -extern int mt_main(int argc, char **argv) -{ - const char *file = "/dev/tape"; - const struct mt_opcodes *code = opcodes; - struct mtop op; - struct mtpos position; - int fd, mode; - - if (argc < 2) { - show_usage(); - } - - if (strcmp(argv[1], "-f") == 0) { - if (argc < 4) { - show_usage(); - } - file = argv[2]; - argv += 2; - argc -= 2; - } - - while (code->name != 0) { - if (strcmp(code->name, argv[1]) == 0) - break; - code++; - } - - if (code->name == 0) { - error_msg("unrecognized opcode %s.", argv[1]); - return EXIT_FAILURE; - } - - op.mt_op = code->value; - if (argc >= 3) - op.mt_count = atoi(argv[2]); - else - op.mt_count = 1; /* One, not zero, right? */ - - switch (code->value) { - case MTWEOF: - case MTERASE: - case MTWSM: - case MTSETDRVBUFFER: - mode = O_WRONLY; - break; - - default: - mode = O_RDONLY; - break; - } - - if ((fd = open(file, mode, 0)) < 0) - perror_msg_and_die("%s", file); - - switch (code->value) { - case MTTELL: - if (ioctl(fd, MTIOCPOS, &position) < 0) - perror_msg_and_die("%s", file); - printf ("At block %d.\n", (int) position.mt_blkno); - break; - - default: - if (ioctl(fd, MTIOCTOP, &op) != 0) - perror_msg_and_die("%s", file); - break; - } - - return EXIT_SUCCESS; -} diff --git a/busybox/mv.c b/busybox/mv.c deleted file mode 100644 index b890abf6e..000000000 --- a/busybox/mv.c +++ /dev/null @@ -1,168 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mv implementation for busybox - * - * - * Copyright (C) 2000 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 - * - */ - -#include -#include -#include -#include -#include -#include - -#include "busybox.h" - -static int flags; - -static int manual_rename(const char *source, const char *dest) -{ - struct stat source_stat; - struct stat dest_stat; - int source_exists = 1; - int dest_exists = 1; - - if (stat(source, &source_stat) < 0) { - if (errno != ENOENT) { - perror_msg("unable to stat `%s'", source); - return -1; - } - source_exists = 0; - } - - if (stat(dest, &dest_stat) < 0) { - if (errno != ENOENT) { - perror_msg("unable to stat `%s'", dest); - return -1; - } - dest_exists = 0; - } - - if (dest_exists) { - if (S_ISDIR(dest_stat.st_mode) && - (!source_exists || !S_ISDIR(source_stat.st_mode))) { - error_msg("cannot overwrite directory with non-directory"); - return -1; - } - - if (!S_ISDIR(dest_stat.st_mode) && source_exists && - S_ISDIR(source_stat.st_mode)) { - error_msg("cannot overwrite non-directory with directory"); - return -1; - } - - if (unlink(dest) < 0) { - perror_msg("cannot remove `%s'", dest); - return -1; - } - } - - if (copy_file(source, dest, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS | - FILEUTILS_PRESERVE_SYMLINKS) < 0) - return -1; - - if (remove_file(source, FILEUTILS_RECUR | FILEUTILS_FORCE) < 0) - return -1; - - return 0; -} - -static int move_file(const char *source, const char *dest) -{ - struct stat dest_stat; - int dest_exists = 1; - - if (stat(dest, &dest_stat) < 0) { - if (errno != ENOENT) { - perror_msg("unable to stat `%s'", dest); - return -1; - } - dest_exists = 0; - } - - if (dest_exists && !(flags & FILEUTILS_FORCE) && - ((access(dest, W_OK) < 0 && isatty(0)) || - (flags & FILEUTILS_INTERACTIVE))) { - fprintf(stderr, "mv: overwrite `%s'? ", dest); - if (!ask_confirmation()) - return 0; - } - - if (rename(source, dest) < 0) { - if (errno == EXDEV) - return manual_rename(source, dest); - - perror_msg("unable to rename `%s'", source); - return -1; - } - - return 0; -} - -extern int mv_main(int argc, char **argv) -{ - int status = 0; - int opt; - int i; - - while ((opt = getopt(argc, argv, "fi")) != -1) - switch (opt) { - case 'f': - flags &= ~FILEUTILS_INTERACTIVE; - flags |= FILEUTILS_FORCE; - break; - case 'i': - flags &= ~FILEUTILS_FORCE; - flags |= FILEUTILS_INTERACTIVE; - break; - default: - show_usage(); - } - - if (optind + 2 > argc) - show_usage(); - - if (optind + 2 == argc) { - struct stat dest_stat; - int dest_exists = 1; - - if (stat(argv[optind + 1], &dest_stat) < 0) { - if (errno != ENOENT) - perror_msg_and_die("unable to stat `%s'", argv[optind + 1]); - dest_exists = 0; - } - - if (!dest_exists || !S_ISDIR(dest_stat.st_mode)) { - if (move_file(argv[optind], argv[optind + 1]) < 0) - status = 1; - return status; - } - } - - for (i = optind; i < argc - 1; i++) { - char *dest = concat_path_file(argv[argc - 1], - get_last_path_component(argv[i])); - if (move_file(argv[i], dest) < 0) - status = 1; - free(dest); - } - - return status; -} diff --git a/busybox/nc.c b/busybox/nc.c deleted file mode 100644 index 5335872e5..000000000 --- a/busybox/nc.c +++ /dev/null @@ -1,137 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* nc: mini-netcat - built from the ground up for LRP - Copyright (C) 1998 Charles P. Wright - - 0.0.1 6K It works. - 0.0.2 5K Smaller and you can also check the exit condition if you wish. - 0.0.3 Uses select() - - 19980918 Busy Boxed! Dave Cinege - 19990512 Uses Select. Charles P. Wright - 19990513 Fixes stdin stupidity and uses buffers. Charles P. Wright - - 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 -#include -#include "busybox.h" - -int nc_main(int argc, char **argv) -{ - int do_listen = 0, lport = 0, tmpfd, opt, sfd; - char buf[BUFSIZ]; - - struct sockaddr_in address; - struct hostent *hostinfo; - - fd_set readfds, testfds; - - while ((opt = getopt(argc, argv, "lp:")) > 0) { - switch (opt) { - case 'l': - do_listen++; - break; - case 'p': - lport = atoi(optarg); - break; - default: - show_usage(); - } - } - - if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc)) - show_usage(); - - if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) - perror_msg_and_die("socket"); - - address.sin_family = AF_INET; - - if (lport != 0) { - memset(&address.sin_addr, 0, sizeof(address.sin_addr)); - address.sin_port = htons(lport); - - if (bind(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) - perror_msg_and_die("bind"); - } - - if (do_listen) { - socklen_t addrlen = sizeof(address); - - if (listen(sfd, 1) < 0) - perror_msg_and_die("listen"); - - if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0) - perror_msg_and_die("accept"); - - close(sfd); - sfd = tmpfd; - } else { - hostinfo = xgethostbyname(argv[optind]); - - address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; - address.sin_port = htons(atoi(argv[optind+1])); - - if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) - perror_msg_and_die("connect"); - } - - FD_ZERO(&readfds); - FD_SET(sfd, &readfds); - FD_SET(STDIN_FILENO, &readfds); - - while (1) { - int fd; - int ofd; - int nread; - - testfds = readfds; - - if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0) - perror_msg_and_die("select"); - - for (fd = 0; fd < FD_SETSIZE; fd++) { - if (FD_ISSET(fd, &testfds)) { - if ((nread = safe_read(fd, buf, sizeof(buf))) < 0) - perror_msg_and_die("read"); - - if (fd == sfd) { - if (nread == 0) - exit(0); - ofd = STDOUT_FILENO; - } else { - if (nread == 0) - shutdown(sfd, 1); - ofd = sfd; - } - - if (full_write(ofd, buf, nread) < 0) - perror_msg_and_die("write"); - } - } - } -} diff --git a/busybox/networking/hostname.c b/busybox/networking/hostname.c deleted file mode 100644 index d87851509..000000000 --- a/busybox/networking/hostname.c +++ /dev/null @@ -1,128 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * $Id: hostname.c,v 1.30 2001/06/26 02:06:08 bug1 Exp $ - * Mini hostname implementation for busybox - * - * Copyright (C) 1999 by Randolph Chung - * - * adjusted by Erik Andersen to remove - * use of long options and GNU getopt. Improved the usage info. - * - * 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 "busybox.h" - -static void do_sethostname(char *s, int isfile) -{ - FILE *f; - char buf[255]; - - if (!s) - return; - if (!isfile) { - if (sethostname(s, strlen(s)) < 0) { - if (errno == EPERM) - error_msg_and_die("you must be root to change the hostname"); - else - perror_msg_and_die("sethostname"); - } - } else { - f = xfopen(s, "r"); - fgets(buf, 255, f); -#ifdef BB_FEATURE_CLEAN_UP - fclose(f); -#endif - chomp(buf); - do_sethostname(buf, 0); - } -} - -int hostname_main(int argc, char **argv) -{ - int opt_short = 0; - int opt_domain = 0; - int opt_ip = 0; - struct hostent *h; - char *filename = NULL; - char buf[255]; - char *s = NULL; - - if (argc < 1) - show_usage(); - - while (--argc > 0 && **(++argv) == '-') { - while (*(++(*argv))) { - switch (**argv) { - case 's': - opt_short = 1; - break; - case 'i': - opt_ip = 1; - break; - case 'd': - opt_domain = 1; - break; - case 'F': - if (--argc == 0) { - show_usage(); - } - filename = *(++argv); - break; - case '-': - if (strcmp(++(*argv), "file") || --argc ==0 ) { - show_usage(); - } - filename = *(++argv); - break; - default: - show_usage(); - } - if (filename != NULL) - break; - } - } - - if (argc >= 1) { - do_sethostname(*argv, 0); - } else if (filename != NULL) { - do_sethostname(filename, 1); - } else { - gethostname(buf, 255); - if (opt_short) { - s = strchr(buf, '.'); - if (!s) - s = buf; - *s = 0; - puts(buf); - } else if (opt_domain) { - s = strchr(buf, '.'); - puts(s ? s + 1 : ""); - } else if (opt_ip) { - h = xgethostbyname(buf); - puts(inet_ntoa(*(struct in_addr *) (h->h_addr))); - } else { - puts(buf); - } - } - return(0); -} diff --git a/busybox/networking/ifconfig.c b/busybox/networking/ifconfig.c deleted file mode 100644 index 5f8b0eed6..000000000 --- a/busybox/networking/ifconfig.c +++ /dev/null @@ -1,492 +0,0 @@ -/* ifconfig - * - * Similar to the standard Unix ifconfig, but with only the necessary - * parts for AF_INET, and without any printing of if info (for now). - * - * Bjorn Wesen, Axis Communications AB - * - * - * Authors of the original ifconfig was: - * Fred N. van Kempen, - * - * 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. - * - * $Id: ifconfig.c,v 1.11.2.1 2001/08/10 18:22:15 andersen Exp $ - * - */ - -/* - * Heavily modified by Manuel Novoa III Mar 6, 2001 - * - * From initial port to busybox, removed most of the redundancy by - * converting to a table-driven approach. Added several (optional) - * args missing from initial port. - * - * Still missing: media, tunnel. - */ - -#include -#include -#include // strcmp and friends -#include // isdigit and friends -#include /* offsetof */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#ifdef BB_FEATURE_IFCONFIG_SLIP -#include -#endif - -/* I don't know if this is needed for busybox or not. Anyone? */ -#define QUESTIONABLE_ALIAS_CASE - - -/* Defines for glibc2.0 users. */ -#ifndef SIOCSIFTXQLEN -#define SIOCSIFTXQLEN 0x8943 -#define SIOCGIFTXQLEN 0x8942 -#endif - -/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */ -#ifndef ifr_qlen -#define ifr_qlen ifr_ifru.ifru_mtu -#endif - -#ifndef IFF_DYNAMIC -#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */ -#endif - -/* - * Here are the bit masks for the "flags" member of struct options below. - * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'. - * CLR clears the flag; SET sets the flag; ARG signifies (optional) arg. - */ -#define N_CLR 0x01 -#define M_CLR 0x02 -#define N_SET 0x04 -#define M_SET 0x08 -#define N_ARG 0x10 -#define M_ARG 0x20 - -#define M_MASK (M_CLR | M_SET | M_ARG) -#define N_MASK (N_CLR | N_SET | N_ARG) -#define SET_MASK (N_SET | M_SET) -#define CLR_MASK (N_CLR | M_CLR) -#define SET_CLR_MASK (SET_MASK | CLR_MASK) -#define ARG_MASK (M_ARG | N_ARG) - -/* - * Here are the bit masks for the "arg_flags" member of struct options below. - */ - -/* - * cast type: - * 00 int - * 01 char * - * 02 HOST_COPY in_ether - * 03 HOST_COPY INET_resolve - */ -#define A_CAST_TYPE 0x03 -/* - * map type: - * 00 not a map type (mem_start, io_addr, irq) - * 04 memstart (unsigned long) - * 08 io_addr (unsigned short) - * 0C irq (unsigned char) - */ -#define A_MAP_TYPE 0x0C -#define A_ARG_REQ 0x10 /* Set if an arg is required. */ -#define A_NETMASK 0x20 /* Set if netmask (check for multiple sets). */ -#define A_SET_AFTER 0x40 /* Set a flag at the end. */ -#define A_COLON_CHK 0x80 /* Is this needed? See below. */ - -/* - * These defines are for dealing with the A_CAST_TYPE field. - */ -#define A_CAST_CHAR_PTR 0x01 -#define A_CAST_RESOLVE 0x01 -#define A_CAST_HOST_COPY 0x02 -#define A_CAST_HOST_COPY_IN_ETHER A_CAST_HOST_COPY -#define A_CAST_HOST_COPY_RESOLVE (A_CAST_HOST_COPY | A_CAST_RESOLVE) - -/* - * These defines are for dealing with the A_MAP_TYPE field. - */ -#define A_MAP_ULONG 0x04 /* memstart */ -#define A_MAP_USHORT 0x08 /* io_addr */ -#define A_MAP_UCHAR 0x0C /* irq */ - -/* - * Define the bit masks signifying which operations to perform for each arg. - */ - -#define ARG_METRIC (A_ARG_REQ /*| A_CAST_INT*/) -#define ARG_MTU (A_ARG_REQ /*| A_CAST_INT*/) -#define ARG_TXQUEUELEN (A_ARG_REQ /*| A_CAST_INT*/) -#define ARG_MEM_START (A_ARG_REQ | A_MAP_ULONG) -#define ARG_IO_ADDR (A_ARG_REQ | A_MAP_USHORT) -#define ARG_IRQ (A_ARG_REQ | A_MAP_UCHAR) -#define ARG_DSTADDR (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE) -#define ARG_NETMASK (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_NETMASK) -#define ARG_BROADCAST (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER) -#define ARG_HW (A_ARG_REQ | A_CAST_HOST_COPY_IN_ETHER) -#define ARG_POINTOPOINT (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER) -#define ARG_KEEPALIVE (A_ARG_REQ | A_CAST_CHAR_PTR) -#define ARG_OUTFILL (A_ARG_REQ | A_CAST_CHAR_PTR) -#define ARG_HOSTNAME (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK) - - -/* - * Set up the tables. Warning! They must have corresponding order! - */ - -struct arg1opt { - const char *name; - unsigned short selector; - unsigned short ifr_offset; -}; - -struct options { - const char *name; - const unsigned char flags; - const unsigned char arg_flags; - const unsigned short selector; -}; - -#define ifreq_offsetof(x) offsetof(struct ifreq, x) - -static const struct arg1opt Arg1Opt[] = { - {"SIOCSIFMETRIC", SIOCSIFMETRIC, ifreq_offsetof(ifr_metric)}, - {"SIOCSIFMTU", SIOCSIFMTU, ifreq_offsetof(ifr_mtu)}, - {"SIOCSIFTXQLEN", SIOCSIFTXQLEN, ifreq_offsetof(ifr_qlen)}, - {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)}, - {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)}, - {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)}, -#ifdef BB_FEATURE_IFCONFIG_HW - {"SIOCSIFHWADDR", SIOCSIFHWADDR, ifreq_offsetof(ifr_hwaddr)}, -#endif - {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)}, -#ifdef SIOCSKEEPALIVE - {"SIOCSKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data)}, -#endif -#ifdef SIOCSOUTFILL - {"SIOCSOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data)}, -#endif -#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ - {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.mem_start)}, - {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.base_addr)}, - {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq)}, -#endif - /* Last entry if for unmatched (possibly hostname) arg. */ - {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)}, -}; - -static const struct options OptArray[] = { - {"metric", N_ARG, ARG_METRIC, 0}, - {"mtu", N_ARG, ARG_MTU, 0}, - {"txqueuelen", N_ARG, ARG_TXQUEUELEN, 0}, - {"dstaddr", N_ARG, ARG_DSTADDR, 0}, - {"netmask", N_ARG, ARG_NETMASK, 0}, - {"broadcast", N_ARG | M_CLR, ARG_BROADCAST, IFF_BROADCAST}, -#ifdef BB_FEATURE_IFCONFIG_HW - {"hw", N_ARG, ARG_HW, 0}, -#endif - {"pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT}, -#ifdef SIOCSKEEPALIVE - {"keepalive", N_ARG, ARG_KEEPALIVE, 0}, -#endif -#ifdef SIOCSOUTFILL - {"outfill", N_ARG, ARG_OUTFILL, 0}, -#endif -#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ - {"mem_start", N_ARG, ARG_MEM_START, 0}, - {"io_addr", N_ARG, ARG_IO_ADDR, 0}, - {"irq", N_ARG, ARG_IRQ, 0}, -#endif - {"arp", N_CLR | M_SET, 0, IFF_NOARP}, - {"trailers", N_CLR | M_SET, 0, IFF_NOTRAILERS}, - {"promisc", N_SET | M_CLR, 0, IFF_PROMISC}, - {"multicast", N_SET | M_CLR, 0, IFF_MULTICAST}, - {"allmulti", N_SET | M_CLR, 0, IFF_ALLMULTI}, - {"dynamic", N_SET | M_CLR, 0, IFF_DYNAMIC}, - {"up", N_SET , 0, (IFF_UP | IFF_RUNNING)}, - {"down", N_CLR , 0, IFF_UP}, - { NULL, 0, ARG_HOSTNAME, (IFF_UP | IFF_RUNNING)} -}; - -/* - * A couple of prototypes. - */ - -#ifdef BB_FEATURE_IFCONFIG_HW -static int in_ether(char *bufp, struct sockaddr *sap); -#endif - -#ifdef BB_FEATURE_IFCONFIG_STATUS -extern int interface_opt_a; -extern int display_interfaces(char *ifname); -#endif - -/* - * Our main function. - */ - -int ifconfig_main(int argc, char **argv) -{ - struct ifreq ifr; - struct sockaddr_in sai; -#ifdef BB_FEATURE_IFCONFIG_HW - struct sockaddr sa; -#endif - const struct arg1opt *a1op; - const struct options *op; - int sockfd; /* socket fd we use to manipulate stuff with */ - int goterr; - int selector; - char *p; - char host[128]; - unsigned char mask; - unsigned char did_flags; - - goterr = 0; - did_flags = 0; - - /* skip argv[0] */ - ++argv; - --argc; - -#ifdef BB_FEATURE_IFCONFIG_STATUS - if ((argc > 0) && (strcmp(*argv,"-a") == 0)) { - interface_opt_a = 1; - --argc; - ++argv; - } -#endif - - if(argc <= 1) { -#ifdef BB_FEATURE_IFCONFIG_STATUS - return display_interfaces(argc ? *argv : NULL); -#else - error_msg_and_die( "ifconfig was not compiled with interface status display support."); -#endif - } - - /* Create a channel to the NET kernel. */ - if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - perror_msg_and_die("socket"); - } - - /* get interface name */ - safe_strncpy(ifr.ifr_name, *argv, IFNAMSIZ); - - /* Process the remaining arguments. */ - while (*++argv != (char *) NULL) { - p = *argv; - mask = N_MASK; - if (*p == '-') { /* If the arg starts with '-'... */ - ++p; /* advance past it and */ - mask = M_MASK; /* set the appropriate mask. */ - } - for (op = OptArray ; op->name ; op++) { /* Find table entry. */ - if (strcmp(p,op->name) == 0) { /* If name matches... */ - if ((mask &= op->flags)) { /* set the mask and go. */ - goto FOUND_ARG;; - } - /* If we get here, there was a valid arg with an */ - /* invalid '-' prefix. */ - ++goterr; - goto LOOP; - } - } - - /* We fell through, so treat as possible hostname. */ - a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1; - mask = op->arg_flags; - goto HOSTNAME; - - FOUND_ARG: - if (mask & ARG_MASK) { - mask = op->arg_flags; - a1op = Arg1Opt + (op - OptArray); - if (mask & A_NETMASK & did_flags) { - show_usage(); - } - if (*++argv == NULL) { - if (mask & A_ARG_REQ) { - show_usage(); - } else { - --argv; - mask &= A_SET_AFTER; /* just for broadcast */ - } - } else { /* got an arg so process it */ - HOSTNAME: - did_flags |= (mask & A_NETMASK); - if (mask & A_CAST_HOST_COPY) { -#ifdef BB_FEATURE_IFCONFIG_HW - if (mask & A_CAST_RESOLVE) { -#endif - safe_strncpy(host, *argv, (sizeof host)); - sai.sin_family = AF_INET; - sai.sin_port = 0; - if (!strcmp(host, "default")) { - /* Default is special, meaning 0.0.0.0. */ - sai.sin_addr.s_addr = INADDR_ANY; - } else if (inet_aton(host, &sai.sin_addr) == 0) { - /* It's not a dotted quad. */ - ++goterr; - continue; - } - p = (char *) &sai; -#ifdef BB_FEATURE_IFCONFIG_HW - } else { /* A_CAST_HOST_COPY_IN_ETHER */ - /* This is the "hw" arg case. */ - if (strcmp("ether", *argv) || (*++argv == NULL)) { - show_usage(); - } - safe_strncpy(host, *argv, (sizeof host)); - if (in_ether(host, &sa)) { - fprintf(stderr, "invalid hw-addr %s\n", host); - ++goterr; - continue; - } - p = (char *) &sa; - } -#endif - memcpy((((char *)(&ifr)) + a1op->ifr_offset), - p, sizeof(struct sockaddr)); - } else { - unsigned int i = strtoul(*argv,NULL,0); - p = ((char *)(&ifr)) + a1op->ifr_offset; -#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ - if (mask & A_MAP_TYPE) { - if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) { - ++goterr; - continue; - } - if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) { - *((unsigned char *) p) = i; - } else if (mask & A_MAP_USHORT) { - *((unsigned short *) p) = i; - } else { - *((unsigned long *) p) = i; - } - } else -#endif - if (mask & A_CAST_CHAR_PTR) { - *((caddr_t *) p) = (caddr_t) i; - } else { /* A_CAST_INT */ - *((int *) p) = i; - } - } - - if (ioctl(sockfd, a1op->selector, &ifr) < 0) { - perror(a1op->name); - ++goterr; - continue; - } - -#ifdef QUESTIONABLE_ALIAS_CASE - if (mask & A_COLON_CHK) { - /* - * Don't do the set_flag() if the address is an alias with - * a - at the end, since it's deleted already! - Roman - * - * Should really use regex.h here, not sure though how well - * it'll go with the cross-platform support etc. - */ - char *ptr; - short int found_colon = 0; - for (ptr = ifr.ifr_name; *ptr; ptr++ ) { - if (*ptr == ':') { - found_colon++; - } - } - - if (found_colon && *(ptr - 1) == '-') { - continue; - } - } -#endif - } - if (!(mask & A_SET_AFTER)) { - continue; - } - mask = N_SET; - } - - if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { - perror("SIOCGIFFLAGS"); - ++goterr; - } else { - selector = op->selector; - if (mask & SET_MASK) { - ifr.ifr_flags |= selector; - } else { - ifr.ifr_flags &= ~selector; - } - if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { - perror("SIOCSIFFLAGS"); - ++goterr; - } - } - LOOP: - } /* end of while-loop */ - - return goterr; -} - -#ifdef BB_FEATURE_IFCONFIG_HW -/* Input an Ethernet address and convert to binary. */ -static int -in_ether(char *bufp, struct sockaddr *sap) -{ - unsigned char *ptr; - int i, j; - unsigned char val; - unsigned char c; - - sap->sa_family = ARPHRD_ETHER; - ptr = sap->sa_data; - - for (i = 0 ; i < ETH_ALEN ; i++) { - val = 0; - - /* We might get a semicolon here - not required. */ - if (i && (*bufp == ':')) { - bufp++; - } - - for (j=0 ; j<2 ; j++) { - c = *bufp; - if (c >= '0' && c <= '9') { - c -= '0'; - } else if (c >= 'a' && c <= 'f') { - c -= ('a' - 10); - } else if (c >= 'A' && c <= 'F') { - c -= ('A' - 10); - } else if (j && (c == ':' || c == 0)) { - break; - } else { - return -1; - } - ++bufp; - val <<= 4; - val += c; - } - *ptr++ = val; - } - - return (int) (*bufp); /* Error if we don't end at end of string. */ -} -#endif diff --git a/busybox/networking/nc.c b/busybox/networking/nc.c deleted file mode 100644 index 5335872e5..000000000 --- a/busybox/networking/nc.c +++ /dev/null @@ -1,137 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* nc: mini-netcat - built from the ground up for LRP - Copyright (C) 1998 Charles P. Wright - - 0.0.1 6K It works. - 0.0.2 5K Smaller and you can also check the exit condition if you wish. - 0.0.3 Uses select() - - 19980918 Busy Boxed! Dave Cinege - 19990512 Uses Select. Charles P. Wright - 19990513 Fixes stdin stupidity and uses buffers. Charles P. Wright - - 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 -#include -#include "busybox.h" - -int nc_main(int argc, char **argv) -{ - int do_listen = 0, lport = 0, tmpfd, opt, sfd; - char buf[BUFSIZ]; - - struct sockaddr_in address; - struct hostent *hostinfo; - - fd_set readfds, testfds; - - while ((opt = getopt(argc, argv, "lp:")) > 0) { - switch (opt) { - case 'l': - do_listen++; - break; - case 'p': - lport = atoi(optarg); - break; - default: - show_usage(); - } - } - - if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc)) - show_usage(); - - if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) - perror_msg_and_die("socket"); - - address.sin_family = AF_INET; - - if (lport != 0) { - memset(&address.sin_addr, 0, sizeof(address.sin_addr)); - address.sin_port = htons(lport); - - if (bind(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) - perror_msg_and_die("bind"); - } - - if (do_listen) { - socklen_t addrlen = sizeof(address); - - if (listen(sfd, 1) < 0) - perror_msg_and_die("listen"); - - if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0) - perror_msg_and_die("accept"); - - close(sfd); - sfd = tmpfd; - } else { - hostinfo = xgethostbyname(argv[optind]); - - address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; - address.sin_port = htons(atoi(argv[optind+1])); - - if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) - perror_msg_and_die("connect"); - } - - FD_ZERO(&readfds); - FD_SET(sfd, &readfds); - FD_SET(STDIN_FILENO, &readfds); - - while (1) { - int fd; - int ofd; - int nread; - - testfds = readfds; - - if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0) - perror_msg_and_die("select"); - - for (fd = 0; fd < FD_SETSIZE; fd++) { - if (FD_ISSET(fd, &testfds)) { - if ((nread = safe_read(fd, buf, sizeof(buf))) < 0) - perror_msg_and_die("read"); - - if (fd == sfd) { - if (nread == 0) - exit(0); - ofd = STDOUT_FILENO; - } else { - if (nread == 0) - shutdown(sfd, 1); - ofd = sfd; - } - - if (full_write(ofd, buf, nread) < 0) - perror_msg_and_die("write"); - } - } - } -} diff --git a/busybox/networking/nslookup.c b/busybox/networking/nslookup.c deleted file mode 100644 index 9b7cb645c..000000000 --- a/busybox/networking/nslookup.c +++ /dev/null @@ -1,183 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini nslookup implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by John Beppu - * - * 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 -#include -#include "busybox.h" - -/* - | I'm only implementing non-interactive mode; - | I totally forgot nslookup even had an interactive mode. - | - | [ TODO ] - | + find out how to use non-default name servers - */ - -/* only works for IPv4 */ -static int addr_fprint(char *addr) -{ - u_int8_t split[4]; - u_int32_t ip; - u_int32_t *x = (u_int32_t *) addr; - - ip = ntohl(*x); - split[0] = (ip & 0xff000000) >> 24; - split[1] = (ip & 0x00ff0000) >> 16; - split[2] = (ip & 0x0000ff00) >> 8; - split[3] = (ip & 0x000000ff); - printf("%d.%d.%d.%d", split[0], split[1], split[2], split[3]); - return 0; -} - -/* takes the NULL-terminated array h_addr_list, and - * prints its contents appropriately - */ -static int addr_list_fprint(char **h_addr_list) -{ - int i, j; - char *addr_string = (h_addr_list[1]) - ? "Addresses: " : "Address: "; - - printf("%s ", addr_string); - for (i = 0, j = 0; h_addr_list[i]; i++, j++) { - addr_fprint(h_addr_list[i]); - - /* real nslookup does this */ - if (j == 4) { - if (h_addr_list[i + 1]) { - printf("\n "); - } - j = 0; - } else { - if (h_addr_list[i + 1]) { - printf(", "); - } - } - - } - printf("\n"); - return 0; -} - -/* print the results as nslookup would */ -static struct hostent *hostent_fprint(struct hostent *host) -{ - if (host) { - printf("Name: %s\n", host->h_name); - addr_list_fprint(host->h_addr_list); - } else { - printf("*** Unknown host\n"); - } - return host; -} - -/* changes a c-string matching the perl regex \d+\.\d+\.\d+\.\d+ - * into a u_int32_t - */ -static u_int32_t str_to_addr(const char *addr) -{ - u_int32_t split[4]; - u_int32_t ip; - - sscanf(addr, "%d.%d.%d.%d", - &split[0], &split[1], &split[2], &split[3]); - - /* assuming sscanf worked */ - ip = (split[0] << 24) | - (split[1] << 16) | (split[2] << 8) | (split[3]); - - return htonl(ip); -} - -/* gethostbyaddr wrapper */ -static struct hostent *gethostbyaddr_wrapper(const char *address) -{ - struct in_addr addr; - - addr.s_addr = str_to_addr(address); - return gethostbyaddr((char *) &addr, 4, AF_INET); /* IPv4 only for now */ -} - -#ifdef __UCLIBC__ -#warning FIXME after fixing uClibc to define struct _res -static inline void server_print(void) -{ - printf("Server: %s\n", "default"); - printf("Address: %s\n\n", "default"); -} -#else -/* lookup the default nameserver and display it */ -static inline void server_print(void) -{ - struct sockaddr_in def = _res.nsaddr_list[0]; - char *ip = inet_ntoa(def.sin_addr); - - hostent_fprint(gethostbyaddr_wrapper(ip)); - printf("\n"); -} -#endif - -/* naive function to check whether char *s is an ip address */ -static int is_ip_address(const char *s) -{ - while (*s) { - if ((isdigit(*s)) || (*s == '.')) { - s++; - continue; - } - return 0; - } - return 1; -} - -/* ________________________________________________________________________ */ -int nslookup_main(int argc, char **argv) -{ - struct hostent *host; - - if (argc < 2 || *argv[1]=='-') { - show_usage(); - } - - res_init(); - server_print(); - if (is_ip_address(argv[1])) { - host = gethostbyaddr_wrapper(argv[1]); - } else { - host = gethostbyname(argv[1]); - } - hostent_fprint(host); - return EXIT_SUCCESS; -} - -/* $Id: nslookup.c,v 1.24 2001/07/06 17:51:29 andersen Exp $ */ diff --git a/busybox/networking/ping.c b/busybox/networking/ping.c deleted file mode 100644 index 5ca5dd9e0..000000000 --- a/busybox/networking/ping.c +++ /dev/null @@ -1,555 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * $Id: ping.c,v 1.46 2001/07/17 01:12:36 andersen Exp $ - * Mini ping implementation for busybox - * - * Copyright (C) 1999 by Randolph Chung - * - * 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 - * - * This version of ping is adapted from the ping in netkit-base 0.10, - * which is: - * - * Copyright (c) 1989 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Mike Muuss. - * - * Original copyright notice is retained at the end of this file. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - - -/* It turns out that libc5 doesn't have proper icmp support - * built into it header files, so we have to supplement it */ -#if __GNU_LIBRARY__ < 5 -static const int ICMP_MINLEN = 8; /* abs minimum */ - -struct icmp_ra_addr -{ - u_int32_t ira_addr; - u_int32_t ira_preference; -}; - - -struct icmp -{ - u_int8_t icmp_type; /* type of message, see below */ - u_int8_t icmp_code; /* type sub code */ - u_int16_t icmp_cksum; /* ones complement checksum of struct */ - union - { - u_char ih_pptr; /* ICMP_PARAMPROB */ - struct in_addr ih_gwaddr; /* gateway address */ - struct ih_idseq /* echo datagram */ - { - u_int16_t icd_id; - u_int16_t icd_seq; - } ih_idseq; - u_int32_t ih_void; - - /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ - struct ih_pmtu - { - u_int16_t ipm_void; - u_int16_t ipm_nextmtu; - } ih_pmtu; - - struct ih_rtradv - { - u_int8_t irt_num_addrs; - u_int8_t irt_wpa; - u_int16_t irt_lifetime; - } ih_rtradv; - } icmp_hun; -#define icmp_pptr icmp_hun.ih_pptr -#define icmp_gwaddr icmp_hun.ih_gwaddr -#define icmp_id icmp_hun.ih_idseq.icd_id -#define icmp_seq icmp_hun.ih_idseq.icd_seq -#define icmp_void icmp_hun.ih_void -#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void -#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu -#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs -#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa -#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime - union - { - struct - { - u_int32_t its_otime; - u_int32_t its_rtime; - u_int32_t its_ttime; - } id_ts; - struct - { - struct ip idi_ip; - /* options and then 64 bits of data */ - } id_ip; - struct icmp_ra_addr id_radv; - u_int32_t id_mask; - u_int8_t id_data[1]; - } icmp_dun; -#define icmp_otime icmp_dun.id_ts.its_otime -#define icmp_rtime icmp_dun.id_ts.its_rtime -#define icmp_ttime icmp_dun.id_ts.its_ttime -#define icmp_ip icmp_dun.id_ip.idi_ip -#define icmp_radv icmp_dun.id_radv -#define icmp_mask icmp_dun.id_mask -#define icmp_data icmp_dun.id_data -}; -#endif - -static const int DEFDATALEN = 56; -static const int MAXIPLEN = 60; -static const int MAXICMPLEN = 76; -static const int MAXPACKET = 65468; -#define MAX_DUP_CHK (8 * 128) -static const int MAXWAIT = 10; -static const int PINGINTERVAL = 1; /* second */ - -#define O_QUIET (1 << 0) - -#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ -#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ -#define SET(bit) (A(bit) |= B(bit)) -#define CLR(bit) (A(bit) &= (~B(bit))) -#define TST(bit) (A(bit) & B(bit)) - -static void ping(const char *host); - -/* common routines */ -static int in_cksum(unsigned short *buf, int sz) -{ - int nleft = sz; - int sum = 0; - unsigned short *w = buf; - unsigned short ans = 0; - - while (nleft > 1) { - sum += *w++; - nleft -= 2; - } - - if (nleft == 1) { - *(unsigned char *) (&ans) = *(unsigned char *) w; - sum += ans; - } - - sum = (sum >> 16) + (sum & 0xFFFF); - sum += (sum >> 16); - ans = ~sum; - return (ans); -} - -/* simple version */ -#ifndef BB_FEATURE_FANCY_PING -static char *hostname = NULL; - -static void noresp(int ign) -{ - printf("No response from %s\n", hostname); - exit(0); -} - -static void ping(const char *host) -{ - struct hostent *h; - struct sockaddr_in pingaddr; - struct icmp *pkt; - int pingsock, c; - char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; - - pingsock = create_icmp_socket(); - - memset(&pingaddr, 0, sizeof(struct sockaddr_in)); - - pingaddr.sin_family = AF_INET; - h = xgethostbyname(host); - memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr)); - hostname = h->h_name; - - pkt = (struct icmp *) packet; - memset(pkt, 0, sizeof(packet)); - pkt->icmp_type = ICMP_ECHO; - pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); - - c = sendto(pingsock, packet, sizeof(packet), 0, - (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in)); - - if (c < 0 || c != sizeof(packet)) - perror_msg_and_die("sendto"); - - signal(SIGALRM, noresp); - alarm(5); /* give the host 5000ms to respond */ - /* listen for replies */ - while (1) { - struct sockaddr_in from; - size_t fromlen = sizeof(from); - - if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, - (struct sockaddr *) &from, &fromlen)) < 0) { - if (errno == EINTR) - continue; - perror_msg("recvfrom"); - continue; - } - if (c >= 76) { /* ip + icmp */ - struct iphdr *iphdr = (struct iphdr *) packet; - - pkt = (struct icmp *) (packet + (iphdr->ihl << 2)); /* skip ip hdr */ - if (pkt->icmp_type == ICMP_ECHOREPLY) - break; - } - } - printf("%s is alive!\n", hostname); - return; -} - -extern int ping_main(int argc, char **argv) -{ - argc--; - argv++; - if (argc < 1) - show_usage(); - ping(*argv); - return EXIT_SUCCESS; -} - -#else /* ! BB_FEATURE_FANCY_PING */ -/* full(er) version */ -static char *hostname = NULL; -static struct sockaddr_in pingaddr; -static int pingsock = -1; -static int datalen; /* intentionally uninitialized to work around gcc bug */ - -static long ntransmitted = 0, nreceived = 0, nrepeats = 0, pingcount = 0; -static int myid = 0, options = 0; -static unsigned long tmin = ULONG_MAX, tmax = 0, tsum = 0; -static char rcvd_tbl[MAX_DUP_CHK / 8]; - -static void sendping(int); -static void pingstats(int); -static void unpack(char *, int, struct sockaddr_in *); - -/**************************************************************************/ - -static void pingstats(int junk) -{ - int status; - - signal(SIGINT, SIG_IGN); - - printf("\n--- %s ping statistics ---\n", hostname); - printf("%ld packets transmitted, ", ntransmitted); - printf("%ld packets received, ", nreceived); - if (nrepeats) - printf("%ld duplicates, ", nrepeats); - if (ntransmitted) - printf("%ld%% packet loss\n", - (ntransmitted - nreceived) * 100 / ntransmitted); - if (nreceived) - printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n", - tmin / 10, tmin % 10, - (tsum / (nreceived + nrepeats)) / 10, - (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10); - if (nreceived != 0) - status = EXIT_SUCCESS; - else - status = EXIT_FAILURE; - exit(status); -} - -static void sendping(int junk) -{ - struct icmp *pkt; - int i; - char packet[datalen + 8]; - - pkt = (struct icmp *) packet; - - pkt->icmp_type = ICMP_ECHO; - pkt->icmp_code = 0; - pkt->icmp_cksum = 0; - pkt->icmp_seq = ntransmitted++; - pkt->icmp_id = myid; - CLR(pkt->icmp_seq % MAX_DUP_CHK); - - gettimeofday((struct timeval *) &packet[8], NULL); - pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); - - i = sendto(pingsock, packet, sizeof(packet), 0, - (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in)); - - if (i < 0) - perror_msg_and_die("sendto"); - else if ((size_t)i != sizeof(packet)) - error_msg_and_die("ping wrote %d chars; %d expected", i, - (int)sizeof(packet)); - - signal(SIGALRM, sendping); - if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */ - alarm(PINGINTERVAL); - } else { /* done, wait for the last ping to come back */ - /* todo, don't necessarily need to wait so long... */ - signal(SIGALRM, pingstats); - alarm(MAXWAIT); - } -} - -static char *icmp_type_name (int id) -{ - switch (id) { - case ICMP_ECHOREPLY: return "Echo Reply"; - case ICMP_DEST_UNREACH: return "Destination Unreachable"; - case ICMP_SOURCE_QUENCH: return "Source Quench"; - case ICMP_REDIRECT: return "Redirect (change route)"; - case ICMP_ECHO: return "Echo Request"; - case ICMP_TIME_EXCEEDED: return "Time Exceeded"; - case ICMP_PARAMETERPROB: return "Parameter Problem"; - case ICMP_TIMESTAMP: return "Timestamp Request"; - case ICMP_TIMESTAMPREPLY: return "Timestamp Reply"; - case ICMP_INFO_REQUEST: return "Information Request"; - case ICMP_INFO_REPLY: return "Information Reply"; - case ICMP_ADDRESS: return "Address Mask Request"; - case ICMP_ADDRESSREPLY: return "Address Mask Reply"; - default: return "unknown ICMP type"; - } -} - -static void unpack(char *buf, int sz, struct sockaddr_in *from) -{ - struct icmp *icmppkt; - struct iphdr *iphdr; - struct timeval tv, *tp; - int hlen, dupflag; - unsigned long triptime; - - gettimeofday(&tv, NULL); - - /* check IP header */ - iphdr = (struct iphdr *) buf; - hlen = iphdr->ihl << 2; - /* discard if too short */ - if (sz < (datalen + ICMP_MINLEN)) - return; - - sz -= hlen; - icmppkt = (struct icmp *) (buf + hlen); - - if (icmppkt->icmp_id != myid) - return; /* not our ping */ - - if (icmppkt->icmp_type == ICMP_ECHOREPLY) { - ++nreceived; - tp = (struct timeval *) icmppkt->icmp_data; - - if ((tv.tv_usec -= tp->tv_usec) < 0) { - --tv.tv_sec; - tv.tv_usec += 1000000; - } - tv.tv_sec -= tp->tv_sec; - - triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100); - tsum += triptime; - if (triptime < tmin) - tmin = triptime; - if (triptime > tmax) - tmax = triptime; - - if (TST(icmppkt->icmp_seq % MAX_DUP_CHK)) { - ++nrepeats; - --nreceived; - dupflag = 1; - } else { - SET(icmppkt->icmp_seq % MAX_DUP_CHK); - dupflag = 0; - } - - if (options & O_QUIET) - return; - - printf("%d bytes from %s: icmp_seq=%u", sz, - inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr), - icmppkt->icmp_seq); - printf(" ttl=%d", iphdr->ttl); - printf(" time=%lu.%lu ms", triptime / 10, triptime % 10); - if (dupflag) - printf(" (DUP!)"); - printf("\n"); - } else - if (icmppkt->icmp_type != ICMP_ECHO) - error_msg("Warning: Got ICMP %d (%s)", - icmppkt->icmp_type, icmp_type_name (icmppkt->icmp_type)); -} - -static void ping(const char *host) -{ - struct hostent *h; - char buf[MAXHOSTNAMELEN]; - char packet[datalen + MAXIPLEN + MAXICMPLEN]; - int sockopt; - - pingsock = create_icmp_socket(); - - memset(&pingaddr, 0, sizeof(struct sockaddr_in)); - - pingaddr.sin_family = AF_INET; - h = xgethostbyname(host); - if (h->h_addrtype != AF_INET) - error_msg_and_die("unknown address type; only AF_INET is currently supported."); - - memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr)); - strncpy(buf, h->h_name, sizeof(buf) - 1); - hostname = buf; - - /* enable broadcast pings */ - sockopt = 1; - setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt, - sizeof(sockopt)); - - /* set recv buf for broadcast pings */ - sockopt = 48 * 1024; - setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt, - sizeof(sockopt)); - - printf("PING %s (%s): %d data bytes\n", - hostname, - inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr), - datalen); - - signal(SIGINT, pingstats); - - /* start the ping's going ... */ - sendping(0); - - /* listen for replies */ - while (1) { - struct sockaddr_in from; - socklen_t fromlen = (socklen_t) sizeof(from); - int c; - - if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, - (struct sockaddr *) &from, &fromlen)) < 0) { - if (errno == EINTR) - continue; - perror_msg("recvfrom"); - continue; - } - unpack(packet, c, &from); - if (pingcount > 0 && nreceived >= pingcount) - break; - } - pingstats(0); -} - -extern int ping_main(int argc, char **argv) -{ - char *thisarg; - - datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */ - - argc--; - argv++; - options = 0; - /* Parse any options */ - while (argc >= 1 && **argv == '-') { - thisarg = *argv; - thisarg++; - switch (*thisarg) { - case 'q': - options |= O_QUIET; - break; - case 'c': - if (--argc <= 0) - show_usage(); - argv++; - pingcount = atoi(*argv); - break; - case 's': - if (--argc <= 0) - show_usage(); - argv++; - datalen = atoi(*argv); - break; - default: - show_usage(); - } - argc--; - argv++; - } - if (argc < 1) - show_usage(); - - myid = getpid() & 0xFFFF; - ping(*argv); - return EXIT_SUCCESS; -} -#endif /* ! BB_FEATURE_FANCY_PING */ - -/* - * Copyright (c) 1989 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Mike Muuss. - * - * 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. - */ diff --git a/busybox/networking/route.c b/busybox/networking/route.c deleted file mode 100644 index 9d210af64..000000000 --- a/busybox/networking/route.c +++ /dev/null @@ -1,450 +0,0 @@ -/* route - * - * Similar to the standard Unix route, but with only the necessary - * parts for AF_INET - * - * Bjorn Wesen, Axis Communications AB - * - * Author of the original route: - * Fred N. van Kempen, - * (derived from FvK's 'route.c 1.70 01/04/94') - * - * 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. - * - * displayroute() code added by Vladimir N. Oleynik - * adjustments by Larry Doolittle - */ - -#include -#include -#include -#include -#include // HZ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#define _(x) x - -#define RTACTION_ADD 1 -#define RTACTION_DEL 2 -#define RTACTION_HELP 3 -#define RTACTION_FLUSH 4 -#define RTACTION_SHOW 5 - -#define E_NOTFOUND 8 -#define E_SOCK 7 -#define E_LOOKUP 6 -#define E_VERSION 5 -#define E_USAGE 4 -#define E_OPTERR 3 -#define E_INTERN 2 -#define E_NOSUPP 1 - -/* resolve XXX.YYY.ZZZ.QQQ -> binary */ - -static int -INET_resolve(char *name, struct sockaddr *sa) -{ - struct sockaddr_in *s_in = (struct sockaddr_in *)sa; - - s_in->sin_family = AF_INET; - s_in->sin_port = 0; - - /* Default is special, meaning 0.0.0.0. */ - if (strcmp(name, "default")==0) { - s_in->sin_addr.s_addr = INADDR_ANY; - return 1; - } - /* Look to see if it's a dotted quad. */ - if (inet_aton(name, &s_in->sin_addr)) { - return 0; - } - /* guess not.. */ - return -1; -} - -#if defined (SIOCADDRTOLD) || defined (RTF_IRTT) /* route */ -#define HAVE_NEW_ADDRT 1 -#endif -#ifdef RTF_IRTT /* route */ -#define HAVE_RTF_IRTT 1 -#endif -#ifdef RTF_REJECT /* route */ -#define HAVE_RTF_REJECT 1 -#endif - -#if HAVE_NEW_ADDRT -#define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr) -#define full_mask(x) (x) -#else -#define mask_in_addr(x) ((x).rt_genmask) -#define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr) -#endif - -/* add or delete a route depending on action */ - -static int -INET_setroute(int action, int options, char **args) -{ - struct rtentry rt; - char target[128], gateway[128] = "NONE", netmask[128] = "default"; - int xflag, isnet; - int skfd; - - xflag = 0; - - if (*args == NULL) - show_usage(); - if (strcmp(*args, "-net")==0) { - xflag = 1; - args++; - } else if (strcmp(*args, "-host")==0) { - xflag = 2; - args++; - } - safe_strncpy(target, *args++, (sizeof target)); - - /* Clean out the RTREQ structure. */ - memset((char *) &rt, 0, sizeof(struct rtentry)); - - - if ((isnet = INET_resolve(target, &rt.rt_dst)) < 0) { - error_msg(_("can't resolve %s"), target); - return EXIT_FAILURE; /* XXX change to E_something */ - } - - switch (xflag) { - case 1: - isnet = 1; - break; - - case 2: - isnet = 0; - break; - - default: - break; - } - - /* Fill in the other fields. */ - rt.rt_flags = (RTF_UP | RTF_HOST); - if (isnet) - rt.rt_flags &= ~RTF_HOST; - - while (*args) { - if (strcmp(*args, "metric")==0) { - int metric; - - args++; - if (!*args || !isdigit(**args)) - show_usage(); - metric = atoi(*args); -#if HAVE_NEW_ADDRT - rt.rt_metric = metric + 1; -#else - ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); /* XXX Fixme */ -#endif - args++; - continue; - } - - if (strcmp(*args, "netmask")==0) { - struct sockaddr mask; - - args++; - if (!*args || mask_in_addr(rt)) - show_usage(); - safe_strncpy(netmask, *args, (sizeof netmask)); - if ((isnet = INET_resolve(netmask, &mask)) < 0) { - error_msg(_("can't resolve netmask %s"), netmask); - return E_LOOKUP; - } - rt.rt_genmask = full_mask(mask); - args++; - continue; - } - - if (strcmp(*args, "gw")==0 || strcmp(*args, "gateway")==0) { - args++; - if (!*args) - show_usage(); - if (rt.rt_flags & RTF_GATEWAY) - show_usage(); - safe_strncpy(gateway, *args, (sizeof gateway)); - if ((isnet = INET_resolve(gateway, &rt.rt_gateway)) < 0) { - error_msg(_("can't resolve gw %s"), gateway); - return E_LOOKUP; - } - if (isnet) { - error_msg( - _("%s: cannot use a NETWORK as gateway!"), - gateway); - return E_OPTERR; - } - rt.rt_flags |= RTF_GATEWAY; - args++; - continue; - } - - if (strcmp(*args, "mss")==0) { - args++; - rt.rt_flags |= RTF_MSS; - if (!*args) - show_usage(); - rt.rt_mss = atoi(*args); - args++; - if (rt.rt_mss < 64 || rt.rt_mss > 32768) { - error_msg(_("Invalid MSS.")); - return E_OPTERR; - } - continue; - } - - if (strcmp(*args, "window")==0) { - args++; - if (!*args) - show_usage(); - rt.rt_flags |= RTF_WINDOW; - rt.rt_window = atoi(*args); - args++; - if (rt.rt_window < 128) { - error_msg(_("Invalid window.")); - return E_OPTERR; - } - continue; - } - - if (strcmp(*args, "irtt")==0) { - args++; - if (!*args) - show_usage(); - args++; -#if HAVE_RTF_IRTT - rt.rt_flags |= RTF_IRTT; - rt.rt_irtt = atoi(*(args - 1)); - rt.rt_irtt *= (HZ / 100); /* FIXME */ -#if 0 /* FIXME: do we need to check anything of this? */ - if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) { - error_msg(_("Invalid initial rtt.")); - return E_OPTERR; - } -#endif -#else - ENOSUPP("inet_setroute", "RTF_IRTT"); /* XXX Fixme */ -#endif - continue; - } - - if (strcmp(*args, "reject")==0) { - args++; -#if HAVE_RTF_REJECT - rt.rt_flags |= RTF_REJECT; -#else - ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */ -#endif - continue; - } - if (strcmp(*args, "mod")==0) { - args++; - rt.rt_flags |= RTF_MODIFIED; - continue; - } - if (strcmp(*args, "dyn")==0) { - args++; - rt.rt_flags |= RTF_DYNAMIC; - continue; - } - if (strcmp(*args, "reinstate")==0) { - args++; - rt.rt_flags |= RTF_REINSTATE; - continue; - } - if (strcmp(*args, "device")==0 || strcmp(*args, "dev")==0) { - args++; - if (rt.rt_dev || *args == NULL) - show_usage(); - rt.rt_dev = *args++; - continue; - } - /* nothing matches */ - if (!rt.rt_dev) { - rt.rt_dev = *args++; - if (*args) - show_usage(); /* must be last to catch typos */ - } else { - show_usage(); - } - } - -#if HAVE_RTF_REJECT - if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev) - rt.rt_dev = "lo"; -#endif - - /* sanity checks.. */ - if (mask_in_addr(rt)) { - unsigned long mask = mask_in_addr(rt); - mask = ~ntohl(mask); - if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) { - error_msg( - _("netmask %.8x doesn't make sense with host route"), - (unsigned int)mask); - return E_OPTERR; - } - if (mask & (mask + 1)) { - error_msg(_("bogus netmask %s"), netmask); - return E_OPTERR; - } - mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr; - if (mask & ~mask_in_addr(rt)) { - error_msg(_("netmask doesn't match route address")); - return E_OPTERR; - } - } - /* Fill out netmask if still unset */ - if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST) - mask_in_addr(rt) = 0xffffffff; - - /* Create a socket to the INET kernel. */ - if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - perror("socket"); - return E_SOCK; - } - /* Tell the kernel to accept this route. */ - if (action == RTACTION_DEL) { - if (ioctl(skfd, SIOCDELRT, &rt) < 0) { - perror("SIOCDELRT"); - close(skfd); - return E_SOCK; - } - } else { - if (ioctl(skfd, SIOCADDRT, &rt) < 0) { - perror("SIOCADDRT"); - close(skfd); - return E_SOCK; - } - } - - /* Close the socket. */ - (void) close(skfd); - return EXIT_SUCCESS; -} - -#ifndef RTF_UP -/* Keep this in sync with /usr/src/linux/include/linux/route.h */ -#define RTF_UP 0x0001 /* route usable */ -#define RTF_GATEWAY 0x0002 /* destination is a gateway */ -#define RTF_HOST 0x0004 /* host entry (net otherwise) */ -#define RTF_REINSTATE 0x0008 /* reinstate route after tmout */ -#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */ -#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */ -#define RTF_MTU 0x0040 /* specific MTU for this route */ -#ifndef RTF_MSS -#define RTF_MSS RTF_MTU /* Compatibility :-( */ -#endif -#define RTF_WINDOW 0x0080 /* per route window clamping */ -#define RTF_IRTT 0x0100 /* Initial round trip time */ -#define RTF_REJECT 0x0200 /* Reject route */ -#endif - -static void displayroutes(void) -{ - char buff[256]; - int nl = 0 ; - struct in_addr dest; - struct in_addr gw; - struct in_addr mask; - int flgs, ref, use, metric; - char flags[64]; - unsigned long int d,g,m; - - char sdest[16], sgw[16]; - - - FILE *fp = xfopen("/proc/net/route", "r"); - - while( fgets(buff, sizeof(buff), fp) != NULL ) { - if(nl) { - int ifl = 0; - while(buff[ifl]!=' ' && buff[ifl]!='\t' && buff[ifl]!='\0') - ifl++; - buff[ifl]=0; /* interface */ - if(sscanf(buff+ifl+1, "%lx%lx%X%d%d%d%lx", - &d, &g, &flgs, &ref, &use, &metric, &m)!=7) { - error_msg_and_die( "Unsuported kernel route format\n"); - } - if(nl==1) - printf("Kernel IP routing table\n" - "Destination Gateway Genmask Flags Metric Ref Use Iface\n"); - - ifl = 0; /* parse flags */ - if(flgs&RTF_UP) { - if(flgs&RTF_REJECT) - flags[ifl++]='!'; - else - flags[ifl++]='U'; - if(flgs&RTF_GATEWAY) - flags[ifl++]='G'; - if(flgs&RTF_HOST) - flags[ifl++]='H'; - if(flgs&RTF_REINSTATE) - flags[ifl++]='R'; - if(flgs&RTF_DYNAMIC) - flags[ifl++]='D'; - if(flgs&RTF_MODIFIED) - flags[ifl++]='M'; - flags[ifl]=0; - dest.s_addr = d; - gw.s_addr = g; - mask.s_addr = m; - strcpy(sdest, (dest.s_addr==0 ? "default" : - inet_ntoa(dest))); - strcpy(sgw, (gw.s_addr==0 ? "*" : - inet_ntoa(gw))); - printf("%-16s%-16s%-16s%-6s%-6d %-2d %7d %s\n", - sdest, sgw, - inet_ntoa(mask), - flags, metric, ref, use, buff); - } - } - nl++; - } -} - -int route_main(int argc, char **argv) -{ - int what = 0; - - argc--; - argv++; - - if (*argv == NULL) { - displayroutes(); - return EXIT_SUCCESS; - } else { - /* check verb */ - if (strcmp(*argv, "add")==0) - what = RTACTION_ADD; - else if (strcmp(*argv, "del")==0 || strcmp(*argv, "delete")==0) - what = RTACTION_DEL; - else if (strcmp(*argv, "flush")==0) - what = RTACTION_FLUSH; - else - show_usage(); - } - - return INET_setroute(what, 0, ++argv); -} diff --git a/busybox/networking/telnet.c b/busybox/networking/telnet.c deleted file mode 100644 index ce82a0ee8..000000000 --- a/busybox/networking/telnet.c +++ /dev/null @@ -1,711 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * telnet implementation for busybox - * - * Author: Tomi Ollila - * Copyright (C) 1994-2000 by Tomi Ollila - * - * Created: Thu Apr 7 13:29:41 1994 too - * Last modified: Fri Jun 9 14:34:24 2000 too - * - * 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 - * - * HISTORY - * Revision 3.1 1994/04/17 11:31:54 too - * initial revision - * Modified 2000/06/13 for inclusion into BusyBox by Erik Andersen - * - * Modified 2001/05/07 to add ability to pass TTYPE to remote host by Jim McQuillan - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#if 0 -static const int DOTRACE = 1; -#endif - -#ifdef DOTRACE -#include /* for inet_ntoa()... */ -#define TRACE(x, y) do { if (x) printf y; } while (0) -#else -#define TRACE(x, y) -#endif - -#if 0 -#define USE_POLL -#include -#else -#include -#endif - -#define DATABUFSIZE 128 -#define IACBUFSIZE 128 - -static const int CHM_TRY = 0; -static const int CHM_ON = 1; -static const int CHM_OFF = 2; - -static const int UF_ECHO = 0x01; -static const int UF_SGA = 0x02; - -enum { - TS_0 = 1, - TS_IAC = 2, - TS_OPT = 3, - TS_SUB1 = 4, - TS_SUB2 = 5, -}; - -#define WriteCS(fd, str) write(fd, str, sizeof str -1) - -typedef unsigned char byte; - -/* use globals to reduce size ??? */ /* test this hypothesis later */ -static struct Globalvars { - int netfd; /* console fd:s are 0 and 1 (and 2) */ - /* same buffer used both for network and console read/write */ - char buf[DATABUFSIZE]; /* allocating so static size is smaller */ - byte telstate; /* telnet negotiation state from network input */ - byte telwish; /* DO, DONT, WILL, WONT */ - byte charmode; - byte telflags; - byte gotsig; - /* buffer to handle telnet negotiations */ - char iacbuf[IACBUFSIZE]; - short iaclen; /* could even use byte */ - struct termios termios_def; - struct termios termios_raw; -} G; - -#define xUSE_GLOBALVAR_PTR /* xUSE... -> don't use :D (makes smaller code) */ - -#ifdef USE_GLOBALVAR_PTR -struct Globalvars * Gptr; -#define G (*Gptr) -#else -static struct Globalvars G; -#endif - -static inline void iacflush() -{ - write(G.netfd, G.iacbuf, G.iaclen); - G.iaclen = 0; -} - -/* Function prototypes */ -static int getport(char * p); -static struct in_addr getserver(char * p); -static int create_socket(); -static void setup_sockaddr_in(struct sockaddr_in * addr, int port); -static int remote_connect(struct in_addr addr, int port); -static void rawmode(); -static void cookmode(); -static void do_linemode(); -static void will_charmode(); -static void telopt(byte c); -static int subneg(byte c); -#if 0 -static int local_bind(int port); -#endif - -/* Some globals */ -static int one = 1; - -#ifdef BB_FEATURE_TELNET_TTYPE -static char *ttype; -#endif - -static void doexit(int ev) -{ - cookmode(); - exit(ev); -} - -static void conescape() -{ - char b; - - if (G.gotsig) /* came from line mode... go raw */ - rawmode(); - - WriteCS(1, "\r\nConsole escape. Commands are:\r\n\n" - " l go to line mode\r\n" - " c go to character mode\r\n" - " z suspend telnet\r\n" - " e exit telnet\r\n"); - - if (read(0, &b, 1) <= 0) - doexit(1); - - switch (b) - { - case 'l': - if (!G.gotsig) - { - do_linemode(); - goto rrturn; - } - break; - case 'c': - if (G.gotsig) - { - will_charmode(); - goto rrturn; - } - break; - case 'z': - cookmode(); - kill(0, SIGTSTP); - rawmode(); - break; - case 'e': - doexit(0); - } - - WriteCS(1, "continuing...\r\n"); - - if (G.gotsig) - cookmode(); - - rrturn: - G.gotsig = 0; - -} -static void handlenetoutput(int len) -{ - /* here we could do smart tricks how to handle 0xFF:s in output - * stream like writing twice every sequence of FF:s (thus doing - * many write()s. But I think interactive telnet application does - * not need to be 100% 8-bit clean, so changing every 0xff:s to - * 0x7f:s */ - - int i; - byte * p = G.buf; - - for (i = len; i > 0; i--, p++) - { - if (*p == 0x1d) - { - conescape(); - return; - } - if (*p == 0xff) - *p = 0x7f; - } - write(G.netfd, G.buf, len); -} - - -static void handlenetinput(int len) -{ - int i; - int cstart = 0; - - for (i = 0; i < len; i++) - { - byte c = G.buf[i]; - - if (G.telstate == 0) /* most of the time state == 0 */ - { - if (c == IAC) - { - cstart = i; - G.telstate = TS_IAC; - } - } - else - switch (G.telstate) - { - case TS_0: - if (c == IAC) - G.telstate = TS_IAC; - else - G.buf[cstart++] = c; - break; - - case TS_IAC: - if (c == IAC) /* IAC IAC -> 0xFF */ - { - G.buf[cstart++] = c; - G.telstate = TS_0; - break; - } - /* else */ - switch (c) - { - case SB: - G.telstate = TS_SUB1; - break; - case DO: - case DONT: - case WILL: - case WONT: - G.telwish = c; - G.telstate = TS_OPT; - break; - default: - G.telstate = TS_0; /* DATA MARK must be added later */ - } - break; - case TS_OPT: /* WILL, WONT, DO, DONT */ - telopt(c); - G.telstate = TS_0; - break; - case TS_SUB1: /* Subnegotiation */ - case TS_SUB2: /* Subnegotiation */ - if (subneg(c) == TRUE) - G.telstate = TS_0; - break; - } - } - if (G.telstate) - { - if (G.iaclen) iacflush(); - if (G.telstate == TS_0) G.telstate = 0; - - len = cstart; - } - - if (len) - write(1, G.buf, len); -} - - -/* ******************************* */ - -static inline void putiac(int c) -{ - G.iacbuf[G.iaclen++] = c; -} - - -static void putiac2(byte wwdd, byte c) -{ - if (G.iaclen + 3 > IACBUFSIZE) - iacflush(); - - putiac(IAC); - putiac(wwdd); - putiac(c); -} - -#if 0 -static void putiac1(byte c) -{ - if (G.iaclen + 2 > IACBUFSIZE) - iacflush(); - - putiac(IAC); - putiac(c); -} -#endif - -#ifdef BB_FEATURE_TELNET_TTYPE -static void putiac_subopt(byte c, char *str) -{ - int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 ) - - if (G.iaclen + len > IACBUFSIZE) - iacflush(); - - putiac(IAC); - putiac(SB); - putiac(c); - putiac(0); - - while(*str) - putiac(*str++); - - putiac(IAC); - putiac(SE); -} -#endif - -/* void putiacstring (subneg strings) */ - -/* ******************************* */ - -static char const escapecharis[] = "\r\nEscape character is "; - -static void setConMode() -{ - if (G.telflags & UF_ECHO) - { - if (G.charmode == CHM_TRY) { - G.charmode = CHM_ON; - printf("\r\nEntering character mode%s'^]'.\r\n", escapecharis); - rawmode(); - } - } - else - { - if (G.charmode != CHM_OFF) { - G.charmode = CHM_OFF; - printf("\r\nEntering line mode%s'^C'.\r\n", escapecharis); - cookmode(); - } - } -} - -/* ******************************* */ - -static void will_charmode() -{ - G.charmode = CHM_TRY; - G.telflags |= (UF_ECHO | UF_SGA); - setConMode(); - - putiac2(DO, TELOPT_ECHO); - putiac2(DO, TELOPT_SGA); - iacflush(); -} - -static void do_linemode() -{ - G.charmode = CHM_TRY; - G.telflags &= ~(UF_ECHO | UF_SGA); - setConMode(); - - putiac2(DONT, TELOPT_ECHO); - putiac2(DONT, TELOPT_SGA); - iacflush(); -} - -/* ******************************* */ - -static inline void to_notsup(char c) -{ - if (G.telwish == WILL) putiac2(DONT, c); - else if (G.telwish == DO) putiac2(WONT, c); -} - -static inline void to_echo() -{ - /* if server requests ECHO, don't agree */ - if (G.telwish == DO) { putiac2(WONT, TELOPT_ECHO); return; } - else if (G.telwish == DONT) return; - - if (G.telflags & UF_ECHO) - { - if (G.telwish == WILL) - return; - } - else - if (G.telwish == WONT) - return; - - if (G.charmode != CHM_OFF) - G.telflags ^= UF_ECHO; - - if (G.telflags & UF_ECHO) - putiac2(DO, TELOPT_ECHO); - else - putiac2(DONT, TELOPT_ECHO); - - setConMode(); - WriteCS(1, "\r\n"); /* sudden modec */ -} - -static inline void to_sga() -{ - /* daemon always sends will/wont, client do/dont */ - - if (G.telflags & UF_SGA) - { - if (G.telwish == WILL) - return; - } - else - if (G.telwish == WONT) - return; - - if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */ - putiac2(DO, TELOPT_SGA); - else - putiac2(DONT, TELOPT_SGA); - - return; -} - -#ifdef BB_FEATURE_TELNET_TTYPE -static inline void to_ttype() -{ - /* Tell server we will (or won't) do TTYPE */ - - if(ttype) - putiac2(WILL, TELOPT_TTYPE); - else - putiac2(WONT, TELOPT_TTYPE); - - return; -} -#endif - -static void telopt(byte c) -{ - switch (c) - { - case TELOPT_ECHO: to_echo(c); break; - case TELOPT_SGA: to_sga(c); break; -#ifdef BB_FEATURE_TELNET_TTYPE - case TELOPT_TTYPE: to_ttype(c); break; -#endif - default: to_notsup(c); break; - } -} - - -/* ******************************* */ - -/* subnegotiation -- ignore all (except TTYPE) */ - -static int subneg(byte c) -{ - switch (G.telstate) - { - case TS_SUB1: - if (c == IAC) - G.telstate = TS_SUB2; -#ifdef BB_FEATURE_TELNET_TTYPE - else - if (c == TELOPT_TTYPE) - putiac_subopt(TELOPT_TTYPE,ttype); -#endif - break; - case TS_SUB2: - if (c == SE) - return TRUE; - G.telstate = TS_SUB1; - /* break; */ - } - return FALSE; -} - -/* ******************************* */ - -static void fgotsig(int sig) -{ - G.gotsig = sig; -} - - -static void rawmode() -{ - tcsetattr(0, TCSADRAIN, &G.termios_raw); -} - -static void cookmode() -{ - tcsetattr(0, TCSADRAIN, &G.termios_def); -} - -extern int telnet_main(int argc, char** argv) -{ - struct in_addr host; - int port; - int len; -#ifdef USE_POLL - struct pollfd ufds[2]; -#else - fd_set readfds; - int maxfd; -#endif - -#ifdef BB_FEATURE_TELNET_TTYPE - ttype = getenv("TERM"); -#endif - - memset(&G, 0, sizeof G); - - if (tcgetattr(0, &G.termios_def) < 0) - exit(1); - - G.termios_raw = G.termios_def; - cfmakeraw(&G.termios_raw); - - if (argc < 2) show_usage(); - port = (argc > 2)? getport(argv[2]): 23; - - host = getserver(argv[1]); - - G.netfd = remote_connect(host, port); - - signal(SIGINT, fgotsig); - -#ifdef USE_POLL - ufds[0].fd = 0; ufds[1].fd = G.netfd; - ufds[0].events = ufds[1].events = POLLIN; -#else - FD_ZERO(&readfds); - FD_SET(0, &readfds); - FD_SET(G.netfd, &readfds); - maxfd = G.netfd + 1; -#endif - - while (1) - { -#ifndef USE_POLL - fd_set rfds = readfds; - - switch (select(maxfd, &rfds, NULL, NULL, NULL)) -#else - switch (poll(ufds, 2, -1)) -#endif - { - case 0: - /* timeout */ - case -1: - /* error, ignore and/or log something, bay go to loop */ - if (G.gotsig) - conescape(); - else - sleep(1); - break; - default: - -#ifdef USE_POLL - if (ufds[0].revents) /* well, should check POLLIN, but ... */ -#else - if (FD_ISSET(0, &rfds)) -#endif - { - len = read(0, G.buf, DATABUFSIZE); - - if (len <= 0) - doexit(0); - - TRACE(0, ("Read con: %d\n", len)); - - handlenetoutput(len); - } - -#ifdef USE_POLL - if (ufds[1].revents) /* well, should check POLLIN, but ... */ -#else - if (FD_ISSET(G.netfd, &rfds)) -#endif - { - len = read(G.netfd, G.buf, DATABUFSIZE); - - if (len <= 0) - { - WriteCS(1, "Connection closed by foreign host.\r\n"); - doexit(1); - } - TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len)); - - handlenetinput(len); - } - } - } -} - -static int getport(char * p) -{ - unsigned int port = atoi(p); - - if ((unsigned)(port - 1 ) > 65534) - { - error_msg_and_die("%s: bad port number", p); - } - return port; -} - -static struct in_addr getserver(char * host) -{ - struct in_addr addr; - - struct hostent * he; - he = xgethostbyname(host); - memcpy(&addr, he->h_addr, sizeof addr); - - TRACE(1, ("addr: %s\n", inet_ntoa(addr))); - - return addr; -} - -static int create_socket() -{ - return socket(AF_INET, SOCK_STREAM, 0); -} - -static void setup_sockaddr_in(struct sockaddr_in * addr, int port) -{ - memset(addr, 0, sizeof(struct sockaddr_in)); - addr->sin_family = AF_INET; - addr->sin_port = htons(port); -} - -#if 0 -static int local_bind(int port) -{ - struct sockaddr_in s_addr; - int s = create_socket(); - - setup_sockaddr_in(&s_addr, port); - - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one); - - if (bind(s, &s_addr, sizeof s_addr) < 0) - { - char * e = sys_errlist[errno]; - syserrorexit("bind"); - exit(1); - } - listen(s, 1); - - return s; -} -#endif - -static int remote_connect(struct in_addr addr, int port) -{ - struct sockaddr_in s_addr; - int s = create_socket(); - - setup_sockaddr_in(&s_addr, port); - s_addr.sin_addr = addr; - - setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one); - - if (connect(s, (struct sockaddr *)&s_addr, sizeof s_addr) < 0) - { - perror_msg_and_die("Unable to connect to remote host"); - } - return s; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ - diff --git a/busybox/networking/tftp.c b/busybox/networking/tftp.c deleted file mode 100644 index 999b5d706..000000000 --- a/busybox/networking/tftp.c +++ /dev/null @@ -1,383 +0,0 @@ -/* ------------------------------------------------------------------------- */ -/* tftp.c */ -/* */ -/* A simple tftp client for busybox. */ -/* Tries to follow RFC1350. */ -/* Only "octet" mode and 512-byte data blocks are supported. */ -/* */ -/* Copyright (C) 2001 Magnus Damm */ -/* */ -/* Parts of the code based on: */ -/* */ -/* atftp: Copyright (C) 2000 Jean-Pierre Lefebvre */ -/* and Remi Lefebvre */ -/* */ -/* utftp: Copyright (C) 1999 Uwe Ohse */ -/* */ -/* 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 -#include -#include - -#include "busybox.h" - -//#define BB_FEATURE_TFTP_DEBUG - -static const char *tftp_error_msg[] = { - "Undefined error", - "File not found", - "Access violation", - "Disk full or allocation error", - "Illegal TFTP operation", - "Unknown transfer ID", - "File already exists", - "No such user" -}; - -const int tftp_cmd_get = 1; -const int tftp_cmd_put = 2; - -static inline int tftp(const int cmd, const struct hostent *host, - const char *serverfile, int localfd, const int port, int tftp_bufsize) -{ - const int cmd_get = cmd & tftp_cmd_get; - const int cmd_put = cmd & tftp_cmd_put; - const int bb_tftp_num_retries = 5; - - struct sockaddr_in sa; - struct sockaddr_in from; - struct timeval tv; - socklen_t fromlen; - fd_set rfds; - char *cp; - unsigned short tmp; - int socketfd; - int len; - int opcode = 0; - int finished = 0; - int timeout = bb_tftp_num_retries; - int block_nr = 1; - RESERVE_BB_BUFFER(buf, tftp_bufsize + 4); // Why 4 ? - - tftp_bufsize += 4; - - if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { - perror_msg("socket"); - return EXIT_FAILURE; - } - - len = sizeof(sa); - - memset(&sa, 0, len); - bind(socketfd, (struct sockaddr *)&sa, len); - - sa.sin_family = host->h_addrtype; - sa.sin_port = htons(port); - memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr, - sizeof(sa.sin_addr)); - - /* build opcode */ - - if (cmd_get) { - opcode = 1; // read request = 1 - } - - if (cmd_put) { - opcode = 2; // write request = 2 - } - - while (1) { - - - /* build packet of type "opcode" */ - - - cp = buf; - - *((unsigned short *) cp) = htons(opcode); - - cp += 2; - - /* add filename and mode */ - - if ((cmd_get && (opcode == 1)) || // read request = 1 - (cmd_put && (opcode == 2))) { // write request = 2 - - /* what is this trying to do ? */ - while (cp != &buf[tftp_bufsize - 1]) { - if ((*cp = *serverfile++) == '\0') - break; - cp++; - } - /* and this ? */ - if ((*cp != '\0') || (&buf[tftp_bufsize - 1] - cp) < 7) { - error_msg("too long server-filename"); - break; - } - - memcpy(cp + 1, "octet", 6); - cp += 7; - } - - /* add ack and data */ - - if ((cmd_get && (opcode == 4)) || // acknowledgement = 4 - (cmd_put && (opcode == 3))) { // data packet == 3 - - *((unsigned short *) cp) = htons(block_nr); - - cp += 2; - - block_nr++; - - if (cmd_put && (opcode == 3)) { // data packet == 3 - len = read(localfd, cp, tftp_bufsize - 4); - - if (len < 0) { - perror_msg("read"); - break; - } - - if (len != (tftp_bufsize - 4)) { - finished++; - } - - cp += len; - } else if (finished) { - break; - } - } - - - /* send packet */ - - - do { - - len = cp - buf; - -#ifdef BB_FEATURE_TFTP_DEBUG - printf("sending %u bytes\n", len); - for (cp = buf; cp < &buf[len]; cp++) - printf("%02x ", *cp); - printf("\n"); -#endif - if (sendto(socketfd, buf, len, 0, - (struct sockaddr *) &sa, sizeof(sa)) < 0) { - perror_msg("send"); - len = -1; - break; - } - - - /* receive packet */ - - - memset(&from, 0, sizeof(from)); - fromlen = sizeof(from); - - tv.tv_sec = 5; // BB_TFPT_TIMEOUT = 5 - tv.tv_usec = 0; - - FD_ZERO(&rfds); - FD_SET(socketfd, &rfds); - - switch (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) { - case 1: - len = recvfrom(socketfd, buf, tftp_bufsize, 0, - (struct sockaddr *) &from, &fromlen); - - if (len < 0) { - perror_msg("recvfrom"); - break; - } - - timeout = 0; - - if (sa.sin_port == htons(port)) { - sa.sin_port = from.sin_port; - } - if (sa.sin_port == from.sin_port) { - break; - } - - /* fall-through for bad packets! */ - /* discard the packet - treat as timeout */ - timeout = bb_tftp_num_retries; - - case 0: - error_msg("timeout"); - - if (timeout == 0) { - len = -1; - error_msg("last timeout"); - } else { - timeout--; - } - break; - - default: - perror_msg("select"); - len = -1; - } - - } while (timeout && (len >= 0)); - - if (len < 0) { - break; - } - - /* process received packet */ - - - opcode = ntohs(*((unsigned short *) buf)); - tmp = ntohs(*((unsigned short *) &buf[2])); - -#ifdef BB_FEATURE_TFTP_DEBUG - printf("received %d bytes: %04x %04x\n", len, opcode, tmp); -#endif - - if (cmd_get && (opcode == 3)) { // data packet == 3 - - if (tmp == block_nr) { - len = write(localfd, &buf[4], len - 4); - - if (len < 0) { - perror_msg("write"); - break; - } - - if (len != (tftp_bufsize - 4)) { - finished++; - } - - opcode = 4; // acknowledgement = 4 - continue; - } - } - - if (cmd_put && (opcode == 4)) { // acknowledgement = 4 - - if (tmp == (block_nr - 1)) { - if (finished) { - break; - } - - opcode = 3; // data packet == 3 - continue; - } - } - - if (opcode == 5) { // error code == 5 - char *msg = NULL; - - if (buf[4] != '\0') { - msg = &buf[4]; - buf[tftp_bufsize - 1] = '\0'; - } else if (tmp < (sizeof(tftp_error_msg) / sizeof(char *))) { - msg = (char *) tftp_error_msg[tmp]; - } - - if (msg) { - error_msg("server says: %s", msg); - } - - break; - } - } - - close(socketfd); - - return finished ? EXIT_SUCCESS : EXIT_FAILURE; -} - -int tftp_main(int argc, char **argv) -{ - struct hostent *host = NULL; - char *localfile = NULL; - char *remotefile = NULL; - int port = 69; - int cmd = 0; - int fd = -1; - int flags = 0; - int opt; - int result; - int blocksize = 512; - - while ((opt = getopt(argc, argv, "b:gpl:r:")) != -1) { - switch (opt) { - case 'b': - blocksize = atoi(optarg); - break; -#ifdef BB_FEATURE_TFTP_GET - case 'g': - cmd = tftp_cmd_get; - flags = O_WRONLY | O_CREAT; - break; -#endif -#ifdef BB_FEATURE_TFTP_PUT - case 'p': - cmd = tftp_cmd_put; - flags = O_RDONLY; - break; -#endif - case 'l': - localfile = xstrdup(optarg); - break; - case 'r': - remotefile = xstrdup(optarg); - break; - } - } - - if ((cmd == 0) || (optind == argc)) { - show_usage(); - } - - fd = open(localfile, flags, 0644); - if (fd < 0) { - perror_msg_and_die("local file"); - } - - host = xgethostbyname(argv[optind]); - - if (optind + 2 == argc) { - port = atoi(argv[optind + 1]); - } - -#ifdef BB_FEATURE_TFTP_DEBUG - printf("using server \"%s\", serverfile \"%s\"," - "localfile \"%s\".\n", - inet_ntoa(*((struct in_addr *) host->h_addr)), - remotefile, localfile); -#endif - - result = tftp(cmd, host, remotefile, fd, port, blocksize); - close(fd); - - return(result); -} \ No newline at end of file diff --git a/busybox/networking/traceroute.c b/busybox/networking/traceroute.c deleted file mode 100644 index a3abd0a00..000000000 --- a/busybox/networking/traceroute.c +++ /dev/null @@ -1,652 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Van Jacobson. - * - * Special for busybox ported by Vladimir Oleynik 2001 - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. - */ - -/* - * traceroute host - trace the route ip packets follow going to "host". - * Notes - * ----- - * This program must be run by root or be setuid. (I suggest that - * you *don't* make it setuid -- casual use could result in a lot - * of unnecessary traffic on our poor, congested nets.) - * - * I stole the idea for this program from Steve Deering. Since - * the first release, I've learned that had I attended the right - * IETF working group meetings, I also could have stolen it from Guy - * Almes or Matt Mathis. I don't know (or care) who came up with - * the idea first. I envy the originators' perspicacity and I'm - * glad they didn't keep the idea a secret. - * - * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or - * enhancements to the original distribution. - * - * I've hacked up a round-trip-route version of this that works by - * sending a loose-source-routed udp datagram through the destination - * back to yourself. Unfortunately, SO many gateways botch source - * routing, the thing is almost worthless. Maybe one day... - * - * -- Van Jacobson (van@helios.ee.lbl.gov) - * Tue Dec 20 03:50:13 PST 1988 - */ - -#undef BB_FEATURE_TRACEROUTE_VERBOSE -//#define BB_FEATURE_TRACEROUTE_VERBOSE -#undef BB_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - /* It turns out that libc5 doesn't have proper icmp support - * built into it header files, so we have to supplement it */ -#if __GNU_LIBRARY__ < 5 -static const int ICMP_MINLEN = 8; /* abs minimum */ - -struct icmp_ra_addr -{ - u_int32_t ira_addr; - u_int32_t ira_preference; -}; - - -struct icmp -{ - u_int8_t icmp_type; /* type of message, see below */ - u_int8_t icmp_code; /* type sub code */ - u_int16_t icmp_cksum; /* ones complement checksum of struct */ - union - { - u_char ih_pptr; /* ICMP_PARAMPROB */ - struct in_addr ih_gwaddr; /* gateway address */ - struct ih_idseq /* echo datagram */ - { - u_int16_t icd_id; - u_int16_t icd_seq; - } ih_idseq; - u_int32_t ih_void; - - /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ - struct ih_pmtu - { - u_int16_t ipm_void; - u_int16_t ipm_nextmtu; - } ih_pmtu; - - struct ih_rtradv - { - u_int8_t irt_num_addrs; - u_int8_t irt_wpa; - u_int16_t irt_lifetime; - } ih_rtradv; - } icmp_hun; -#define icmp_pptr icmp_hun.ih_pptr -#define icmp_gwaddr icmp_hun.ih_gwaddr -#define icmp_id icmp_hun.ih_idseq.icd_id -#define icmp_seq icmp_hun.ih_idseq.icd_seq -#define icmp_void icmp_hun.ih_void -#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void -#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu -#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs -#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa -#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime - union - { - struct - { - u_int32_t its_otime; - u_int32_t its_rtime; - u_int32_t its_ttime; - } id_ts; - struct - { - struct ip idi_ip; - /* options and then 64 bits of data */ - } id_ip; - struct icmp_ra_addr id_radv; - u_int32_t id_mask; - u_int8_t id_data[1]; - } icmp_dun; -#define icmp_otime icmp_dun.id_ts.its_otime -#define icmp_rtime icmp_dun.id_ts.its_rtime -#define icmp_ttime icmp_dun.id_ts.its_ttime -#define icmp_ip icmp_dun.id_ip.idi_ip -#define icmp_radv icmp_dun.id_radv -#define icmp_mask icmp_dun.id_mask -#define icmp_data icmp_dun.id_data -}; - -#define ICMP_MINLEN 8 /* abs minimum */ -#define ICMP_UNREACH 3 /* dest unreachable, codes: */ -#define ICMP_TIMXCEED 11 /* time exceeded, code: */ -#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ -#define ICMP_UNREACH_NET 0 /* bad net */ -#define ICMP_UNREACH_HOST 1 /* bad host */ -#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ -#define ICMP_UNREACH_PORT 3 /* bad port */ -#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ -#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ -#endif - - -#define MAXPACKET 65535 /* max ip packet size */ -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 64 -#endif - -/* - * format of a (udp) probe packet. - */ -struct opacket { - struct ip ip; - struct udphdr udp; - u_char seq; /* sequence number of this packet */ - u_char ttl; /* ttl packet left with */ - struct timeval tv; /* time packet left */ -}; - -/* - * Definitions for internet protocol version 4. - * Per RFC 791, September 1981. - */ -#define IPVERSION 4 - - -#include "busybox.h" - -static u_char packet[512]; /* last inbound (icmp) packet */ -static struct opacket *outpacket; /* last output (udp) packet */ - -static int s; /* receive (icmp) socket file descriptor */ -static int sndsock; /* send (udp) socket file descriptor */ - -static struct sockaddr whereto; /* Who to try to reach */ -static int datalen; /* How much data */ - -static char *hostname; - -static int max_ttl = 30; -static u_short ident; -static u_short port = 32768+666; /* start udp dest port # for probe packets */ - -#ifdef BB_FEATURE_TRACEROUTE_VERBOSE -static int verbose; -#endif -static int waittime = 5; /* time to wait for response (in seconds) */ -static int nflag; /* print addresses numerically */ - -/* - * Construct an Internet address representation. - * If the nflag has been supplied, give - * numeric value, otherwise try for symbolic name. - */ -static inline void -inetname(struct sockaddr_in *from) -{ - char *cp; - struct hostent *hp; - static char domain[MAXHOSTNAMELEN + 1]; - static int first = 1; - const char *ina; - - if (first && !nflag) { - first = 0; - if (gethostname(domain, MAXHOSTNAMELEN) == 0 && - (cp = strchr(domain, '.'))) - (void) strcpy(domain, cp + 1); - else - domain[0] = 0; - } - cp = 0; - if (!nflag && from->sin_addr.s_addr != INADDR_ANY) { - hp = gethostbyaddr((char *)&(from->sin_addr), sizeof (from->sin_addr), AF_INET); - if (hp) { - if ((cp = strchr(hp->h_name, '.')) && - !strcmp(cp + 1, domain)) - *cp = 0; - cp = (char *)hp->h_name; - } - } - ina = inet_ntoa(from->sin_addr); - if (nflag) - printf(" %s", ina); - else - printf(" %s (%s)", (cp ? cp : ina), ina); -} - -static inline void -print(u_char *buf, int cc, struct sockaddr_in *from) -{ - struct ip *ip; - int hlen; - - ip = (struct ip *) buf; - hlen = ip->ip_hl << 2; - cc -= hlen; - - inetname(from); -#ifdef BB_FEATURE_TRACEROUTE_VERBOSE - if (verbose) - printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); -#endif -} - -static inline double -deltaT(struct timeval *t1p, struct timeval *t2p) -{ - double dt; - - dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + - (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; - return (dt); -} - -static inline int -wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer) -{ - fd_set fds; - static struct timeval wait; - int cc = 0; - int fromlen = sizeof (*from); - - FD_ZERO(&fds); - FD_SET(sock, &fds); - if (reset_timer) { - /* - * traceroute could hang if someone else has a ping - * running and our ICMP reply gets dropped but we don't - * realize it because we keep waking up to handle those - * other ICMP packets that keep coming in. To fix this, - * "reset_timer" will only be true if the last packet that - * came in was for us or if this is the first time we're - * waiting for a reply since sending out a probe. Note - * that this takes advantage of the select() feature on - * Linux where the remaining timeout is written to the - * struct timeval area. - */ - wait.tv_sec = waittime; - wait.tv_usec = 0; - } - - if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0) - cc=recvfrom(s, (char *)packet, sizeof(packet), 0, - (struct sockaddr *)from, &fromlen); - - return(cc); -} - -#ifdef BB_FEATURE_TRACEROUTE_VERBOSE -/* - * Convert an ICMP "type" field to a printable string. - */ -static inline const char * -pr_type(t) - u_char t; -{ - static const char * const ttab[] = { - "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", - "Source Quench", "Redirect", "ICMP 6", "ICMP 7", - "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", - "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", - "Info Reply" - }; - - if(t > 16) - return("OUT-OF-RANGE"); - - return(ttab[t]); -} -#endif - -static inline int -packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq) -{ - struct icmp *icp; - u_char type, code; - int hlen; - struct ip *ip; - - ip = (struct ip *) buf; - hlen = ip->ip_hl << 2; - if (cc < hlen + ICMP_MINLEN) { -#ifdef BB_FEATURE_TRACEROUTE_VERBOSE - if (verbose) - printf("packet too short (%d bytes) from %s\n", cc, - inet_ntoa(from->sin_addr)); -#endif - return (0); - } - cc -= hlen; - icp = (struct icmp *)(buf + hlen); - type = icp->icmp_type; code = icp->icmp_code; - if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || - type == ICMP_UNREACH) { - struct ip *hip; - struct udphdr *up; - - hip = &icp->icmp_ip; - hlen = hip->ip_hl << 2; - up = (struct udphdr *)((u_char *)hip + hlen); - if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP && - up->source == htons(ident) && - up->dest == htons(port+seq)) - return (type == ICMP_TIMXCEED? -1 : code+1); - } -#ifdef BB_FEATURE_TRACEROUTE_VERBOSE - if (verbose) { - int i; - u_long *lp = (u_long *)&icp->icmp_ip; - - printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n", - cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst), - type, pr_type(type), icp->icmp_code); - for (i = 4; i < cc ; i += sizeof(long)) - printf("%2d: x%8.8lx\n", i, *lp++); - } -#endif - return(0); -} - -static void /* not inline */ -send_probe(int seq, int ttl) -{ - struct opacket *op = outpacket; - struct ip *ip = &op->ip; - struct udphdr *up = &op->udp; - int i; - struct timezone tz; - - ip->ip_off = 0; - ip->ip_hl = sizeof(*ip) >> 2; - ip->ip_p = IPPROTO_UDP; - ip->ip_len = datalen; - ip->ip_ttl = ttl; - ip->ip_v = IPVERSION; - ip->ip_id = htons(ident+seq); - - up->source = htons(ident); - up->dest = htons(port+seq); - up->len = htons((u_short)(datalen - sizeof(struct ip))); - up->check = 0; - - op->seq = seq; - op->ttl = ttl; - (void) gettimeofday(&op->tv, &tz); - - i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto, - sizeof(struct sockaddr)); - if (i < 0 || i != datalen) { - if (i<0) - perror("sendto"); - printf("traceroute: wrote %s %d chars, ret=%d\n", hostname, - datalen, i); - (void) fflush(stdout); - } -} - - -int -#ifndef BB_TRACEROUTE -main(argc, argv) -#else -traceroute_main(argc, argv) -#endif - int argc; - char *argv[]; -{ - extern char *optarg; - extern int optind; - struct hostent *hp; - struct sockaddr_in from, *to; - int ch, i, on, probe, seq, tos, ttl; - - int options = 0; /* socket options */ - char *source = 0; - int nprobes = 3; - - on = 1; - seq = tos = 0; - to = (struct sockaddr_in *)&whereto; - while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF) - switch(ch) { - case 'd': -#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG - options |= SO_DEBUG; -#endif - break; - case 'm': - max_ttl = atoi(optarg); - if (max_ttl <= 1) - error_msg_and_die("max ttl must be >1."); - break; - case 'n': - nflag++; - break; - case 'p': - port = atoi(optarg); - if (port < 1) - error_msg_and_die("port must be >0."); - break; - case 'q': - nprobes = atoi(optarg); - if (nprobes < 1) - error_msg_and_die("nprobes must be >0."); - break; - case 'r': - options |= SO_DONTROUTE; - break; - case 's': - /* - * set the ip source address of the outbound - * probe (e.g., on a multi-homed host). - */ - source = optarg; - break; - case 't': - tos = atoi(optarg); - if (tos < 0 || tos > 255) - error_msg_and_die("tos must be 0 to 255."); - break; - case 'v': -#ifdef BB_FEATURE_TRACEROUTE_VERBOSE - verbose++; -#endif - break; - case 'w': - waittime = atoi(optarg); - if (waittime <= 1) - error_msg_and_die("wait must be >1 sec."); - break; - default: - show_usage(); - } - argc -= optind; - argv += optind; - - if (argc < 1) - show_usage(); - - setlinebuf (stdout); - - memset(&whereto, 0, sizeof(struct sockaddr)); - hp = xgethostbyname(*argv); - to->sin_family = hp->h_addrtype; - memcpy(&to->sin_addr, hp->h_addr, hp->h_length); - hostname = (char *)hp->h_name; - if (*++argv) - datalen = atoi(*argv); - if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) - error_msg_and_die("packet size must be 0 <= s < %d.", - MAXPACKET - sizeof(struct opacket)); - datalen += sizeof(struct opacket); - outpacket = (struct opacket *)xmalloc((unsigned)datalen); - memset(outpacket, 0, datalen); - outpacket->ip.ip_dst = to->sin_addr; - outpacket->ip.ip_tos = tos; - outpacket->ip.ip_v = IPVERSION; - outpacket->ip.ip_id = 0; - - ident = (getpid() & 0xffff) | 0x8000; - - if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) - perror_msg_and_die(can_not_create_raw_socket); - - s = create_icmp_socket(); - -#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG - if (options & SO_DEBUG) - (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, - (char *)&on, sizeof(on)); -#endif - if (options & SO_DONTROUTE) - (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, - (char *)&on, sizeof(on)); -#ifdef SO_SNDBUF - if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, - sizeof(datalen)) < 0) - perror_msg_and_die("SO_SNDBUF"); -#endif SO_SNDBUF -#ifdef IP_HDRINCL - if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, - sizeof(on)) < 0) - perror_msg_and_die("IP_HDRINCL"); -#endif IP_HDRINCL -#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG - if (options & SO_DEBUG) - (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, - (char *)&on, sizeof(on)); -#endif - if (options & SO_DONTROUTE) - (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, - (char *)&on, sizeof(on)); - - if (source) { - memset(&from, 0, sizeof(struct sockaddr)); - from.sin_family = AF_INET; - from.sin_addr.s_addr = inet_addr(source); - if (from.sin_addr.s_addr == -1) - error_msg_and_die("unknown host %s", source); - outpacket->ip.ip_src = from.sin_addr; -#ifndef IP_HDRINCL - if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) - perror_msg_and_die("bind"); -#endif IP_HDRINCL - } - - fprintf(stderr, "traceroute to %s (%s)", hostname, - inet_ntoa(to->sin_addr)); - if (source) - fprintf(stderr, " from %s", source); - fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen); - - for (ttl = 1; ttl <= max_ttl; ++ttl) { - u_long lastaddr = 0; - int got_there = 0; - int unreachable = 0; - - printf("%2d ", ttl); - for (probe = 0; probe < nprobes; ++probe) { - int cc, reset_timer; - struct timeval t1, t2; - struct timezone tz; - struct ip *ip; - - (void) gettimeofday(&t1, &tz); - send_probe(++seq, ttl); - reset_timer = 1; - while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) { - (void) gettimeofday(&t2, &tz); - if ((i = packet_ok(packet, cc, &from, seq))) { - reset_timer = 1; - if (from.sin_addr.s_addr != lastaddr) { - print(packet, cc, &from); - lastaddr = from.sin_addr.s_addr; - } - printf(" %g ms", deltaT(&t1, &t2)); - switch(i - 1) { - case ICMP_UNREACH_PORT: - ip = (struct ip *)packet; - if (ip->ip_ttl <= 1) - printf(" !"); - ++got_there; - break; - case ICMP_UNREACH_NET: - ++unreachable; - printf(" !N"); - break; - case ICMP_UNREACH_HOST: - ++unreachable; - printf(" !H"); - break; - case ICMP_UNREACH_PROTOCOL: - ++got_there; - printf(" !P"); - break; - case ICMP_UNREACH_NEEDFRAG: - ++unreachable; - printf(" !F"); - break; - case ICMP_UNREACH_SRCFAIL: - ++unreachable; - printf(" !S"); - break; - } - break; - } else - reset_timer = 0; - } - if (cc == 0) - printf(" *"); - (void) fflush(stdout); - } - putchar('\n'); - if (got_there || unreachable >= nprobes-1) - exit(0); - } - - return 0; -} diff --git a/busybox/networking/wget.c b/busybox/networking/wget.c deleted file mode 100644 index 59373d1d9..000000000 --- a/busybox/networking/wget.c +++ /dev/null @@ -1,834 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * wget - retrieve a file using HTTP or FTP - * - * Chip Rosenthal Covad Communications - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include - -#include "busybox.h" - -/* Stupid libc5 doesn't define this... */ -#ifndef timersub -#define timersub(a, b, result) \ - do { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ - --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ - } \ - } while (0) -#endif - -struct host_info { - char *host; - int port; - char *path; - int is_ftp; - char *user; -}; - -static void parse_url(char *url, struct host_info *h); -static FILE *open_socket(char *host, int port); -static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc); -static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf); - -/* Globals (can be accessed from signal handlers */ -static off_t filesize = 0; /* content-length of the file */ -static int chunked = 0; /* chunked transfer encoding */ -#ifdef BB_FEATURE_WGET_STATUSBAR -static void progressmeter(int flag); -static char *curfile; /* Name of current file being transferred. */ -static struct timeval start; /* Time a transfer started. */ -static volatile unsigned long statbytes = 0; /* Number of bytes transferred so far. */ -/* For progressmeter() -- number of seconds before xfer considered "stalled" */ -static const int STALLTIME = 5; -#endif - -static void close_and_delete_outfile(FILE* output, char *fname_out, int do_continue) -{ - if (output != stdout && do_continue==0) { - fclose(output); - unlink(fname_out); - } -} - -/* Read NMEMB elements of SIZE bytes into PTR from STREAM. Returns the - * number of elements read, and a short count if an eof or non-interrupt - * error is encountered. */ -static size_t safe_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) -{ - size_t ret = 0; - - do { - clearerr(stream); - ret += fread((char *)ptr + (ret * size), size, nmemb - ret, stream); - } while (ret < nmemb && ferror(stream) && errno == EINTR); - - return ret; -} - -/* Write NMEMB elements of SIZE bytes from PTR to STREAM. Returns the - * number of elements written, and a short count if an eof or non-interrupt - * error is encountered. */ -static size_t safe_fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream) -{ - size_t ret = 0; - - do { - clearerr(stream); - ret += fwrite((char *)ptr + (ret * size), size, nmemb - ret, stream); - } while (ret < nmemb && ferror(stream) && errno == EINTR); - - return ret; -} - -/* Read a line or SIZE - 1 bytes into S, whichever is less, from STREAM. - * Returns S, or NULL if an eof or non-interrupt error is encountered. */ -static char *safe_fgets(char *s, int size, FILE *stream) -{ - char *ret; - - do { - clearerr(stream); - ret = fgets(s, size, stream); - } while (ret == NULL && ferror(stream) && errno == EINTR); - - return ret; -} - -#define close_delete_and_die(s...) { \ - close_and_delete_outfile(output, fname_out, do_continue); \ - error_msg_and_die(s); } - - -#ifdef BB_FEATURE_WGET_AUTHENTICATION -/* - * Base64-encode character string - * oops... isn't something similar in uuencode.c? - * It would be better to use already existing code - */ -char *base64enc(char *p, char *buf, int len) { - - char al[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - char *s = buf; - - while(*p) { - if (s >= buf+len-4) - error_msg_and_die("buffer overflow"); - *(s++) = al[(*p >> 2) & 0x3F]; - *(s++) = al[((*p << 4) & 0x30) | ((*(p+1) >> 4) & 0x0F)]; - *s = *(s+1) = '='; - *(s+2) = 0; - if (! *(++p)) break; - *(s++) = al[((*p << 2) & 0x3C) | ((*(p+1) >> 6) & 0x03)]; - if (! *(++p)) break; - *(s++) = al[*(p++) & 0x3F]; - } - - return buf; -} -#endif - -int wget_main(int argc, char **argv) -{ - int n, try=5, status; - int port; - char *proxy; - char *dir_prefix=NULL; - char *s, buf[512]; - struct stat sbuf; - char extra_headers[1024]; - char *extra_headers_ptr = extra_headers; - int extra_headers_left = sizeof(extra_headers); - int which_long_opt = 0, option_index = -1; - struct host_info server, target; - - FILE *sfp = NULL; /* socket to web/ftp server */ - FILE *dfp = NULL; /* socket to ftp server (data) */ - char *fname_out = NULL; /* where to direct output (-O) */ - int do_continue = 0; /* continue a prev transfer (-c) */ - long beg_range = 0L; /* range at which continue begins */ - int got_clen = 0; /* got content-length: from server */ - FILE *output; /* socket to web server */ - int quiet_flag = FALSE; /* Be verry, verry quiet... */ - -#define LONG_HEADER 1 - struct option long_options[] = { - { "continue", 0, NULL, 'c' }, - { "quiet", 0, NULL, 'q' }, - { "output-document", 1, NULL, 'O' }, - { "header", 1, &which_long_opt, LONG_HEADER }, - { 0, 0, 0, 0 } - }; - /* - * Crack command line. - */ - while ((n = getopt_long(argc, argv, "cqO:P:", long_options, &option_index)) != EOF) { - switch (n) { - case 'c': - ++do_continue; - break; - case 'P': - dir_prefix = optarg; - break; - case 'q': - quiet_flag = TRUE; - break; - case 'O': - /* can't set fname_out to NULL if outputting to stdout, because - * this gets interpreted as the auto-gen output filename - * case below - tausq@debian.org - */ - fname_out = optarg; - break; - case 0: - switch (which_long_opt) { - case LONG_HEADER: { - int arglen = strlen(optarg); - if(extra_headers_left - arglen - 2 <= 0) - error_msg_and_die("extra_headers buffer too small(need %i)", extra_headers_left - arglen); - strcpy(extra_headers_ptr, optarg); - extra_headers_ptr += arglen; - extra_headers_left -= ( arglen + 2 ); - *extra_headers_ptr++ = '\r'; - *extra_headers_ptr++ = '\n'; - *(extra_headers_ptr + 1) = 0; - break; - } - } - break; - default: - show_usage(); - } - } - - if (argc - optind != 1) - show_usage(); - - parse_url(argv[optind], &target); - server.host = target.host; - server.port = target.port; - - /* - * Use the proxy if necessary. - */ - proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy"); - if (proxy) - parse_url(xstrdup(proxy), &server); - - /* Guess an output filename */ - if (!fname_out) { - fname_out = -#ifdef BB_FEATURE_WGET_STATUSBAR - curfile = -#endif - get_last_path_component(target.path); - if (fname_out==NULL || strlen(fname_out)<1) { - fname_out = -#ifdef BB_FEATURE_WGET_STATUSBAR - curfile = -#endif - "index.html"; - } - if (dir_prefix != NULL) - fname_out = concat_path_file(dir_prefix, fname_out); -#ifdef BB_FEATURE_WGET_STATUSBAR - } else { - curfile = get_last_path_component(fname_out); -#endif - } - if (do_continue && !fname_out) - error_msg_and_die("cannot specify continue (-c) without a filename (-O)"); - - - /* - * Open the output file stream. - */ - if (strcmp(fname_out, "-") == 0) { - output = stdout; - quiet_flag = TRUE; - } else { - output = xfopen(fname_out, (do_continue ? "a" : "w")); - } - - /* - * Determine where to start transfer. - */ - if (do_continue) { - if (fstat(fileno(output), &sbuf) < 0) - perror_msg_and_die("fstat()"); - if (sbuf.st_size > 0) - beg_range = sbuf.st_size; - else - do_continue = 0; - } - - if (proxy || !target.is_ftp) { - /* - * HTTP session - */ - do { - if (! --try) - close_delete_and_die("too many redirections"); - - /* - * Open socket to http server - */ - if (sfp) fclose(sfp); - sfp = open_socket(server.host, server.port); - - /* - * Send HTTP request. - */ - if (proxy) { - fprintf(sfp, "GET %stp://%s:%d/%s HTTP/1.1\r\n", - target.is_ftp ? "f" : "ht", target.host, - target.port, target.path); - } else { - fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); - } - - fprintf(sfp, "Host: %s\r\nUser-Agent: Wget\r\n", target.host); - -#ifdef BB_FEATURE_WGET_AUTHENTICATION - if (target.user) { - fprintf(sfp, "Authorization: Basic %s\r\n", - base64enc(target.user, buf, sizeof(buf))); - } - if (proxy && server.user) { - fprintf(sfp, "Proxy-Authorization: Basic %s\r\n", - base64enc(server.user, buf, sizeof(buf))); - } -#endif - - if (do_continue) - fprintf(sfp, "Range: bytes=%ld-\r\n", beg_range); - if(extra_headers_left < sizeof(extra_headers)) - fputs(extra_headers,sfp); - fprintf(sfp,"Connection: close\r\n\r\n"); - - /* - * Retrieve HTTP response line and check for "200" status code. - */ -read_response: if (fgets(buf, sizeof(buf), sfp) == NULL) - close_delete_and_die("no response from server"); - - for (s = buf ; *s != '\0' && !isspace(*s) ; ++s) - ; - for ( ; isspace(*s) ; ++s) - ; - switch (status = atoi(s)) { - case 0: - case 100: - while (gethdr(buf, sizeof(buf), sfp, &n) != NULL); - goto read_response; - case 200: - if (do_continue && output != stdout) - output = freopen(fname_out, "w", output); - do_continue = 0; - break; - case 300: /* redirection */ - case 301: - case 302: - case 303: - break; - case 206: - if (do_continue) - break; - /*FALLTHRU*/ - default: - chomp(buf); - close_delete_and_die("server returned error %d: %s", atoi(s), buf); - } - - /* - * Retrieve HTTP headers. - */ - while ((s = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) { - if (strcasecmp(buf, "content-length") == 0) { - filesize = atol(s); - got_clen = 1; - continue; - } - if (strcasecmp(buf, "transfer-encoding") == 0) { - if (strcasecmp(s, "chunked") == 0) { - chunked = got_clen = 1; - } else { - close_delete_and_die("server wants to do %s transfer encoding", s); - } - } - if (strcasecmp(buf, "location") == 0) { - if (s[0] == '/') - target.path = xstrdup(s+1); - else { - parse_url(xstrdup(s), &target); - if (!proxy) { - server.host = target.host; - server.port = target.port; - } - } - } - } - } while(status >= 300); - - dfp = sfp; - } - else - { - /* - * FTP session - */ - if (! target.user) - target.user = xstrdup("anonymous:busybox@"); - - sfp = open_socket(server.host, server.port); - if (ftpcmd(NULL, NULL, sfp, buf) != 220) - close_delete_and_die("%s", buf+4); - - /* - * Splitting username:password pair, - * trying to log in - */ - s = strchr(target.user, ':'); - if (s) - *(s++) = '\0'; - switch(ftpcmd("USER ", target.user, sfp, buf)) { - case 230: - break; - case 331: - if (ftpcmd("PASS ", s, sfp, buf) == 230) - break; - /* FALLTHRU (failed login) */ - default: - close_delete_and_die("ftp login: %s", buf+4); - } - - ftpcmd("CDUP", NULL, sfp, buf); - ftpcmd("TYPE I", NULL, sfp, buf); - - /* - * Querying file size - */ - if (ftpcmd("SIZE /", target.path, sfp, buf) == 213) { - filesize = atol(buf+4); - got_clen = 1; - } - - /* - * Entering passive mode - */ - if (ftpcmd("PASV", NULL, sfp, buf) != 227) - close_delete_and_die("PASV: %s", buf+4); - s = strrchr(buf, ','); - *s = 0; - port = atoi(s+1); - s = strrchr(buf, ','); - port += atoi(s+1) * 256; - dfp = open_socket(server.host, port); - - if (do_continue) { - sprintf(buf, "REST %ld", beg_range); - if (ftpcmd(buf, NULL, sfp, buf) != 350) { - if (output != stdout) - output = freopen(fname_out, "w", output); - do_continue = 0; - } else - filesize -= beg_range; - } - - if (ftpcmd("RETR /", target.path, sfp, buf) > 150) - close_delete_and_die("RETR: %s", buf+4); - - } - - - /* - * Retrieve file - */ - if (chunked) { - fgets(buf, sizeof(buf), dfp); - filesize = strtol(buf, (char **) NULL, 16); - } -#ifdef BB_FEATURE_WGET_STATUSBAR - if (quiet_flag==FALSE) - progressmeter(-1); -#endif - do { - while ((filesize > 0 || !got_clen) && (n = safe_fread(buf, 1, chunked ? (filesize > sizeof(buf) ? sizeof(buf) : filesize) : sizeof(buf), dfp)) > 0) { - safe_fwrite(buf, 1, n, output); -#ifdef BB_FEATURE_WGET_STATUSBAR - statbytes+=n; -#endif - if (got_clen) - filesize -= n; - } - - if (chunked) { - safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */ - safe_fgets(buf, sizeof(buf), dfp); - filesize = strtol(buf, (char **) NULL, 16); - if (filesize==0) chunked = 0; /* all done! */ - } - - if (n == 0 && ferror(dfp)) - perror_msg_and_die("network read error"); - } while (chunked); -#ifdef BB_FEATURE_WGET_STATUSBAR - if (quiet_flag==FALSE) - progressmeter(1); -#endif - if (!proxy && target.is_ftp) { - fclose(dfp); - if (ftpcmd(NULL, NULL, sfp, buf) != 226) - error_msg_and_die("ftp error: %s", buf+4); - ftpcmd("QUIT", NULL, sfp, buf); - } - exit(EXIT_SUCCESS); -} - - -void parse_url(char *url, struct host_info *h) -{ - char *cp, *sp, *up; - - if (strncmp(url, "http://", 7) == 0) { - h->port = 80; - h->host = url + 7; - h->is_ftp = 0; - } else if (strncmp(url, "ftp://", 6) == 0) { - h->port = 21; - h->host = url + 6; - h->is_ftp = 1; - } else - error_msg_and_die("not an http or ftp url: %s", url); - - sp = strchr(h->host, '/'); - if (sp != NULL) { - *sp++ = '\0'; - h->path = sp; - } else - h->path = ""; - - up = strrchr(h->host, '@'); - if (up != NULL) { - h->user = h->host; - *up++ = '\0'; - h->host = up; - } else - h->user = NULL; - - cp = strchr(h->host, ':'); - if (cp != NULL) { - *cp++ = '\0'; - h->port = atoi(cp); - } - -} - - -FILE *open_socket(char *host, int port) -{ - struct sockaddr_in s_in; - struct hostent *hp; - int fd; - FILE *fp; - - memset(&s_in, 0, sizeof(s_in)); - s_in.sin_family = AF_INET; - hp = xgethostbyname(host); - memcpy(&s_in.sin_addr, hp->h_addr_list[0], hp->h_length); - s_in.sin_port = htons(port); - - /* - * Get the server onto a stdio stream. - */ - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) - perror_msg_and_die("socket()"); - if (connect(fd, (struct sockaddr *) &s_in, sizeof(s_in)) < 0) - perror_msg_and_die("connect(%s)", host); - if ((fp = fdopen(fd, "r+")) == NULL) - perror_msg_and_die("fdopen()"); - - return fp; -} - - -char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc) -{ - char *s, *hdrval; - int c; - - *istrunc = 0; - - /* retrieve header line */ - if (fgets(buf, bufsiz, fp) == NULL) - return NULL; - - /* see if we are at the end of the headers */ - for (s = buf ; *s == '\r' ; ++s) - ; - if (s[0] == '\n') - return NULL; - - /* convert the header name to lower case */ - for (s = buf ; isalnum(*s) || *s == '-' ; ++s) - *s = tolower(*s); - - /* verify we are at the end of the header name */ - if (*s != ':') - error_msg_and_die("bad header line: %s", buf); - - /* locate the start of the header value */ - for (*s++ = '\0' ; *s == ' ' || *s == '\t' ; ++s) - ; - hdrval = s; - - /* locate the end of header */ - while (*s != '\0' && *s != '\r' && *s != '\n') - ++s; - - /* end of header found */ - if (*s != '\0') { - *s = '\0'; - return hdrval; - } - - /* Rats! The buffer isn't big enough to hold the entire header value. */ - while (c = getc(fp), c != EOF && c != '\n') - ; - *istrunc = 1; - return hdrval; -} - -static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf) -{ - char *p; - - if (s1) { - if (!s2) s2=""; - fprintf(fp, "%s%s\n", s1, s2); - fflush(fp); - } - - do { - p = fgets(buf, 510, fp); - if (!p) - perror_msg_and_die("fgets()"); - } while (! isdigit(buf[0]) || buf[3] != ' '); - - return atoi(buf); -} - -#ifdef BB_FEATURE_WGET_STATUSBAR -/* Stuff below is from BSD rcp util.c, as added to openshh. - * Original copyright notice is retained at the end of this file. - * - */ - - -static int -getttywidth(void) -{ - struct winsize winsize; - - if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1) - return (winsize.ws_col ? winsize.ws_col : 80); - else - return (80); -} - -static void -updateprogressmeter(int ignore) -{ - int save_errno = errno; - - progressmeter(0); - errno = save_errno; -} - -static void -alarmtimer(int wait) -{ - struct itimerval itv; - - itv.it_value.tv_sec = wait; - itv.it_value.tv_usec = 0; - itv.it_interval = itv.it_value; - setitimer(ITIMER_REAL, &itv, NULL); -} - - -static void -progressmeter(int flag) -{ - static const char prefixes[] = " KMGTP"; - static struct timeval lastupdate; - static off_t lastsize, totalsize; - struct timeval now, td, wait; - off_t cursize, abbrevsize; - double elapsed; - int ratio, barlength, i, remaining; - char buf[256]; - - if (flag == -1) { - (void) gettimeofday(&start, (struct timezone *) 0); - lastupdate = start; - lastsize = 0; - totalsize = filesize; /* as filesize changes.. */ - } - - (void) gettimeofday(&now, (struct timezone *) 0); - cursize = statbytes; - if (totalsize != 0 && !chunked) { - ratio = 100.0 * cursize / totalsize; - ratio = MAX(ratio, 0); - ratio = MIN(ratio, 100); - } else - ratio = 100; - - snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ", curfile, ratio); - - barlength = getttywidth() - 51; - if (barlength > 0) { - i = barlength * ratio / 100; - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - "|%.*s%*s|", i, - "*****************************************************************************" - "*****************************************************************************", - barlength - i, ""); - } - i = 0; - abbrevsize = cursize; - while (abbrevsize >= 100000 && i < sizeof(prefixes)) { - i++; - abbrevsize >>= 10; - } - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5d %c%c ", - (int) abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' : - 'B'); - - timersub(&now, &lastupdate, &wait); - if (cursize > lastsize) { - lastupdate = now; - lastsize = cursize; - if (wait.tv_sec >= STALLTIME) { - start.tv_sec += wait.tv_sec; - start.tv_usec += wait.tv_usec; - } - wait.tv_sec = 0; - } - timersub(&now, &start, &td); - elapsed = td.tv_sec + (td.tv_usec / 1000000.0); - - if (wait.tv_sec >= STALLTIME) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - " - stalled -"); - } else if (statbytes <= 0 || elapsed <= 0.0 || cursize > totalsize || chunked) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - " --:-- ETA"); - } else { - remaining = (int) (totalsize / (statbytes / elapsed) - elapsed); - i = remaining / 3600; - if (i) - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - "%2d:", i); - else - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - " "); - i = remaining % 3600; - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - "%02d:%02d ETA", i / 60, i % 60); - } - write(fileno(stderr), buf, strlen(buf)); - - if (flag == -1) { - struct sigaction sa; - sa.sa_handler = updateprogressmeter; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sigaction(SIGALRM, &sa, NULL); - alarmtimer(1); - } else if (flag == 1) { - alarmtimer(0); - statbytes = 0; - putc('\n', stderr); - } -} -#endif - -/* Original copyright notice which applies to the BB_FEATURE_WGET_STATUSBAR stuff, - * much of which was blatently stolen from openssh. */ - -/*- - * Copyright (c) 1992, 1993 - * The 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. - * - * $Id: wget.c,v 1.45 2001/07/19 22:28:01 andersen Exp $ - */ - - - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ - - - diff --git a/busybox/nfsmount.c b/busybox/nfsmount.c deleted file mode 100644 index cd722acc3..000000000 --- a/busybox/nfsmount.c +++ /dev/null @@ -1,977 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * nfsmount.c -- Linux NFS mount - * Copyright (C) 1993 Rick Sladkey - * - * 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. - * - * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port - * numbers to be specified on the command line. - * - * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler : - * Omit the call to connect() for Linux version 1.3.11 or later. - * - * Wed Oct 1 23:55:28 1997: Dick Streefland - * Implemented the "bg", "fg" and "retry" mount options for NFS. - * - * 1999-02-22 Arkadiusz Mi¶kiewicz - * - added Native Language Support - * - * Modified by Olaf Kirch and Trond Myklebust for new NFS code, - * plus NFSv3 stuff. - */ - -/* - * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" -#undef TRUE -#undef FALSE -#include -#include -#include -#include /* For the kernels nfs stuff */ -#include "nfsmount.h" - -#ifndef NFS_FHSIZE -static const int NFS_FHSIZE = 32; -#endif -#ifndef NFS_PORT -static const int NFS_PORT = 2049; -#endif - -/* Disable the nls stuff */ -# undef bindtextdomain -# define bindtextdomain(Domain, Directory) /* empty */ -# undef textdomain -# define textdomain(Domain) /* empty */ -# define _(Text) (Text) -# define N_(Text) (Text) - -static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */ -static const int MS_RDONLY = 1; /* Mount read-only */ -static const int MS_NOSUID = 2; /* Ignore suid and sgid bits */ -static const int MS_NODEV = 4; /* Disallow access to device special files */ -static const int MS_NOEXEC = 8; /* Disallow program execution */ -static const int MS_SYNCHRONOUS = 16; /* Writes are synced at once */ -static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS */ -static const int MS_MANDLOCK = 64; /* Allow mandatory locks on an FS */ -static const int S_QUOTA = 128; /* Quota initialized for file/directory/symlink */ -static const int S_APPEND = 256; /* Append-only file */ -static const int S_IMMUTABLE = 512; /* Immutable file */ -static const int MS_NOATIME = 1024; /* Do not update access times. */ -static const int MS_NODIRATIME = 2048; /* Do not update directory access times */ - - -/* - * We want to be able to compile mount on old kernels in such a way - * that the binary will work well on more recent kernels. - * Thus, if necessary we teach nfsmount.c the structure of new fields - * that will come later. - * - * Moreover, the new kernel includes conflict with glibc includes - * so it is easiest to ignore the kernel altogether (at compile time). - */ - -/* NOTE: Do not make this into a 'static const int' because the pre-processor - * needs to test this value in some #if statements. */ -#define NFS_MOUNT_VERSION 4 - -struct nfs2_fh { - char data[32]; -}; -struct nfs3_fh { - unsigned short size; - unsigned char data[64]; -}; - -struct nfs_mount_data { - int version; /* 1 */ - int fd; /* 1 */ - struct nfs2_fh old_root; /* 1 */ - int flags; /* 1 */ - int rsize; /* 1 */ - int wsize; /* 1 */ - int timeo; /* 1 */ - int retrans; /* 1 */ - int acregmin; /* 1 */ - int acregmax; /* 1 */ - int acdirmin; /* 1 */ - int acdirmax; /* 1 */ - struct sockaddr_in addr; /* 1 */ - char hostname[256]; /* 1 */ - int namlen; /* 2 */ - unsigned int bsize; /* 3 */ - struct nfs3_fh root; /* 4 */ -}; - -/* bits in the flags field */ - -static const int NFS_MOUNT_SOFT = 0x0001; /* 1 */ -static const int NFS_MOUNT_INTR = 0x0002; /* 1 */ -static const int NFS_MOUNT_SECURE = 0x0004; /* 1 */ -static const int NFS_MOUNT_POSIX = 0x0008; /* 1 */ -static const int NFS_MOUNT_NOCTO = 0x0010; /* 1 */ -static const int NFS_MOUNT_NOAC = 0x0020; /* 1 */ -static const int NFS_MOUNT_TCP = 0x0040; /* 2 */ -static const int NFS_MOUNT_VER3 = 0x0080; /* 3 */ -static const int NFS_MOUNT_KERBEROS = 0x0100; /* 3 */ -static const int NFS_MOUNT_NONLM = 0x0200; /* 3 */ - - -#define UTIL_LINUX_VERSION "2.10m" -#define util_linux_version "util-linux-2.10m" - -#define HAVE_inet_aton -#define HAVE_scsi_h -#define HAVE_blkpg_h -#define HAVE_kd_h -#define HAVE_termcap -#define HAVE_locale_h -#define HAVE_libintl_h -#define ENABLE_NLS -#define HAVE_langinfo_h -#define HAVE_progname -#define HAVE_openpty -#define HAVE_nanosleep -#define HAVE_personality -#define HAVE_tm_gmtoff - -static char *nfs_strerror(int status); - -#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r)) -#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2) - -static const int EX_FAIL = 32; /* mount failure */ -static const int EX_BG = 256; /* retry in background (internal only) */ - - -/* - * nfs_mount_version according to the sources seen at compile time. - */ -static int nfs_mount_version; - -/* - * Unfortunately, the kernel prints annoying console messages - * in case of an unexpected nfs mount version (instead of - * just returning some error). Therefore we'll have to try - * and figure out what version the kernel expects. - * - * Variables: - * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time - * NFS_MOUNT_VERSION: these nfsmount sources at compile time - * nfs_mount_version: version this source and running kernel can handle - */ -static void -find_kernel_nfs_mount_version(void) -{ - static int kernel_version = 0; - - if (kernel_version) - return; - - nfs_mount_version = NFS_MOUNT_VERSION; /* default */ - - kernel_version = get_kernel_revision(); - if (kernel_version) { - if (kernel_version < MAKE_VERSION(2,1,32)) - nfs_mount_version = 1; - else if (kernel_version < MAKE_VERSION(2,2,18) || - (kernel_version >= MAKE_VERSION(2,3,0) && - kernel_version < MAKE_VERSION(2,3,99))) - nfs_mount_version = 3; - else - nfs_mount_version = 4; /* since 2.3.99pre4 */ - } - if (nfs_mount_version > NFS_MOUNT_VERSION) - nfs_mount_version = NFS_MOUNT_VERSION; -} - -static struct pmap * -get_mountport(struct sockaddr_in *server_addr, - long unsigned prog, - long unsigned version, - long unsigned proto, - long unsigned port) -{ -struct pmaplist *pmap; -static struct pmap p = {0, 0, 0, 0}; - -server_addr->sin_port = PMAPPORT; -pmap = pmap_getmaps(server_addr); - -if (version > MAX_NFSPROT) - version = MAX_NFSPROT; -if (!prog) - prog = MOUNTPROG; -p.pm_prog = prog; -p.pm_vers = version; -p.pm_prot = proto; -p.pm_port = port; - -while (pmap) { - if (pmap->pml_map.pm_prog != prog) - goto next; - if (!version && p.pm_vers > pmap->pml_map.pm_vers) - goto next; - if (version > 2 && pmap->pml_map.pm_vers != version) - goto next; - if (version && version <= 2 && pmap->pml_map.pm_vers > 2) - goto next; - if (pmap->pml_map.pm_vers > MAX_NFSPROT || - (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) || - (port && pmap->pml_map.pm_port != port)) - goto next; - memcpy(&p, &pmap->pml_map, sizeof(p)); -next: - pmap = pmap->pml_next; -} -if (!p.pm_vers) - p.pm_vers = MOUNTVERS; -if (!p.pm_port) - p.pm_port = MOUNTPORT; -if (!p.pm_prot) - p.pm_prot = IPPROTO_TCP; -return &p; -} - -int nfsmount(const char *spec, const char *node, int *flags, - char **extra_opts, char **mount_opts, int running_bg) -{ - static char *prev_bg_host; - char hostdir[1024]; - CLIENT *mclient; - char *hostname; - char *pathname; - char *old_opts; - char *mounthost=NULL; - char new_opts[1024]; - struct timeval total_timeout; - enum clnt_stat clnt_stat; - static struct nfs_mount_data data; - char *opt, *opteq; - int val; - struct hostent *hp; - struct sockaddr_in server_addr; - struct sockaddr_in mount_server_addr; - struct pmap* pm_mnt; - int msock, fsock; - struct timeval retry_timeout; - union { - struct fhstatus nfsv2; - struct mountres3 nfsv3; - } status; - struct stat statbuf; - char *s; - int port; - int mountport; - int proto; - int bg; - int soft; - int intr; - int posix; - int nocto; - int noac; - int nolock; - int retry; - int tcp; - int mountprog; - int mountvers; - int nfsprog; - int nfsvers; - int retval; - time_t t; - time_t prevt; - time_t timeout; - - find_kernel_nfs_mount_version(); - - retval = EX_FAIL; - msock = fsock = -1; - mclient = NULL; - if (strlen(spec) >= sizeof(hostdir)) { - error_msg("excessively long host:dir argument"); - goto fail; - } - strcpy(hostdir, spec); - if ((s = strchr(hostdir, ':'))) { - hostname = hostdir; - pathname = s + 1; - *s = '\0'; - /* Ignore all but first hostname in replicated mounts - until they can be fully supported. (mack@sgi.com) */ - if ((s = strchr(hostdir, ','))) { - *s = '\0'; - error_msg("warning: multiple hostnames not supported"); - } - } else { - error_msg("directory to mount not in host:dir format"); - goto fail; - } - - server_addr.sin_family = AF_INET; -#ifdef HAVE_inet_aton - if (!inet_aton(hostname, &server_addr.sin_addr)) -#endif - { - if ((hp = gethostbyname(hostname)) == NULL) { - herror_msg("%s", hostname); - goto fail; - } else { - if (hp->h_length > sizeof(struct in_addr)) { - error_msg("got bad hp->h_length"); - hp->h_length = sizeof(struct in_addr); - } - memcpy(&server_addr.sin_addr, - hp->h_addr, hp->h_length); - } - } - - memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr)); - - /* add IP address to mtab options for use when unmounting */ - - s = inet_ntoa(server_addr.sin_addr); - old_opts = *extra_opts; - if (!old_opts) - old_opts = ""; - if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) { - error_msg("excessively long option argument"); - goto fail; - } - sprintf(new_opts, "%s%saddr=%s", - old_opts, *old_opts ? "," : "", s); - *extra_opts = xstrdup(new_opts); - - /* Set default options. - * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to - * let the kernel decide. - * timeo is filled in after we know whether it'll be TCP or UDP. */ - memset(&data, 0, sizeof(data)); - data.retrans = 3; - data.acregmin = 3; - data.acregmax = 60; - data.acdirmin = 30; - data.acdirmax = 60; -#if NFS_MOUNT_VERSION >= 2 - data.namlen = NAME_MAX; -#endif - - bg = 0; - soft = 0; - intr = 0; - posix = 0; - nocto = 0; - nolock = 0; - noac = 0; - retry = 10000; /* 10000 minutes ~ 1 week */ - tcp = 0; - - mountprog = MOUNTPROG; - mountvers = 0; - port = 0; - mountport = 0; - nfsprog = NFS_PROGRAM; - nfsvers = 0; - - /* parse options */ - - for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) { - if ((opteq = strchr(opt, '='))) { - val = atoi(opteq + 1); - *opteq = '\0'; - if (!strcmp(opt, "rsize")) - data.rsize = val; - else if (!strcmp(opt, "wsize")) - data.wsize = val; - else if (!strcmp(opt, "timeo")) - data.timeo = val; - else if (!strcmp(opt, "retrans")) - data.retrans = val; - else if (!strcmp(opt, "acregmin")) - data.acregmin = val; - else if (!strcmp(opt, "acregmax")) - data.acregmax = val; - else if (!strcmp(opt, "acdirmin")) - data.acdirmin = val; - else if (!strcmp(opt, "acdirmax")) - data.acdirmax = val; - else if (!strcmp(opt, "actimeo")) { - data.acregmin = val; - data.acregmax = val; - data.acdirmin = val; - data.acdirmax = val; - } - else if (!strcmp(opt, "retry")) - retry = val; - else if (!strcmp(opt, "port")) - port = val; - else if (!strcmp(opt, "mountport")) - mountport = val; - else if (!strcmp(opt, "mounthost")) - mounthost=xstrndup(opteq+1, - strcspn(opteq+1," \t\n\r,")); - else if (!strcmp(opt, "mountprog")) - mountprog = val; - else if (!strcmp(opt, "mountvers")) - mountvers = val; - else if (!strcmp(opt, "nfsprog")) - nfsprog = val; - else if (!strcmp(opt, "nfsvers") || - !strcmp(opt, "vers")) - nfsvers = val; - else if (!strcmp(opt, "proto")) { - if (!strncmp(opteq+1, "tcp", 3)) - tcp = 1; - else if (!strncmp(opteq+1, "udp", 3)) - tcp = 0; - else - printf(_("Warning: Unrecognized proto= option.\n")); - } else if (!strcmp(opt, "namlen")) { -#if NFS_MOUNT_VERSION >= 2 - if (nfs_mount_version >= 2) - data.namlen = val; - else -#endif - printf(_("Warning: Option namlen is not supported.\n")); - } else if (!strcmp(opt, "addr")) - /* ignore */; - else { - printf(_("unknown nfs mount parameter: " - "%s=%d\n"), opt, val); - goto fail; - } - } - else { - val = 1; - if (!strncmp(opt, "no", 2)) { - val = 0; - opt += 2; - } - if (!strcmp(opt, "bg")) - bg = val; - else if (!strcmp(opt, "fg")) - bg = !val; - else if (!strcmp(opt, "soft")) - soft = val; - else if (!strcmp(opt, "hard")) - soft = !val; - else if (!strcmp(opt, "intr")) - intr = val; - else if (!strcmp(opt, "posix")) - posix = val; - else if (!strcmp(opt, "cto")) - nocto = !val; - else if (!strcmp(opt, "ac")) - noac = !val; - else if (!strcmp(opt, "tcp")) - tcp = val; - else if (!strcmp(opt, "udp")) - tcp = !val; - else if (!strcmp(opt, "lock")) { - if (nfs_mount_version >= 3) - nolock = !val; - else - printf(_("Warning: option nolock is not supported.\n")); - } else { - printf(_("unknown nfs mount option: " - "%s%s\n"), val ? "" : "no", opt); - goto fail; - } - } - } - proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP; - - data.flags = (soft ? NFS_MOUNT_SOFT : 0) - | (intr ? NFS_MOUNT_INTR : 0) - | (posix ? NFS_MOUNT_POSIX : 0) - | (nocto ? NFS_MOUNT_NOCTO : 0) - | (noac ? NFS_MOUNT_NOAC : 0); -#if NFS_MOUNT_VERSION >= 2 - if (nfs_mount_version >= 2) - data.flags |= (tcp ? NFS_MOUNT_TCP : 0); -#endif -#if NFS_MOUNT_VERSION >= 3 - if (nfs_mount_version >= 3) - data.flags |= (nolock ? NFS_MOUNT_NONLM : 0); -#endif - if (nfsvers > MAX_NFSPROT) { - error_msg("NFSv%d not supported!", nfsvers); - return 0; - } - if (mountvers > MAX_NFSPROT) { - error_msg("NFSv%d not supported!", nfsvers); - return 0; - } - if (nfsvers && !mountvers) - mountvers = (nfsvers < 3) ? 1 : nfsvers; - if (nfsvers && nfsvers < mountvers) { - mountvers = nfsvers; - } - - /* Adjust options if none specified */ - if (!data.timeo) - data.timeo = tcp ? 70 : 7; - -#ifdef NFS_MOUNT_DEBUG - printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", - data.rsize, data.wsize, data.timeo, data.retrans); - printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n", - data.acregmin, data.acregmax, data.acdirmin, data.acdirmax); - printf("port = %d, bg = %d, retry = %d, flags = %.8x\n", - port, bg, retry, data.flags); - printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n", - mountprog, mountvers, nfsprog, nfsvers); - printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n", - (data.flags & NFS_MOUNT_SOFT) != 0, - (data.flags & NFS_MOUNT_INTR) != 0, - (data.flags & NFS_MOUNT_POSIX) != 0, - (data.flags & NFS_MOUNT_NOCTO) != 0, - (data.flags & NFS_MOUNT_NOAC) != 0); -#if NFS_MOUNT_VERSION >= 2 - printf("tcp = %d\n", - (data.flags & NFS_MOUNT_TCP) != 0); -#endif -#endif - - data.version = nfs_mount_version; - *mount_opts = (char *) &data; - - if (*flags & MS_REMOUNT) - return 0; - - /* - * If the previous mount operation on the same host was - * backgrounded, and the "bg" for this mount is also set, - * give up immediately, to avoid the initial timeout. - */ - if (bg && !running_bg && - prev_bg_host && strcmp(hostname, prev_bg_host) == 0) { - if (retry > 0) - retval = EX_BG; - return retval; - } - - /* create mount deamon client */ - /* See if the nfs host = mount host. */ - if (mounthost) { - if (mounthost[0] >= '0' && mounthost[0] <= '9') { - mount_server_addr.sin_family = AF_INET; - mount_server_addr.sin_addr.s_addr = inet_addr(hostname); - } else { - if ((hp = gethostbyname(mounthost)) == NULL) { - herror_msg("%s", mounthost); - goto fail; - } else { - if (hp->h_length > sizeof(struct in_addr)) { - error_msg("got bad hp->h_length?"); - hp->h_length = sizeof(struct in_addr); - } - mount_server_addr.sin_family = AF_INET; - memcpy(&mount_server_addr.sin_addr, - hp->h_addr, hp->h_length); - } - } - } - - /* - * The following loop implements the mount retries. On the first - * call, "running_bg" is 0. When the mount times out, and the - * "bg" option is set, the exit status EX_BG will be returned. - * For a backgrounded mount, there will be a second call by the - * child process with "running_bg" set to 1. - * - * The case where the mount point is not present and the "bg" - * option is set, is treated as a timeout. This is done to - * support nested mounts. - * - * The "retry" count specified by the user is the number of - * minutes to retry before giving up. - * - * Only the first error message will be displayed. - */ - retry_timeout.tv_sec = 3; - retry_timeout.tv_usec = 0; - total_timeout.tv_sec = 20; - total_timeout.tv_usec = 0; - timeout = time(NULL) + 60 * retry; - prevt = 0; - t = 30; - val = 1; - for (;;) { - if (bg && stat(node, &statbuf) == -1) { - if (running_bg) { - sleep(val); /* 1, 2, 4, 8, 16, 30, ... */ - val *= 2; - if (val > 30) - val = 30; - } - } else { - /* be careful not to use too many CPU cycles */ - if (t - prevt < 30) - sleep(30); - - pm_mnt = get_mountport(&mount_server_addr, - mountprog, - mountvers, - proto, - mountport); - - /* contact the mount daemon via TCP */ - mount_server_addr.sin_port = htons(pm_mnt->pm_port); - msock = RPC_ANYSOCK; - - switch (pm_mnt->pm_prot) { - case IPPROTO_UDP: - mclient = clntudp_create(&mount_server_addr, - pm_mnt->pm_prog, - pm_mnt->pm_vers, - retry_timeout, - &msock); - if (mclient) - break; - mount_server_addr.sin_port = htons(pm_mnt->pm_port); - msock = RPC_ANYSOCK; - case IPPROTO_TCP: - mclient = clnttcp_create(&mount_server_addr, - pm_mnt->pm_prog, - pm_mnt->pm_vers, - &msock, 0, 0); - break; - default: - mclient = 0; - } - if (mclient) { - /* try to mount hostname:pathname */ - mclient->cl_auth = authunix_create_default(); - - /* make pointers in xdr_mountres3 NULL so - * that xdr_array allocates memory for us - */ - memset(&status, 0, sizeof(status)); - - if (pm_mnt->pm_vers == 3) - clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT, - (xdrproc_t) xdr_dirpath, - (caddr_t) &pathname, - (xdrproc_t) xdr_mountres3, - (caddr_t) &status, - total_timeout); - else - clnt_stat = clnt_call(mclient, MOUNTPROC_MNT, - (xdrproc_t) xdr_dirpath, - (caddr_t) &pathname, - (xdrproc_t) xdr_fhstatus, - (caddr_t) &status, - total_timeout); - - if (clnt_stat == RPC_SUCCESS) - break; /* we're done */ - if (errno != ECONNREFUSED) { - clnt_perror(mclient, "mount"); - goto fail; /* don't retry */ - } - if (!running_bg && prevt == 0) - clnt_perror(mclient, "mount"); - auth_destroy(mclient->cl_auth); - clnt_destroy(mclient); - mclient = 0; - close(msock); - } else { - if (!running_bg && prevt == 0) - clnt_pcreateerror("mount"); - } - prevt = t; - } - if (!bg) - goto fail; - if (!running_bg) { - prev_bg_host = xstrdup(hostname); - if (retry > 0) - retval = EX_BG; - goto fail; - } - t = time(NULL); - if (t >= timeout) - goto fail; - } - nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers; - - if (nfsvers == 2) { - if (status.nfsv2.fhs_status != 0) { - error_msg("%s:%s failed, reason given by server: %s", - hostname, pathname, - nfs_strerror(status.nfsv2.fhs_status)); - goto fail; - } - memcpy(data.root.data, - (char *) status.nfsv2.fhstatus_u.fhs_fhandle, - NFS_FHSIZE); -#if NFS_MOUNT_VERSION >= 4 - data.root.size = NFS_FHSIZE; - memcpy(data.old_root.data, - (char *) status.nfsv2.fhstatus_u.fhs_fhandle, - NFS_FHSIZE); -#endif - } else { -#if NFS_MOUNT_VERSION >= 4 - fhandle3 *my_fhandle; - if (status.nfsv3.fhs_status != 0) { - error_msg("%s:%s failed, reason given by server: %s", - hostname, pathname, - nfs_strerror(status.nfsv3.fhs_status)); - goto fail; - } - my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle; - memset(data.old_root.data, 0, NFS_FHSIZE); - memset(&data.root, 0, sizeof(data.root)); - data.root.size = my_fhandle->fhandle3_len; - memcpy(data.root.data, - (char *) my_fhandle->fhandle3_val, - my_fhandle->fhandle3_len); - - data.flags |= NFS_MOUNT_VER3; -#endif - } - - /* create nfs socket for kernel */ - - if (tcp) { - if (nfs_mount_version < 3) { - printf(_("NFS over TCP is not supported.\n")); - goto fail; - } - fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - } else - fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (fsock < 0) { - perror(_("nfs socket")); - goto fail; - } - if (bindresvport(fsock, 0) < 0) { - perror(_("nfs bindresvport")); - goto fail; - } - if (port == 0) { - server_addr.sin_port = PMAPPORT; - port = pmap_getport(&server_addr, nfsprog, nfsvers, - tcp ? IPPROTO_TCP : IPPROTO_UDP); - if (port == 0) - port = NFS_PORT; -#ifdef NFS_MOUNT_DEBUG - else - printf(_("used portmapper to find NFS port\n")); -#endif - } -#ifdef NFS_MOUNT_DEBUG - printf(_("using port %d for nfs deamon\n"), port); -#endif - server_addr.sin_port = htons(port); - /* - * connect() the socket for kernels 1.3.10 and below only, - * to avoid problems with multihomed hosts. - * --Swen - */ - if (get_kernel_revision() <= 66314 - && connect(fsock, (struct sockaddr *) &server_addr, - sizeof (server_addr)) < 0) { - perror(_("nfs connect")); - goto fail; - } - - /* prepare data structure for kernel */ - - data.fd = fsock; - memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr)); - strncpy(data.hostname, hostname, sizeof(data.hostname)); - - /* clean up */ - - auth_destroy(mclient->cl_auth); - clnt_destroy(mclient); - close(msock); - return 0; - - /* abort */ - -fail: - if (msock != -1) { - if (mclient) { - auth_destroy(mclient->cl_auth); - clnt_destroy(mclient); - } - close(msock); - } - if (fsock != -1) - close(fsock); - return retval; -} - -/* - * We need to translate between nfs status return values and - * the local errno values which may not be the same. - * - * Andreas Schwab : change errno: - * "after #include the symbol errno is reserved for any use, - * it cannot even be used as a struct tag or field name". - */ - -#ifndef EDQUOT -#define EDQUOT ENOSPC -#endif - -static struct { - enum nfs_stat stat; - int errnum; -} nfs_errtbl[] = { - { NFS_OK, 0 }, - { NFSERR_PERM, EPERM }, - { NFSERR_NOENT, ENOENT }, - { NFSERR_IO, EIO }, - { NFSERR_NXIO, ENXIO }, - { NFSERR_ACCES, EACCES }, - { NFSERR_EXIST, EEXIST }, - { NFSERR_NODEV, ENODEV }, - { NFSERR_NOTDIR, ENOTDIR }, - { NFSERR_ISDIR, EISDIR }, -#ifdef NFSERR_INVAL - { NFSERR_INVAL, EINVAL }, /* that Sun forgot */ -#endif - { NFSERR_FBIG, EFBIG }, - { NFSERR_NOSPC, ENOSPC }, - { NFSERR_ROFS, EROFS }, - { NFSERR_NAMETOOLONG, ENAMETOOLONG }, - { NFSERR_NOTEMPTY, ENOTEMPTY }, - { NFSERR_DQUOT, EDQUOT }, - { NFSERR_STALE, ESTALE }, -#ifdef EWFLUSH - { NFSERR_WFLUSH, EWFLUSH }, -#endif - /* Throw in some NFSv3 values for even more fun (HP returns these) */ - { 71, EREMOTE }, - - { -1, EIO } -}; - -static char *nfs_strerror(int status) -{ - int i; - static char buf[256]; - - for (i = 0; nfs_errtbl[i].stat != -1; i++) { - if (nfs_errtbl[i].stat == status) - return strerror(nfs_errtbl[i].errnum); - } - sprintf(buf, _("unknown nfs status return value: %d"), status); - return buf; -} - -static bool_t -xdr_fhandle (XDR *xdrs, fhandle objp) -{ - //register int32_t *buf; - - if (!xdr_opaque (xdrs, objp, FHSIZE)) - return FALSE; - return TRUE; -} - -bool_t -xdr_fhstatus (XDR *xdrs, fhstatus *objp) -{ - //register int32_t *buf; - - if (!xdr_u_int (xdrs, &objp->fhs_status)) - return FALSE; - switch (objp->fhs_status) { - case 0: - if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle)) - return FALSE; - break; - default: - break; - } - return TRUE; -} - -bool_t -xdr_dirpath (XDR *xdrs, dirpath *objp) -{ - //register int32_t *buf; - - if (!xdr_string (xdrs, objp, MNTPATHLEN)) - return FALSE; - return TRUE; -} - -bool_t -xdr_fhandle3 (XDR *xdrs, fhandle3 *objp) -{ - //register int32_t *buf; - - if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp) -{ - //register int32_t *buf; - - if (!xdr_fhandle3 (xdrs, &objp->fhandle)) - return FALSE; - if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->auth_flavours.auth_flavours_len, ~0, - sizeof (int), (xdrproc_t) xdr_int)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mountstat3 (XDR *xdrs, mountstat3 *objp) -{ - //register int32_t *buf; - - if (!xdr_enum (xdrs, (enum_t *) objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mountres3 (XDR *xdrs, mountres3 *objp) -{ - //register int32_t *buf; - - if (!xdr_mountstat3 (xdrs, &objp->fhs_status)) - return FALSE; - switch (objp->fhs_status) { - case MNT_OK: - if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo)) - return FALSE; - break; - default: - break; - } - return TRUE; -} - diff --git a/busybox/nfsmount.h b/busybox/nfsmount.h deleted file mode 100644 index b3d5a51e6..000000000 --- a/busybox/nfsmount.h +++ /dev/null @@ -1,242 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * This file was originally generated using rpcgen. - * But now we edit it by hand as needed to make it - * shut up... - */ - -#ifndef _NFSMOUNT_H_RPCGEN -#define _NFSMOUNT_H_RPCGEN - -#include - - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user or with the express written consent of - * Sun Microsystems, Inc. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ -/* - * Copyright (c) 1985, 1990 by Sun Microsystems, Inc. - */ - -/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */ -#ifndef _rpcsvc_mount_h -#define _rpcsvc_mount_h -#include -#define MOUNTPORT 635 -#define MNTPATHLEN 1024 -#define MNTNAMLEN 255 -#define FHSIZE 32 -#define FHSIZE3 64 - -typedef char fhandle[FHSIZE]; - -typedef struct { - u_int fhandle3_len; - char *fhandle3_val; -} fhandle3; - -enum mountstat3 { - MNT_OK = 0, - MNT3ERR_PERM = 1, - MNT3ERR_NOENT = 2, - MNT3ERR_IO = 5, - MNT3ERR_ACCES = 13, - MNT3ERR_NOTDIR = 20, - MNT3ERR_INVAL = 22, - MNT3ERR_NAMETOOLONG = 63, - MNT3ERR_NOTSUPP = 10004, - MNT3ERR_SERVERFAULT = 10006, -}; -typedef enum mountstat3 mountstat3; - -struct fhstatus { - u_int fhs_status; - union { - fhandle fhs_fhandle; - } fhstatus_u; -}; -typedef struct fhstatus fhstatus; - -struct mountres3_ok { - fhandle3 fhandle; - struct { - u_int auth_flavours_len; - int *auth_flavours_val; - } auth_flavours; -}; -typedef struct mountres3_ok mountres3_ok; - -struct mountres3 { - mountstat3 fhs_status; - union { - mountres3_ok mountinfo; - } mountres3_u; -}; -typedef struct mountres3 mountres3; - -typedef char *dirpath; - -typedef char *name; - -typedef struct mountbody *mountlist; - -struct mountbody { - name ml_hostname; - dirpath ml_directory; - mountlist ml_next; -}; -typedef struct mountbody mountbody; - -typedef struct groupnode *groups; - -struct groupnode { - name gr_name; - groups gr_next; -}; -typedef struct groupnode groupnode; - -typedef struct exportnode *exports; - -struct exportnode { - dirpath ex_dir; - groups ex_groups; - exports ex_next; -}; -typedef struct exportnode exportnode; - -struct ppathcnf { - int pc_link_max; - short pc_max_canon; - short pc_max_input; - short pc_name_max; - short pc_path_max; - short pc_pipe_buf; - u_char pc_vdisable; - char pc_xxx; - short pc_mask[2]; -}; -typedef struct ppathcnf ppathcnf; -#endif /*!_rpcsvc_mount_h*/ - -#define MOUNTPROG 100005 -#define MOUNTVERS 1 - -#define MOUNTPROC_NULL 0 -extern void * mountproc_null_1(void *, CLIENT *); -extern void * mountproc_null_1_svc(void *, struct svc_req *); -#define MOUNTPROC_MNT 1 -extern fhstatus * mountproc_mnt_1(dirpath *, CLIENT *); -extern fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *); -#define MOUNTPROC_DUMP 2 -extern mountlist * mountproc_dump_1(void *, CLIENT *); -extern mountlist * mountproc_dump_1_svc(void *, struct svc_req *); -#define MOUNTPROC_UMNT 3 -extern void * mountproc_umnt_1(dirpath *, CLIENT *); -extern void * mountproc_umnt_1_svc(dirpath *, struct svc_req *); -#define MOUNTPROC_UMNTALL 4 -extern void * mountproc_umntall_1(void *, CLIENT *); -extern void * mountproc_umntall_1_svc(void *, struct svc_req *); -#define MOUNTPROC_EXPORT 5 -extern exports * mountproc_export_1(void *, CLIENT *); -extern exports * mountproc_export_1_svc(void *, struct svc_req *); -#define MOUNTPROC_EXPORTALL 6 -extern exports * mountproc_exportall_1(void *, CLIENT *); -extern exports * mountproc_exportall_1_svc(void *, struct svc_req *); -extern int mountprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); - -#define MOUNTVERS_POSIX 2 - -extern void * mountproc_null_2(void *, CLIENT *); -extern void * mountproc_null_2_svc(void *, struct svc_req *); -extern fhstatus * mountproc_mnt_2(dirpath *, CLIENT *); -extern fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *); -extern mountlist * mountproc_dump_2(void *, CLIENT *); -extern mountlist * mountproc_dump_2_svc(void *, struct svc_req *); -extern void * mountproc_umnt_2(dirpath *, CLIENT *); -extern void * mountproc_umnt_2_svc(dirpath *, struct svc_req *); -extern void * mountproc_umntall_2(void *, CLIENT *); -extern void * mountproc_umntall_2_svc(void *, struct svc_req *); -extern exports * mountproc_export_2(void *, CLIENT *); -extern exports * mountproc_export_2_svc(void *, struct svc_req *); -extern exports * mountproc_exportall_2(void *, CLIENT *); -extern exports * mountproc_exportall_2_svc(void *, struct svc_req *); -#define MOUNTPROC_PATHCONF 7 -extern ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *); -extern ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *); -extern int mountprog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t); - -#define MOUNT_V3 3 - -#define MOUNTPROC3_NULL 0 -extern void * mountproc3_null_3(void *, CLIENT *); -extern void * mountproc3_null_3_svc(void *, struct svc_req *); -#define MOUNTPROC3_MNT 1 -extern mountres3 * mountproc3_mnt_3(dirpath *, CLIENT *); -extern mountres3 * mountproc3_mnt_3_svc(dirpath *, struct svc_req *); -#define MOUNTPROC3_DUMP 2 -extern mountlist * mountproc3_dump_3(void *, CLIENT *); -extern mountlist * mountproc3_dump_3_svc(void *, struct svc_req *); -#define MOUNTPROC3_UMNT 3 -extern void * mountproc3_umnt_3(dirpath *, CLIENT *); -extern void * mountproc3_umnt_3_svc(dirpath *, struct svc_req *); -#define MOUNTPROC3_UMNTALL 4 -extern void * mountproc3_umntall_3(void *, CLIENT *); -extern void * mountproc3_umntall_3_svc(void *, struct svc_req *); -#define MOUNTPROC3_EXPORT 5 -extern exports * mountproc3_export_3(void *, CLIENT *); -extern exports * mountproc3_export_3_svc(void *, struct svc_req *); -extern int mountprog_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t); - -/* the xdr functions */ - -static bool_t xdr_fhandle (XDR *, fhandle); -extern bool_t xdr_fhandle3 (XDR *, fhandle3*); -extern bool_t xdr_mountstat3 (XDR *, mountstat3*); -extern bool_t xdr_fhstatus (XDR *, fhstatus*); -extern bool_t xdr_mountres3_ok (XDR *, mountres3_ok*); -extern bool_t xdr_mountres3 (XDR *, mountres3*); -extern bool_t xdr_dirpath (XDR *, dirpath*); -extern bool_t xdr_name (XDR *, name*); -extern bool_t xdr_mountlist (XDR *, mountlist*); -extern bool_t xdr_mountbody (XDR *, mountbody*); -extern bool_t xdr_groups (XDR *, groups*); -extern bool_t xdr_groupnode (XDR *, groupnode*); -extern bool_t xdr_exports (XDR *, exports*); -extern bool_t xdr_exportnode (XDR *, exportnode*); -extern bool_t xdr_ppathcnf (XDR *, ppathcnf*); - -#ifdef __cplusplus -} -#endif - -#endif /* !_NFSMOUNT_H_RPCGEN */ diff --git a/busybox/nslookup.c b/busybox/nslookup.c deleted file mode 100644 index 9b7cb645c..000000000 --- a/busybox/nslookup.c +++ /dev/null @@ -1,183 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini nslookup implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by John Beppu - * - * 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 -#include -#include "busybox.h" - -/* - | I'm only implementing non-interactive mode; - | I totally forgot nslookup even had an interactive mode. - | - | [ TODO ] - | + find out how to use non-default name servers - */ - -/* only works for IPv4 */ -static int addr_fprint(char *addr) -{ - u_int8_t split[4]; - u_int32_t ip; - u_int32_t *x = (u_int32_t *) addr; - - ip = ntohl(*x); - split[0] = (ip & 0xff000000) >> 24; - split[1] = (ip & 0x00ff0000) >> 16; - split[2] = (ip & 0x0000ff00) >> 8; - split[3] = (ip & 0x000000ff); - printf("%d.%d.%d.%d", split[0], split[1], split[2], split[3]); - return 0; -} - -/* takes the NULL-terminated array h_addr_list, and - * prints its contents appropriately - */ -static int addr_list_fprint(char **h_addr_list) -{ - int i, j; - char *addr_string = (h_addr_list[1]) - ? "Addresses: " : "Address: "; - - printf("%s ", addr_string); - for (i = 0, j = 0; h_addr_list[i]; i++, j++) { - addr_fprint(h_addr_list[i]); - - /* real nslookup does this */ - if (j == 4) { - if (h_addr_list[i + 1]) { - printf("\n "); - } - j = 0; - } else { - if (h_addr_list[i + 1]) { - printf(", "); - } - } - - } - printf("\n"); - return 0; -} - -/* print the results as nslookup would */ -static struct hostent *hostent_fprint(struct hostent *host) -{ - if (host) { - printf("Name: %s\n", host->h_name); - addr_list_fprint(host->h_addr_list); - } else { - printf("*** Unknown host\n"); - } - return host; -} - -/* changes a c-string matching the perl regex \d+\.\d+\.\d+\.\d+ - * into a u_int32_t - */ -static u_int32_t str_to_addr(const char *addr) -{ - u_int32_t split[4]; - u_int32_t ip; - - sscanf(addr, "%d.%d.%d.%d", - &split[0], &split[1], &split[2], &split[3]); - - /* assuming sscanf worked */ - ip = (split[0] << 24) | - (split[1] << 16) | (split[2] << 8) | (split[3]); - - return htonl(ip); -} - -/* gethostbyaddr wrapper */ -static struct hostent *gethostbyaddr_wrapper(const char *address) -{ - struct in_addr addr; - - addr.s_addr = str_to_addr(address); - return gethostbyaddr((char *) &addr, 4, AF_INET); /* IPv4 only for now */ -} - -#ifdef __UCLIBC__ -#warning FIXME after fixing uClibc to define struct _res -static inline void server_print(void) -{ - printf("Server: %s\n", "default"); - printf("Address: %s\n\n", "default"); -} -#else -/* lookup the default nameserver and display it */ -static inline void server_print(void) -{ - struct sockaddr_in def = _res.nsaddr_list[0]; - char *ip = inet_ntoa(def.sin_addr); - - hostent_fprint(gethostbyaddr_wrapper(ip)); - printf("\n"); -} -#endif - -/* naive function to check whether char *s is an ip address */ -static int is_ip_address(const char *s) -{ - while (*s) { - if ((isdigit(*s)) || (*s == '.')) { - s++; - continue; - } - return 0; - } - return 1; -} - -/* ________________________________________________________________________ */ -int nslookup_main(int argc, char **argv) -{ - struct hostent *host; - - if (argc < 2 || *argv[1]=='-') { - show_usage(); - } - - res_init(); - server_print(); - if (is_ip_address(argv[1])) { - host = gethostbyaddr_wrapper(argv[1]); - } else { - host = gethostbyname(argv[1]); - } - hostent_fprint(host); - return EXIT_SUCCESS; -} - -/* $Id: nslookup.c,v 1.24 2001/07/06 17:51:29 andersen Exp $ */ diff --git a/busybox/pidof.c b/busybox/pidof.c deleted file mode 100644 index 50dffd387..000000000 --- a/busybox/pidof.c +++ /dev/null @@ -1,79 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * pidof implementation for busybox - * - * Copyright (C) 2001 by Lineo, inc. - * Written 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 - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - - -extern int pidof_main(int argc, char **argv) -{ - int opt; - - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "ne:f:")) > 0) { - switch (opt) { -#if 0 - case 'g': - break; - case 'e': - break; -#endif - default: - show_usage(); - } - } - - /* if we didn't get a process name, then we need to choke and die here */ - if (argv[optind] == NULL) - show_usage(); - - /* Looks like everything is set to go. */ - while(optind < argc) { - pid_t* pidList; - - pidList = find_pid_by_name( argv[optind]); - if (!pidList || *pidList<=0) { - break; - } - - for(; pidList && *pidList!=0; pidList++) { - printf("%ld ", (long)*pidList); - } - /* Note that we don't bother to free the memory - * allocated in find_pid_by_name(). It will be freed - * upon exit, so we can save a byte or two */ - optind++; - } - printf("\n"); - - return EXIT_SUCCESS; -} diff --git a/busybox/ping.c b/busybox/ping.c deleted file mode 100644 index 5ca5dd9e0..000000000 --- a/busybox/ping.c +++ /dev/null @@ -1,555 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * $Id: ping.c,v 1.46 2001/07/17 01:12:36 andersen Exp $ - * Mini ping implementation for busybox - * - * Copyright (C) 1999 by Randolph Chung - * - * 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 - * - * This version of ping is adapted from the ping in netkit-base 0.10, - * which is: - * - * Copyright (c) 1989 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Mike Muuss. - * - * Original copyright notice is retained at the end of this file. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - - -/* It turns out that libc5 doesn't have proper icmp support - * built into it header files, so we have to supplement it */ -#if __GNU_LIBRARY__ < 5 -static const int ICMP_MINLEN = 8; /* abs minimum */ - -struct icmp_ra_addr -{ - u_int32_t ira_addr; - u_int32_t ira_preference; -}; - - -struct icmp -{ - u_int8_t icmp_type; /* type of message, see below */ - u_int8_t icmp_code; /* type sub code */ - u_int16_t icmp_cksum; /* ones complement checksum of struct */ - union - { - u_char ih_pptr; /* ICMP_PARAMPROB */ - struct in_addr ih_gwaddr; /* gateway address */ - struct ih_idseq /* echo datagram */ - { - u_int16_t icd_id; - u_int16_t icd_seq; - } ih_idseq; - u_int32_t ih_void; - - /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ - struct ih_pmtu - { - u_int16_t ipm_void; - u_int16_t ipm_nextmtu; - } ih_pmtu; - - struct ih_rtradv - { - u_int8_t irt_num_addrs; - u_int8_t irt_wpa; - u_int16_t irt_lifetime; - } ih_rtradv; - } icmp_hun; -#define icmp_pptr icmp_hun.ih_pptr -#define icmp_gwaddr icmp_hun.ih_gwaddr -#define icmp_id icmp_hun.ih_idseq.icd_id -#define icmp_seq icmp_hun.ih_idseq.icd_seq -#define icmp_void icmp_hun.ih_void -#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void -#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu -#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs -#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa -#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime - union - { - struct - { - u_int32_t its_otime; - u_int32_t its_rtime; - u_int32_t its_ttime; - } id_ts; - struct - { - struct ip idi_ip; - /* options and then 64 bits of data */ - } id_ip; - struct icmp_ra_addr id_radv; - u_int32_t id_mask; - u_int8_t id_data[1]; - } icmp_dun; -#define icmp_otime icmp_dun.id_ts.its_otime -#define icmp_rtime icmp_dun.id_ts.its_rtime -#define icmp_ttime icmp_dun.id_ts.its_ttime -#define icmp_ip icmp_dun.id_ip.idi_ip -#define icmp_radv icmp_dun.id_radv -#define icmp_mask icmp_dun.id_mask -#define icmp_data icmp_dun.id_data -}; -#endif - -static const int DEFDATALEN = 56; -static const int MAXIPLEN = 60; -static const int MAXICMPLEN = 76; -static const int MAXPACKET = 65468; -#define MAX_DUP_CHK (8 * 128) -static const int MAXWAIT = 10; -static const int PINGINTERVAL = 1; /* second */ - -#define O_QUIET (1 << 0) - -#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ -#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ -#define SET(bit) (A(bit) |= B(bit)) -#define CLR(bit) (A(bit) &= (~B(bit))) -#define TST(bit) (A(bit) & B(bit)) - -static void ping(const char *host); - -/* common routines */ -static int in_cksum(unsigned short *buf, int sz) -{ - int nleft = sz; - int sum = 0; - unsigned short *w = buf; - unsigned short ans = 0; - - while (nleft > 1) { - sum += *w++; - nleft -= 2; - } - - if (nleft == 1) { - *(unsigned char *) (&ans) = *(unsigned char *) w; - sum += ans; - } - - sum = (sum >> 16) + (sum & 0xFFFF); - sum += (sum >> 16); - ans = ~sum; - return (ans); -} - -/* simple version */ -#ifndef BB_FEATURE_FANCY_PING -static char *hostname = NULL; - -static void noresp(int ign) -{ - printf("No response from %s\n", hostname); - exit(0); -} - -static void ping(const char *host) -{ - struct hostent *h; - struct sockaddr_in pingaddr; - struct icmp *pkt; - int pingsock, c; - char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; - - pingsock = create_icmp_socket(); - - memset(&pingaddr, 0, sizeof(struct sockaddr_in)); - - pingaddr.sin_family = AF_INET; - h = xgethostbyname(host); - memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr)); - hostname = h->h_name; - - pkt = (struct icmp *) packet; - memset(pkt, 0, sizeof(packet)); - pkt->icmp_type = ICMP_ECHO; - pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); - - c = sendto(pingsock, packet, sizeof(packet), 0, - (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in)); - - if (c < 0 || c != sizeof(packet)) - perror_msg_and_die("sendto"); - - signal(SIGALRM, noresp); - alarm(5); /* give the host 5000ms to respond */ - /* listen for replies */ - while (1) { - struct sockaddr_in from; - size_t fromlen = sizeof(from); - - if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, - (struct sockaddr *) &from, &fromlen)) < 0) { - if (errno == EINTR) - continue; - perror_msg("recvfrom"); - continue; - } - if (c >= 76) { /* ip + icmp */ - struct iphdr *iphdr = (struct iphdr *) packet; - - pkt = (struct icmp *) (packet + (iphdr->ihl << 2)); /* skip ip hdr */ - if (pkt->icmp_type == ICMP_ECHOREPLY) - break; - } - } - printf("%s is alive!\n", hostname); - return; -} - -extern int ping_main(int argc, char **argv) -{ - argc--; - argv++; - if (argc < 1) - show_usage(); - ping(*argv); - return EXIT_SUCCESS; -} - -#else /* ! BB_FEATURE_FANCY_PING */ -/* full(er) version */ -static char *hostname = NULL; -static struct sockaddr_in pingaddr; -static int pingsock = -1; -static int datalen; /* intentionally uninitialized to work around gcc bug */ - -static long ntransmitted = 0, nreceived = 0, nrepeats = 0, pingcount = 0; -static int myid = 0, options = 0; -static unsigned long tmin = ULONG_MAX, tmax = 0, tsum = 0; -static char rcvd_tbl[MAX_DUP_CHK / 8]; - -static void sendping(int); -static void pingstats(int); -static void unpack(char *, int, struct sockaddr_in *); - -/**************************************************************************/ - -static void pingstats(int junk) -{ - int status; - - signal(SIGINT, SIG_IGN); - - printf("\n--- %s ping statistics ---\n", hostname); - printf("%ld packets transmitted, ", ntransmitted); - printf("%ld packets received, ", nreceived); - if (nrepeats) - printf("%ld duplicates, ", nrepeats); - if (ntransmitted) - printf("%ld%% packet loss\n", - (ntransmitted - nreceived) * 100 / ntransmitted); - if (nreceived) - printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n", - tmin / 10, tmin % 10, - (tsum / (nreceived + nrepeats)) / 10, - (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10); - if (nreceived != 0) - status = EXIT_SUCCESS; - else - status = EXIT_FAILURE; - exit(status); -} - -static void sendping(int junk) -{ - struct icmp *pkt; - int i; - char packet[datalen + 8]; - - pkt = (struct icmp *) packet; - - pkt->icmp_type = ICMP_ECHO; - pkt->icmp_code = 0; - pkt->icmp_cksum = 0; - pkt->icmp_seq = ntransmitted++; - pkt->icmp_id = myid; - CLR(pkt->icmp_seq % MAX_DUP_CHK); - - gettimeofday((struct timeval *) &packet[8], NULL); - pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); - - i = sendto(pingsock, packet, sizeof(packet), 0, - (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in)); - - if (i < 0) - perror_msg_and_die("sendto"); - else if ((size_t)i != sizeof(packet)) - error_msg_and_die("ping wrote %d chars; %d expected", i, - (int)sizeof(packet)); - - signal(SIGALRM, sendping); - if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */ - alarm(PINGINTERVAL); - } else { /* done, wait for the last ping to come back */ - /* todo, don't necessarily need to wait so long... */ - signal(SIGALRM, pingstats); - alarm(MAXWAIT); - } -} - -static char *icmp_type_name (int id) -{ - switch (id) { - case ICMP_ECHOREPLY: return "Echo Reply"; - case ICMP_DEST_UNREACH: return "Destination Unreachable"; - case ICMP_SOURCE_QUENCH: return "Source Quench"; - case ICMP_REDIRECT: return "Redirect (change route)"; - case ICMP_ECHO: return "Echo Request"; - case ICMP_TIME_EXCEEDED: return "Time Exceeded"; - case ICMP_PARAMETERPROB: return "Parameter Problem"; - case ICMP_TIMESTAMP: return "Timestamp Request"; - case ICMP_TIMESTAMPREPLY: return "Timestamp Reply"; - case ICMP_INFO_REQUEST: return "Information Request"; - case ICMP_INFO_REPLY: return "Information Reply"; - case ICMP_ADDRESS: return "Address Mask Request"; - case ICMP_ADDRESSREPLY: return "Address Mask Reply"; - default: return "unknown ICMP type"; - } -} - -static void unpack(char *buf, int sz, struct sockaddr_in *from) -{ - struct icmp *icmppkt; - struct iphdr *iphdr; - struct timeval tv, *tp; - int hlen, dupflag; - unsigned long triptime; - - gettimeofday(&tv, NULL); - - /* check IP header */ - iphdr = (struct iphdr *) buf; - hlen = iphdr->ihl << 2; - /* discard if too short */ - if (sz < (datalen + ICMP_MINLEN)) - return; - - sz -= hlen; - icmppkt = (struct icmp *) (buf + hlen); - - if (icmppkt->icmp_id != myid) - return; /* not our ping */ - - if (icmppkt->icmp_type == ICMP_ECHOREPLY) { - ++nreceived; - tp = (struct timeval *) icmppkt->icmp_data; - - if ((tv.tv_usec -= tp->tv_usec) < 0) { - --tv.tv_sec; - tv.tv_usec += 1000000; - } - tv.tv_sec -= tp->tv_sec; - - triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100); - tsum += triptime; - if (triptime < tmin) - tmin = triptime; - if (triptime > tmax) - tmax = triptime; - - if (TST(icmppkt->icmp_seq % MAX_DUP_CHK)) { - ++nrepeats; - --nreceived; - dupflag = 1; - } else { - SET(icmppkt->icmp_seq % MAX_DUP_CHK); - dupflag = 0; - } - - if (options & O_QUIET) - return; - - printf("%d bytes from %s: icmp_seq=%u", sz, - inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr), - icmppkt->icmp_seq); - printf(" ttl=%d", iphdr->ttl); - printf(" time=%lu.%lu ms", triptime / 10, triptime % 10); - if (dupflag) - printf(" (DUP!)"); - printf("\n"); - } else - if (icmppkt->icmp_type != ICMP_ECHO) - error_msg("Warning: Got ICMP %d (%s)", - icmppkt->icmp_type, icmp_type_name (icmppkt->icmp_type)); -} - -static void ping(const char *host) -{ - struct hostent *h; - char buf[MAXHOSTNAMELEN]; - char packet[datalen + MAXIPLEN + MAXICMPLEN]; - int sockopt; - - pingsock = create_icmp_socket(); - - memset(&pingaddr, 0, sizeof(struct sockaddr_in)); - - pingaddr.sin_family = AF_INET; - h = xgethostbyname(host); - if (h->h_addrtype != AF_INET) - error_msg_and_die("unknown address type; only AF_INET is currently supported."); - - memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr)); - strncpy(buf, h->h_name, sizeof(buf) - 1); - hostname = buf; - - /* enable broadcast pings */ - sockopt = 1; - setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt, - sizeof(sockopt)); - - /* set recv buf for broadcast pings */ - sockopt = 48 * 1024; - setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt, - sizeof(sockopt)); - - printf("PING %s (%s): %d data bytes\n", - hostname, - inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr), - datalen); - - signal(SIGINT, pingstats); - - /* start the ping's going ... */ - sendping(0); - - /* listen for replies */ - while (1) { - struct sockaddr_in from; - socklen_t fromlen = (socklen_t) sizeof(from); - int c; - - if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, - (struct sockaddr *) &from, &fromlen)) < 0) { - if (errno == EINTR) - continue; - perror_msg("recvfrom"); - continue; - } - unpack(packet, c, &from); - if (pingcount > 0 && nreceived >= pingcount) - break; - } - pingstats(0); -} - -extern int ping_main(int argc, char **argv) -{ - char *thisarg; - - datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */ - - argc--; - argv++; - options = 0; - /* Parse any options */ - while (argc >= 1 && **argv == '-') { - thisarg = *argv; - thisarg++; - switch (*thisarg) { - case 'q': - options |= O_QUIET; - break; - case 'c': - if (--argc <= 0) - show_usage(); - argv++; - pingcount = atoi(*argv); - break; - case 's': - if (--argc <= 0) - show_usage(); - argv++; - datalen = atoi(*argv); - break; - default: - show_usage(); - } - argc--; - argv++; - } - if (argc < 1) - show_usage(); - - myid = getpid() & 0xFFFF; - ping(*argv); - return EXIT_SUCCESS; -} -#endif /* ! BB_FEATURE_FANCY_PING */ - -/* - * Copyright (c) 1989 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Mike Muuss. - * - * 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. - */ diff --git a/busybox/pivot_root.c b/busybox/pivot_root.c deleted file mode 100644 index ba26b9c58..000000000 --- a/busybox/pivot_root.c +++ /dev/null @@ -1,35 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * pivot_root.c - Change root file system. Based on util-linux 2.10s - * - * busyboxed by Evin Robertson - * pivot_root syscall stubbed by Erik Andersen, so it will compile - * regardless of the kernel being used. - */ -#include -#include -#include -#include "busybox.h" - -extern int pivot_root(const char * new_root,const char * put_old); - -int pivot_root_main(int argc, char **argv) -{ - if (argc != 3) - show_usage(); - - if (pivot_root(argv[1],argv[2]) < 0) - perror_msg_and_die("pivot_root"); - - return EXIT_SUCCESS; - -} - - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/poweroff.c b/busybox/poweroff.c deleted file mode 100644 index db20a4572..000000000 --- a/busybox/poweroff.c +++ /dev/null @@ -1,41 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini poweroff implementation for busybox - * - * - * 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 - * - */ - -#include "busybox.h" -#include - -extern int poweroff_main(int argc, char **argv) -{ -#ifdef BB_FEATURE_LINUXRC - /* don't assume init's pid == 1 */ - pid_t *pid = find_pid_by_name("init"); - if (!pid || *pid<=0) { - pid = find_pid_by_name("linuxrc"); - if (!pid || *pid<=0) - error_msg_and_die("no process killed"); - } - return(kill(*pid, SIGUSR2)); -#else - return(kill(1, SIGUSR2)); -#endif -} diff --git a/busybox/printf.c b/busybox/printf.c deleted file mode 100644 index d579a9b4e..000000000 --- a/busybox/printf.c +++ /dev/null @@ -1,455 +0,0 @@ -/* 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. - - 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. */ - -/* Usage: printf format [argument...] - - A front end to the printf function that lets it be used from the shell. - - Backslash escapes: - - \" = double quote - \\ = backslash - \a = alert (bell) - \b = backspace - \c = produce no further output - \f = form feed - \n = new line - \r = carriage return - \t = horizontal tab - \v = vertical tab - \0ooo = octal number (ooo is 0 to 3 digits) - \xhhh = hexadecimal number (hhh is 1 to 3 digits) - - Additional directive: - - %b = print an argument string, interpreting backslash escapes - - The `format' argument is re-used as many times as necessary - to convert all of the given arguments. - - David MacKenzie */ - - -// 19990508 Busy Boxed! Dave Cinege - -#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)); -static void verify __P((char *s, char *end)); - -/* The value to return to the calling program. */ -static int exit_status; - -int printf_main(int argc, char **argv) -{ - char *format; - int args_used; - - exit_status = 0; - if (argc <= 1 || **(argv + 1) == '-') { - show_usage(); - } - - format = argv[1]; - argc -= 2; - argv += 2; - - do { - args_used = print_formatted(format, argc, argv); - argc -= args_used; - argv += args_used; - } - while (args_used > 0 && argc > 0); - -/* - if (argc > 0) - fprintf(stderr, "excess args ignored"); -*/ - - return(exit_status); -} - -/* Print the text in FORMAT, using ARGV (with ARGC elements) for - arguments to any `%' directives. - Return the number of elements of ARGV used. */ - -static int print_formatted(char *format, int argc, 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) { - switch (*f) { - case '%': - direc_start = f++; - direc_length = 1; - field_width = precision = -1; - if (*f == '%') { - putchar('%'); - break; - } - if (*f == 'b') { - if (argc > 0) { - print_esc_string(*argv); - ++argv; - --argc; - } - break; - } - if (strchr("-+ #", *f)) { - ++f; - ++direc_length; - } - if (*f == '*') { - ++f; - ++direc_length; - if (argc > 0) { - field_width = xstrtoul(*argv); - ++argv; - --argc; - } else - field_width = 0; - } 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)) { - ++f; - ++direc_length; - } - } - if (*f == 'l' || *f == 'L' || *f == 'h') { - ++f; - ++direc_length; - } - /* - 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); - break; - - default: - putchar(*f); - } - } - - return save_argc - argc; -} - -/* 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) -{ - 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); - } - break; - } - - free(p); -} - -static unsigned long xstrtoul(char *s) -{ - char *end; - unsigned long val; - - errno = 0; - val = strtoul(s, &end, 0); - verify(s, end); - return val; -} - -static long xstrtol(char *s) -{ - char *end; - long val; - - errno = 0; - val = strtol(s, &end, 0); - verify(s, end); - return val; -} - -static double xstrtod(char *s) -{ - char *end; - double val; - - errno = 0; - val = strtod(s, &end); - verify(s, end); - return val; -} - -static void verify(char *s, char *end) -{ - if (errno) { - fprintf(stderr, "%s", s); - exit_status = 1; - } else if (*end) { - /* - if (s == end) - fprintf(stderr, "%s: expected numeric", s); - else - fprintf(stderr, "%s: not completely converted", s); - */ - exit_status = 1; - } -} diff --git a/busybox/pristine_setup.sh b/busybox/pristine_setup.sh deleted file mode 100755 index 9e638f96e..000000000 --- a/busybox/pristine_setup.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh -# -# To compile BusyBox without touching the original sources -# (as might be interesting for multi-target builds), create -# an empty directory, cd into it, and run this program by -# giving its explicit path (kind of like how you would run -# configure, if BusyBox had one). Then you should be ready -# to "make". Files in the build tree, in particular Config.h, -# will override those in the pristine source tree. -# -# If you use a ? in your path name, you lose, see sed command below. - -export LC_ALL=POSIX -export LC_CTYPE=POSIX - -DIR=${0%%/pristine_setup.sh} -if [ ! -d $DIR ]; then - echo "unexpected problem: $DIR is not a directory. Aborting pristine setup" - exit -fi - -echo " " - -if [ -e ./Config.h ]; then - echo "./Config.h already exists: not overwriting" - exit -fi - -if [ -e ./Makefile ]; then - echo "./Makefile already exists: not overwriting" -fi - -sed -e "s?BB_SRC_DIR =.*?BB_SRC_DIR = $DIR?" <$DIR/Makefile >Makefile || exit -cp $DIR/Config.h Config.h || exit -#mkdir -p pwd_grp - -if [ ! -r $DIR/sh.c ]; then - echo "Warning: no shell selected. You must make the symlink (sh.c to either" - echo "lash.c or hush.c) in $DIR, not here." -fi - -echo " " -echo "You may now type 'make' to build busybox in this directory" -echo "($PWD) using the pristine sources in $DIR" -echo " " - diff --git a/busybox/procps/free.c b/busybox/procps/free.c deleted file mode 100644 index 2e34a972c..000000000 --- a/busybox/procps/free.c +++ /dev/null @@ -1,69 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini free implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -/* getopt not needed */ - -#include -#include -#include -#include "busybox.h" - -extern int free_main(int argc, char **argv) -{ - struct sysinfo info; - sysinfo(&info); - - /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */ - if (info.mem_unit==0) { - info.mem_unit=1; - } - info.mem_unit*=1024; - - /* TODO: Make all this stuff not overflow when mem >= 4 Gib */ - info.totalram/=info.mem_unit; - info.freeram/=info.mem_unit; - info.totalswap/=info.mem_unit; - info.freeswap/=info.mem_unit; - info.sharedram/=info.mem_unit; - info.bufferram/=info.mem_unit; - - if (argc > 1 && **(argv + 1) == '-') - show_usage(); - - printf("%6s%13s%13s%13s%13s%13s\n", "", "total", "used", "free", - "shared", "buffers"); - - printf("%6s%13ld%13ld%13ld%13ld%13ld\n", "Mem:", info.totalram, - info.totalram-info.freeram, info.freeram, - info.sharedram, info.bufferram); - - printf("%6s%13ld%13ld%13ld\n", "Swap:", info.totalswap, - info.totalswap-info.freeswap, info.freeswap); - - printf("%6s%13ld%13ld%13ld\n", "Total:", info.totalram+info.totalswap, - (info.totalram-info.freeram)+(info.totalswap-info.freeswap), - info.freeram+info.freeswap); - return EXIT_SUCCESS; -} - - diff --git a/busybox/procps/kill.c b/busybox/procps/kill.c deleted file mode 100644 index 3884ebdf4..000000000 --- a/busybox/procps/kill.c +++ /dev/null @@ -1,142 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini kill/killall implementation for busybox - * - * 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 - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -static const int KILL = 0; -static const int KILLALL = 1; - - -extern int kill_main(int argc, char **argv) -{ - int whichApp, sig = SIGTERM; - const char *name; - -#ifdef BB_KILLALL - /* Figure out what we are trying to do here */ - whichApp = (strcmp(applet_name, "killall") == 0)? KILLALL : KILL; -#else - whichApp = KILL; -#endif - - argc--; - argv++; - /* Parse any options */ - if (argc < 1) - show_usage(); - - while (argc > 0 && **argv == '-') { - while (*++(*argv)) { - switch (**argv) { - case 'l': - if(argc>1) { - for(argv++; *argv; argv++) { - name = u_signal_names(*argv, &sig, -1); - if(name!=NULL) - printf("%s\n", name); - } - } else { - int col = 0; - for(sig=1; sig < NSIG; sig++) { - name = u_signal_names(0, &sig, 1); - if(name==NULL) /* unnamed */ - continue; - col += printf("%2d) %-16s", sig, name); - if (col > 60) { - printf("\n"); - col = 0; - } - } - printf("\n"); - } - return EXIT_SUCCESS; - case '-': - show_usage(); - default: - name = u_signal_names(*argv, &sig, 0); - if(name==NULL) - error_msg_and_die( "bad signal name: %s", *argv); - argc--; - argv++; - goto do_it_now; - } - argc--; - argv++; - } - } - - do_it_now: - - if (whichApp == KILL) { - /* Looks like they want to do a kill. Do that */ - while (--argc >= 0) { - int pid; - - if (!isdigit(**argv)) - perror_msg_and_die( "Bad PID"); - pid = strtol(*argv, NULL, 0); - if (kill(pid, sig) != 0) - perror_msg_and_die( "Could not kill pid '%d'", pid); - argv++; - } - } -#ifdef BB_KILLALL - else { - int all_found = TRUE; - pid_t myPid=getpid(); - /* Looks like they want to do a killall. Do that */ - while (--argc >= 0) { - pid_t* pidList; - - pidList = find_pid_by_name( *argv); - if (!pidList || *pidList<=0) { - all_found = FALSE; - error_msg_and_die( "%s: no process killed", *argv); - } - - for(; pidList && *pidList!=0; pidList++) { - if (*pidList==myPid) - continue; - if (kill(*pidList, sig) != 0) - perror_msg_and_die( "Could not kill pid '%d'", *pidList); - } - /* Note that we don't bother to free the memory - * allocated in find_pid_by_name(). It will be freed - * upon exit, so we can save a byte or two */ - argv++; - } - if (all_found == FALSE) - return EXIT_FAILURE; - } -#endif - - return EXIT_SUCCESS; -} diff --git a/busybox/procps/pidof.c b/busybox/procps/pidof.c deleted file mode 100644 index 50dffd387..000000000 --- a/busybox/procps/pidof.c +++ /dev/null @@ -1,79 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * pidof implementation for busybox - * - * Copyright (C) 2001 by Lineo, inc. - * Written 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 - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - - -extern int pidof_main(int argc, char **argv) -{ - int opt; - - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "ne:f:")) > 0) { - switch (opt) { -#if 0 - case 'g': - break; - case 'e': - break; -#endif - default: - show_usage(); - } - } - - /* if we didn't get a process name, then we need to choke and die here */ - if (argv[optind] == NULL) - show_usage(); - - /* Looks like everything is set to go. */ - while(optind < argc) { - pid_t* pidList; - - pidList = find_pid_by_name( argv[optind]); - if (!pidList || *pidList<=0) { - break; - } - - for(; pidList && *pidList!=0; pidList++) { - printf("%ld ", (long)*pidList); - } - /* Note that we don't bother to free the memory - * allocated in find_pid_by_name(). It will be freed - * upon exit, so we can save a byte or two */ - optind++; - } - printf("\n"); - - return EXIT_SUCCESS; -} diff --git a/busybox/procps/ps.c b/busybox/procps/ps.c deleted file mode 100644 index 9e96a5402..000000000 --- a/busybox/procps/ps.c +++ /dev/null @@ -1,266 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini ps implementation(s) for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * - * - * This contains _two_ implementations of ps for Linux. One uses the - * traditional /proc virtual filesystem, and the other use the devps kernel - * driver (written by Erik Andersen to avoid using /proc thereby saving 100k+). - * - * - * - * 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 -#include "busybox.h" - -static const int TERMINAL_WIDTH = 79; /* not 80 in case terminal has linefold bug */ - - - -#if ! defined BB_FEATURE_USE_DEVPS_PATCH - -/* The following is the first ps implementation -- - * the one using the /proc virtual filesystem. - */ - -typedef struct proc_s { - char - cmd[16]; /* basename of executable file in call to exec(2) */ - int - ruid, /* real only (sorry) */ - pid, /* process id */ - ppid; /* pid of parent process */ - char - state; /* single-char code for process state (S=sleeping) */ -} proc_t; - - - -static int file2str(char *filename, char *ret, int cap) -{ - int fd, num_read; - - if ((fd = open(filename, O_RDONLY, 0)) == -1) - return -1; - if ((num_read = read(fd, ret, cap - 1)) <= 0) - return -1; - ret[num_read] = 0; - close(fd); - return num_read; -} - - -static void parse_proc_status(char *S, proc_t * P) -{ - char *tmp; - - memset(P->cmd, 0, sizeof P->cmd); - sscanf(S, "Name:\t%15c", P->cmd); - tmp = strchr(P->cmd, '\n'); - if (tmp) - *tmp = '\0'; - tmp = strstr(S, "State"); - sscanf(tmp, "State:\t%c", &P->state); - - tmp = strstr(S, "Pid:"); - if (tmp) - sscanf(tmp, "Pid:\t%d\n" "PPid:\t%d\n", &P->pid, &P->ppid); - else - error_msg("Internal error!"); - - /* For busybox, ignoring effective, saved, etc. */ - tmp = strstr(S, "Uid:"); - if (tmp) - sscanf(tmp, "Uid:\t%d", &P->ruid); - else - error_msg("Internal error!"); - - -} - -extern int ps_main(int argc, char **argv) -{ - proc_t p; - DIR *dir; - FILE *file; - struct dirent *entry; - char path[32], sbuf[512]; - char uidName[9]; - int len, i, c; -#ifdef BB_FEATURE_AUTOWIDTH - struct winsize win = { 0, 0, 0, 0 }; - int terminal_width = TERMINAL_WIDTH; -#else -#define terminal_width TERMINAL_WIDTH -#endif - - - - dir = opendir("/proc"); - if (!dir) - error_msg_and_die("Can't open /proc"); - -#ifdef BB_FEATURE_AUTOWIDTH - ioctl(fileno(stdout), TIOCGWINSZ, &win); - if (win.ws_col > 0) - terminal_width = win.ws_col - 1; -#endif - - printf(" PID Uid Stat Command\n"); - while ((entry = readdir(dir)) != NULL) { - if (!isdigit(*entry->d_name)) - continue; - sprintf(path, "/proc/%s/status", entry->d_name); - if ((file2str(path, sbuf, sizeof sbuf)) != -1) { - parse_proc_status(sbuf, &p); - } - - /* Make some adjustments as needed */ - my_getpwuid(uidName, p.ruid); - if (*uidName == '\0') - sprintf(uidName, "%d", p.ruid); - - sprintf(path, "/proc/%s/cmdline", entry->d_name); - file = fopen(path, "r"); - if (file == NULL) - continue; - i = 0; - len = printf("%5d %-8s %c ", p.pid, uidName, p.state); - while (((c = getc(file)) != EOF) && (i < (terminal_width-len))) { - i++; - if (c == '\0') - c = ' '; - putc(c, stdout); - } - fclose(file); - if (i == 0) - printf("[%s]", p.cmd); - putchar('\n'); - } - closedir(dir); - return EXIT_SUCCESS; -} - - -#else /* BB_FEATURE_USE_DEVPS_PATCH */ - - -/* The following is the second ps implementation -- - * this one uses the nifty new devps kernel device. - */ - -#include /* For Erik's nifty devps device driver */ - - -extern int ps_main(int argc, char **argv) -{ - char device[] = "/dev/ps"; - int i, j, len, fd; - pid_t num_pids; - pid_t* pid_array = NULL; - struct pid_info info; - char uidName[9]; -#ifdef BB_FEATURE_AUTOWIDTH - struct winsize win = { 0, 0, 0, 0 }; - int terminal_width = TERMINAL_WIDTH; -#else -#define terminal_width TERMINAL_WIDTH -#endif - - if (argc > 1 && **(argv + 1) == '-') - show_usage(); - - /* open device */ - fd = open(device, O_RDONLY); - if (fd < 0) - perror_msg_and_die( "open failed for `%s'", device); - - /* Find out how many processes there are */ - if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) - perror_msg_and_die( "\nDEVPS_GET_PID_LIST"); - - /* Allocate some memory -- grab a few extras just in case - * some new processes start up while we wait. The kernel will - * just ignore any extras if we give it too many, and will trunc. - * the list if we give it too few. */ - pid_array = (pid_t*) xcalloc( num_pids+10, sizeof(pid_t)); - pid_array[0] = num_pids+10; - - /* Now grab the pid list */ - if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) - perror_msg_and_die("\nDEVPS_GET_PID_LIST"); - -#ifdef BB_FEATURE_AUTOWIDTH - ioctl(fileno(stdout), TIOCGWINSZ, &win); - if (win.ws_col > 0) - terminal_width = win.ws_col - 1; -#endif - - /* Print up a ps listing */ - printf(" PID Uid Stat Command\n"); - - for (i=1; i 1) { - for( j=0; j<(sizeof(info.command_line)-1) && j < (terminal_width-len); j++) { - if (*(info.command_line+j) == '\0' && *(info.command_line+j+1) != '\0') { - *(info.command_line+j) = ' '; - } - } - *(info.command_line+j) = '\0'; - puts(info.command_line); - } else { - printf("[%s]\n", info.name); - } - } - - /* Free memory */ - free( pid_array); - - /* close device */ - if (close (fd) != 0) - perror_msg_and_die("close failed for `%s'", device); - - exit (0); -} - -#endif /* BB_FEATURE_USE_DEVPS_PATCH */ - diff --git a/busybox/procps/renice.c b/busybox/procps/renice.c deleted file mode 100644 index ec35bdcde..000000000 --- a/busybox/procps/renice.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Mini renice implementation for busybox - * - * - * Copyright (C) 2000 Dave 'Kill a Cop' Cinege - * - * 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 "busybox.h" - - -extern int renice_main(int argc, char **argv) -{ - int prio, status = EXIT_SUCCESS; - - if (argc < 3) show_usage(); - - prio = atoi(*++argv); - if (prio > 20) prio = 20; - if (prio < -20) prio = -20; - - while (*++argv) { - int ps = atoi(*argv); - int oldp = getpriority(PRIO_PROCESS, ps); - - if (setpriority(PRIO_PROCESS, ps, prio) == 0) { - printf("%d: old priority %d, new priority %d\n", ps, oldp, prio ); - } else { - perror_msg("%d: setpriority", ps); - status = EXIT_FAILURE; - } - } - - return status; -} diff --git a/busybox/procps/uptime.c b/busybox/procps/uptime.c deleted file mode 100644 index 6758d959e..000000000 --- a/busybox/procps/uptime.c +++ /dev/null @@ -1,77 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini uptime implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -/* This version of uptime doesn't display the number of users on the system, - * since busybox init doesn't mess with utmp. For folks using utmp that are - * just dying to have # of users reported, feel free to write it as some type - * of BB_FEATURE_UTMP_SUPPORT #define - */ - -/* getopt not needed */ - - -#include -#include -#include -#include -#include "busybox.h" - -static const int FSHIFT = 16; /* nr of bits of precision */ -#define FIXED_1 (1<> FSHIFT) -#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) - - -extern int uptime_main(int argc, char **argv) -{ - int updays, uphours, upminutes; - struct sysinfo info; - struct tm *current_time; - time_t current_secs; - - time(¤t_secs); - current_time = localtime(¤t_secs); - - sysinfo(&info); - - printf(" %2d:%02d%s up ", - current_time->tm_hour%12 ? current_time->tm_hour%12 : 12, - current_time->tm_min, current_time->tm_hour > 11 ? "pm" : "am"); - updays = (int) info.uptime / (60*60*24); - if (updays) - printf("%d day%s, ", updays, (updays != 1) ? "s" : ""); - upminutes = (int) info.uptime / 60; - uphours = (upminutes / 60) % 24; - upminutes %= 60; - if(uphours) - printf("%2d:%02d, ", uphours, upminutes); - else - printf("%d min, ", upminutes); - - printf("load average: %ld.%02ld, %ld.%02ld, %ld.%02ld\n", - LOAD_INT(info.loads[0]), LOAD_FRAC(info.loads[0]), - LOAD_INT(info.loads[1]), LOAD_FRAC(info.loads[1]), - LOAD_INT(info.loads[2]), LOAD_FRAC(info.loads[2])); - - return EXIT_SUCCESS; -} diff --git a/busybox/ps.c b/busybox/ps.c deleted file mode 100644 index 9e96a5402..000000000 --- a/busybox/ps.c +++ /dev/null @@ -1,266 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini ps implementation(s) for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * - * - * This contains _two_ implementations of ps for Linux. One uses the - * traditional /proc virtual filesystem, and the other use the devps kernel - * driver (written by Erik Andersen to avoid using /proc thereby saving 100k+). - * - * - * - * 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 -#include "busybox.h" - -static const int TERMINAL_WIDTH = 79; /* not 80 in case terminal has linefold bug */ - - - -#if ! defined BB_FEATURE_USE_DEVPS_PATCH - -/* The following is the first ps implementation -- - * the one using the /proc virtual filesystem. - */ - -typedef struct proc_s { - char - cmd[16]; /* basename of executable file in call to exec(2) */ - int - ruid, /* real only (sorry) */ - pid, /* process id */ - ppid; /* pid of parent process */ - char - state; /* single-char code for process state (S=sleeping) */ -} proc_t; - - - -static int file2str(char *filename, char *ret, int cap) -{ - int fd, num_read; - - if ((fd = open(filename, O_RDONLY, 0)) == -1) - return -1; - if ((num_read = read(fd, ret, cap - 1)) <= 0) - return -1; - ret[num_read] = 0; - close(fd); - return num_read; -} - - -static void parse_proc_status(char *S, proc_t * P) -{ - char *tmp; - - memset(P->cmd, 0, sizeof P->cmd); - sscanf(S, "Name:\t%15c", P->cmd); - tmp = strchr(P->cmd, '\n'); - if (tmp) - *tmp = '\0'; - tmp = strstr(S, "State"); - sscanf(tmp, "State:\t%c", &P->state); - - tmp = strstr(S, "Pid:"); - if (tmp) - sscanf(tmp, "Pid:\t%d\n" "PPid:\t%d\n", &P->pid, &P->ppid); - else - error_msg("Internal error!"); - - /* For busybox, ignoring effective, saved, etc. */ - tmp = strstr(S, "Uid:"); - if (tmp) - sscanf(tmp, "Uid:\t%d", &P->ruid); - else - error_msg("Internal error!"); - - -} - -extern int ps_main(int argc, char **argv) -{ - proc_t p; - DIR *dir; - FILE *file; - struct dirent *entry; - char path[32], sbuf[512]; - char uidName[9]; - int len, i, c; -#ifdef BB_FEATURE_AUTOWIDTH - struct winsize win = { 0, 0, 0, 0 }; - int terminal_width = TERMINAL_WIDTH; -#else -#define terminal_width TERMINAL_WIDTH -#endif - - - - dir = opendir("/proc"); - if (!dir) - error_msg_and_die("Can't open /proc"); - -#ifdef BB_FEATURE_AUTOWIDTH - ioctl(fileno(stdout), TIOCGWINSZ, &win); - if (win.ws_col > 0) - terminal_width = win.ws_col - 1; -#endif - - printf(" PID Uid Stat Command\n"); - while ((entry = readdir(dir)) != NULL) { - if (!isdigit(*entry->d_name)) - continue; - sprintf(path, "/proc/%s/status", entry->d_name); - if ((file2str(path, sbuf, sizeof sbuf)) != -1) { - parse_proc_status(sbuf, &p); - } - - /* Make some adjustments as needed */ - my_getpwuid(uidName, p.ruid); - if (*uidName == '\0') - sprintf(uidName, "%d", p.ruid); - - sprintf(path, "/proc/%s/cmdline", entry->d_name); - file = fopen(path, "r"); - if (file == NULL) - continue; - i = 0; - len = printf("%5d %-8s %c ", p.pid, uidName, p.state); - while (((c = getc(file)) != EOF) && (i < (terminal_width-len))) { - i++; - if (c == '\0') - c = ' '; - putc(c, stdout); - } - fclose(file); - if (i == 0) - printf("[%s]", p.cmd); - putchar('\n'); - } - closedir(dir); - return EXIT_SUCCESS; -} - - -#else /* BB_FEATURE_USE_DEVPS_PATCH */ - - -/* The following is the second ps implementation -- - * this one uses the nifty new devps kernel device. - */ - -#include /* For Erik's nifty devps device driver */ - - -extern int ps_main(int argc, char **argv) -{ - char device[] = "/dev/ps"; - int i, j, len, fd; - pid_t num_pids; - pid_t* pid_array = NULL; - struct pid_info info; - char uidName[9]; -#ifdef BB_FEATURE_AUTOWIDTH - struct winsize win = { 0, 0, 0, 0 }; - int terminal_width = TERMINAL_WIDTH; -#else -#define terminal_width TERMINAL_WIDTH -#endif - - if (argc > 1 && **(argv + 1) == '-') - show_usage(); - - /* open device */ - fd = open(device, O_RDONLY); - if (fd < 0) - perror_msg_and_die( "open failed for `%s'", device); - - /* Find out how many processes there are */ - if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) - perror_msg_and_die( "\nDEVPS_GET_PID_LIST"); - - /* Allocate some memory -- grab a few extras just in case - * some new processes start up while we wait. The kernel will - * just ignore any extras if we give it too many, and will trunc. - * the list if we give it too few. */ - pid_array = (pid_t*) xcalloc( num_pids+10, sizeof(pid_t)); - pid_array[0] = num_pids+10; - - /* Now grab the pid list */ - if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) - perror_msg_and_die("\nDEVPS_GET_PID_LIST"); - -#ifdef BB_FEATURE_AUTOWIDTH - ioctl(fileno(stdout), TIOCGWINSZ, &win); - if (win.ws_col > 0) - terminal_width = win.ws_col - 1; -#endif - - /* Print up a ps listing */ - printf(" PID Uid Stat Command\n"); - - for (i=1; i 1) { - for( j=0; j<(sizeof(info.command_line)-1) && j < (terminal_width-len); j++) { - if (*(info.command_line+j) == '\0' && *(info.command_line+j+1) != '\0') { - *(info.command_line+j) = ' '; - } - } - *(info.command_line+j) = '\0'; - puts(info.command_line); - } else { - printf("[%s]\n", info.name); - } - } - - /* Free memory */ - free( pid_array); - - /* close device */ - if (close (fd) != 0) - perror_msg_and_die("close failed for `%s'", device); - - exit (0); -} - -#endif /* BB_FEATURE_USE_DEVPS_PATCH */ - diff --git a/busybox/pwd.c b/busybox/pwd.c deleted file mode 100644 index f6a00bf1e..000000000 --- a/busybox/pwd.c +++ /dev/null @@ -1,44 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini pwd implementation for busybox - * - * - * 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 - * - */ - -/* getopt not needed */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -extern int pwd_main(int argc, char **argv) -{ - static char *buf; - - buf = xgetcwd(buf); - - if (buf != NULL) { - puts(buf); - return EXIT_SUCCESS; - } - return EXIT_FAILURE; -} diff --git a/busybox/rdate.c b/busybox/rdate.c deleted file mode 100644 index 50be4de8c..000000000 --- a/busybox/rdate.c +++ /dev/null @@ -1,116 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * The Rdate command will ask a time server for the RFC 868 time - * and optionally set the system time. - * - * by Sterling Huxley - * - * 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 -#include -#include "busybox.h" - - -static const int RFC_868_BIAS = 2208988800UL; - -static time_t askremotedate(const char *host) -{ - struct hostent *h; - struct sockaddr_in s_in; - struct servent *tserv; - unsigned long int nett, localt; - int fd; - - h = xgethostbyname(host); /* get the IP addr */ - - if ((tserv = getservbyname("time", "tcp")) == NULL) /* find port # */ - perror_msg_and_die("time"); - - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) /* get net connection */ - perror_msg_and_die("socket"); - - memcpy(&s_in.sin_addr, h->h_addr, sizeof(s_in.sin_addr)); - s_in.sin_port= tserv->s_port; - s_in.sin_family = AF_INET; - - if (connect(fd, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) /* connect to time server */ - perror_msg_and_die("%s", host); - - if (read(fd, (void *)&nett, 4) != 4) /* read time from server */ - error_msg_and_die("%s did not send the complete time", host); - - close(fd); - - /* convert from network byte order to local byte order. - * RFC 868 time is the number of seconds - * since 00:00 (midnight) 1 January 1900 GMT - * the RFC 868 time 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT - * Subtract the RFC 868 time to get Linux epoch - */ - localt= ntohl(nett) - RFC_868_BIAS; - - return(localt); -} - -int rdate_main(int argc, char **argv) -{ - time_t remote_time; - int opt; - int setdate = 1; - int printdate = 1; - - /* Interpret command line args */ - while ((opt = getopt(argc, argv, "sp")) > 0) { - switch (opt) { - case 's': - printdate = 0; - setdate = 1; - break; - case 'p': - printdate = 1; - setdate = 0; - break; - default: - show_usage(); - } - } - - if (optind == argc) - show_usage(); - - remote_time = askremotedate(argv[optind]); - - if (setdate) { - if (stime(&remote_time) < 0) - perror_msg_and_die("Could not set time of day"); - } - - if (printdate) - printf("%s", ctime(&remote_time)); - - return EXIT_SUCCESS; -} diff --git a/busybox/readlink.c b/busybox/readlink.c deleted file mode 100644 index c46ebd108..000000000 --- a/busybox/readlink.c +++ /dev/null @@ -1,48 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini readlink implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include "busybox.h" - -int readlink_main(int argc, char **argv) -{ - char *buf = NULL; - - /* no options, no getopt */ - - if (argc != 2) - show_usage(); - - buf = xreadlink(argv[1]); - if (!buf) - return EXIT_FAILURE; - puts(buf); -#ifdef BB_FEATURE_CLEAN_UP - free(buf); -#endif - - return EXIT_SUCCESS; -} diff --git a/busybox/reboot.c b/busybox/reboot.c deleted file mode 100644 index 35afd74ff..000000000 --- a/busybox/reboot.c +++ /dev/null @@ -1,49 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini reboot implementation for busybox - * - * - * 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 - * - */ - -#include "busybox.h" -#include - -extern int reboot_main(int argc, char **argv) -{ -#ifdef BB_FEATURE_LINUXRC - /* don't assume init's pid == 1 */ - pid_t *pid = find_pid_by_name("init"); - if (!pid || *pid<=0) { - pid = find_pid_by_name("linuxrc"); - if (!pid || *pid<=0) - error_msg_and_die("no process killed"); - } - return(kill(*pid, SIGTERM)); -#else - return(kill(1, SIGTERM)); -#endif -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/renice.c b/busybox/renice.c deleted file mode 100644 index ec35bdcde..000000000 --- a/busybox/renice.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Mini renice implementation for busybox - * - * - * Copyright (C) 2000 Dave 'Kill a Cop' Cinege - * - * 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 "busybox.h" - - -extern int renice_main(int argc, char **argv) -{ - int prio, status = EXIT_SUCCESS; - - if (argc < 3) show_usage(); - - prio = atoi(*++argv); - if (prio > 20) prio = 20; - if (prio < -20) prio = -20; - - while (*++argv) { - int ps = atoi(*argv); - int oldp = getpriority(PRIO_PROCESS, ps); - - if (setpriority(PRIO_PROCESS, ps, prio) == 0) { - printf("%d: old priority %d, new priority %d\n", ps, oldp, prio ); - } else { - perror_msg("%d: setpriority", ps); - status = EXIT_FAILURE; - } - } - - return status; -} diff --git a/busybox/reset.c b/busybox/reset.c deleted file mode 100644 index 755c4c335..000000000 --- a/busybox/reset.c +++ /dev/null @@ -1,35 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini reset implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * and Kent Robotti - * - * 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 "busybox.h" - -extern int reset_main(int argc, char **argv) -{ - printf("\033c"); - return EXIT_SUCCESS; -} - diff --git a/busybox/rm.c b/busybox/rm.c deleted file mode 100644 index 51c9f4ceb..000000000 --- a/busybox/rm.c +++ /dev/null @@ -1,77 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini rm implementation for busybox - * - * - * 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -extern int rm_main(int argc, char **argv) -{ - int status = 0; - int opt; - int flags = 0; - int i; - - while ((opt = getopt(argc, argv, "fiRr")) != -1) { - switch (opt) { - case 'f': - flags &= ~FILEUTILS_INTERACTIVE; - flags |= FILEUTILS_FORCE; - break; - case 'i': - flags &= ~FILEUTILS_FORCE; - flags |= FILEUTILS_INTERACTIVE; - break; - case 'R': - case 'r': - flags |= FILEUTILS_RECUR; - break; - } - } - - if (!(flags & FILEUTILS_FORCE) && optind == argc) - show_usage(); - - for (i = optind; i < argc; i++) { - char *base = get_last_path_component(argv[i]); - - if (strcmp(base, ".") == 0 || strcmp(base, "..") == 0) { - error_msg("cannot remove `.' or `..'"); - status = 1; - continue; - } - - if (remove_file(argv[i], flags) < 0) - status = 1; - } - - return status; -} diff --git a/busybox/rmdir.c b/busybox/rmdir.c deleted file mode 100644 index cac27cac9..000000000 --- a/busybox/rmdir.c +++ /dev/null @@ -1,97 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini rmdir implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include - -#include "busybox.h" - - -/* Return true if a path is composed of multiple components. */ - -static int -multiple_components_p (const char *path) -{ - const char *s = path; - - while (s[0] != '\0' && s[0] != '/') - s++; - - while (s[0] == '/') - s++; - - return (s[0] != '\0'); -} - - -/* Remove a directory. Returns 0 if successful, -1 on error. */ - -static int -remove_directory (char *path, int flags) -{ - if (!(flags & FILEUTILS_RECUR)) { - if (rmdir (path) < 0) { - perror_msg ("unable to remove `%s'", path); - return -1; - } - } else { - if (remove_directory (path, 0) < 0) - return -1; - - if (multiple_components_p (path)) - if (remove_directory (dirname (path), flags) < 0) - return -1; - } - - return 0; -} - - -extern int -rmdir_main (int argc, char **argv) -{ - int status = EXIT_SUCCESS; - int flags = 0; - int i, opt; - - while ((opt = getopt (argc, argv, "p")) != -1) - switch (opt) { - case 'p': - flags |= FILEUTILS_RECUR; - break; - - default: - show_usage (); - } - - if (optind == argc) - show_usage(); - - for (i = optind; i < argc; i++) - if (remove_directory (argv[i], flags) < 0) - status = EXIT_FAILURE; - - return status; -} diff --git a/busybox/rmmod.c b/busybox/rmmod.c deleted file mode 100644 index 7596d0232..000000000 --- a/busybox/rmmod.c +++ /dev/null @@ -1,62 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini rmmod implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -extern int delete_module(const char * name); - - -extern int rmmod_main(int argc, char **argv) -{ - int n, ret = EXIT_SUCCESS; - - /* Parse command line. */ - while ((n = getopt(argc, argv, "a")) != EOF) { - switch (n) { - case 'a': - /* Unload _all_ unused modules via NULL delete_module() call */ - if (delete_module(NULL)) - perror_msg_and_die("rmmod"); - return EXIT_SUCCESS; - default: - show_usage(); - } - } - - if (optind == argc) - show_usage(); - - for (n = optind; n < argc; n++) { - if (delete_module(argv[n]) < 0) { - perror_msg("%s", argv[n]); - ret = EXIT_FAILURE; - } - } - - return(ret); -} diff --git a/busybox/route.c b/busybox/route.c deleted file mode 100644 index 9d210af64..000000000 --- a/busybox/route.c +++ /dev/null @@ -1,450 +0,0 @@ -/* route - * - * Similar to the standard Unix route, but with only the necessary - * parts for AF_INET - * - * Bjorn Wesen, Axis Communications AB - * - * Author of the original route: - * Fred N. van Kempen, - * (derived from FvK's 'route.c 1.70 01/04/94') - * - * 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. - * - * displayroute() code added by Vladimir N. Oleynik - * adjustments by Larry Doolittle - */ - -#include -#include -#include -#include -#include // HZ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#define _(x) x - -#define RTACTION_ADD 1 -#define RTACTION_DEL 2 -#define RTACTION_HELP 3 -#define RTACTION_FLUSH 4 -#define RTACTION_SHOW 5 - -#define E_NOTFOUND 8 -#define E_SOCK 7 -#define E_LOOKUP 6 -#define E_VERSION 5 -#define E_USAGE 4 -#define E_OPTERR 3 -#define E_INTERN 2 -#define E_NOSUPP 1 - -/* resolve XXX.YYY.ZZZ.QQQ -> binary */ - -static int -INET_resolve(char *name, struct sockaddr *sa) -{ - struct sockaddr_in *s_in = (struct sockaddr_in *)sa; - - s_in->sin_family = AF_INET; - s_in->sin_port = 0; - - /* Default is special, meaning 0.0.0.0. */ - if (strcmp(name, "default")==0) { - s_in->sin_addr.s_addr = INADDR_ANY; - return 1; - } - /* Look to see if it's a dotted quad. */ - if (inet_aton(name, &s_in->sin_addr)) { - return 0; - } - /* guess not.. */ - return -1; -} - -#if defined (SIOCADDRTOLD) || defined (RTF_IRTT) /* route */ -#define HAVE_NEW_ADDRT 1 -#endif -#ifdef RTF_IRTT /* route */ -#define HAVE_RTF_IRTT 1 -#endif -#ifdef RTF_REJECT /* route */ -#define HAVE_RTF_REJECT 1 -#endif - -#if HAVE_NEW_ADDRT -#define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr) -#define full_mask(x) (x) -#else -#define mask_in_addr(x) ((x).rt_genmask) -#define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr) -#endif - -/* add or delete a route depending on action */ - -static int -INET_setroute(int action, int options, char **args) -{ - struct rtentry rt; - char target[128], gateway[128] = "NONE", netmask[128] = "default"; - int xflag, isnet; - int skfd; - - xflag = 0; - - if (*args == NULL) - show_usage(); - if (strcmp(*args, "-net")==0) { - xflag = 1; - args++; - } else if (strcmp(*args, "-host")==0) { - xflag = 2; - args++; - } - safe_strncpy(target, *args++, (sizeof target)); - - /* Clean out the RTREQ structure. */ - memset((char *) &rt, 0, sizeof(struct rtentry)); - - - if ((isnet = INET_resolve(target, &rt.rt_dst)) < 0) { - error_msg(_("can't resolve %s"), target); - return EXIT_FAILURE; /* XXX change to E_something */ - } - - switch (xflag) { - case 1: - isnet = 1; - break; - - case 2: - isnet = 0; - break; - - default: - break; - } - - /* Fill in the other fields. */ - rt.rt_flags = (RTF_UP | RTF_HOST); - if (isnet) - rt.rt_flags &= ~RTF_HOST; - - while (*args) { - if (strcmp(*args, "metric")==0) { - int metric; - - args++; - if (!*args || !isdigit(**args)) - show_usage(); - metric = atoi(*args); -#if HAVE_NEW_ADDRT - rt.rt_metric = metric + 1; -#else - ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); /* XXX Fixme */ -#endif - args++; - continue; - } - - if (strcmp(*args, "netmask")==0) { - struct sockaddr mask; - - args++; - if (!*args || mask_in_addr(rt)) - show_usage(); - safe_strncpy(netmask, *args, (sizeof netmask)); - if ((isnet = INET_resolve(netmask, &mask)) < 0) { - error_msg(_("can't resolve netmask %s"), netmask); - return E_LOOKUP; - } - rt.rt_genmask = full_mask(mask); - args++; - continue; - } - - if (strcmp(*args, "gw")==0 || strcmp(*args, "gateway")==0) { - args++; - if (!*args) - show_usage(); - if (rt.rt_flags & RTF_GATEWAY) - show_usage(); - safe_strncpy(gateway, *args, (sizeof gateway)); - if ((isnet = INET_resolve(gateway, &rt.rt_gateway)) < 0) { - error_msg(_("can't resolve gw %s"), gateway); - return E_LOOKUP; - } - if (isnet) { - error_msg( - _("%s: cannot use a NETWORK as gateway!"), - gateway); - return E_OPTERR; - } - rt.rt_flags |= RTF_GATEWAY; - args++; - continue; - } - - if (strcmp(*args, "mss")==0) { - args++; - rt.rt_flags |= RTF_MSS; - if (!*args) - show_usage(); - rt.rt_mss = atoi(*args); - args++; - if (rt.rt_mss < 64 || rt.rt_mss > 32768) { - error_msg(_("Invalid MSS.")); - return E_OPTERR; - } - continue; - } - - if (strcmp(*args, "window")==0) { - args++; - if (!*args) - show_usage(); - rt.rt_flags |= RTF_WINDOW; - rt.rt_window = atoi(*args); - args++; - if (rt.rt_window < 128) { - error_msg(_("Invalid window.")); - return E_OPTERR; - } - continue; - } - - if (strcmp(*args, "irtt")==0) { - args++; - if (!*args) - show_usage(); - args++; -#if HAVE_RTF_IRTT - rt.rt_flags |= RTF_IRTT; - rt.rt_irtt = atoi(*(args - 1)); - rt.rt_irtt *= (HZ / 100); /* FIXME */ -#if 0 /* FIXME: do we need to check anything of this? */ - if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) { - error_msg(_("Invalid initial rtt.")); - return E_OPTERR; - } -#endif -#else - ENOSUPP("inet_setroute", "RTF_IRTT"); /* XXX Fixme */ -#endif - continue; - } - - if (strcmp(*args, "reject")==0) { - args++; -#if HAVE_RTF_REJECT - rt.rt_flags |= RTF_REJECT; -#else - ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */ -#endif - continue; - } - if (strcmp(*args, "mod")==0) { - args++; - rt.rt_flags |= RTF_MODIFIED; - continue; - } - if (strcmp(*args, "dyn")==0) { - args++; - rt.rt_flags |= RTF_DYNAMIC; - continue; - } - if (strcmp(*args, "reinstate")==0) { - args++; - rt.rt_flags |= RTF_REINSTATE; - continue; - } - if (strcmp(*args, "device")==0 || strcmp(*args, "dev")==0) { - args++; - if (rt.rt_dev || *args == NULL) - show_usage(); - rt.rt_dev = *args++; - continue; - } - /* nothing matches */ - if (!rt.rt_dev) { - rt.rt_dev = *args++; - if (*args) - show_usage(); /* must be last to catch typos */ - } else { - show_usage(); - } - } - -#if HAVE_RTF_REJECT - if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev) - rt.rt_dev = "lo"; -#endif - - /* sanity checks.. */ - if (mask_in_addr(rt)) { - unsigned long mask = mask_in_addr(rt); - mask = ~ntohl(mask); - if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) { - error_msg( - _("netmask %.8x doesn't make sense with host route"), - (unsigned int)mask); - return E_OPTERR; - } - if (mask & (mask + 1)) { - error_msg(_("bogus netmask %s"), netmask); - return E_OPTERR; - } - mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr; - if (mask & ~mask_in_addr(rt)) { - error_msg(_("netmask doesn't match route address")); - return E_OPTERR; - } - } - /* Fill out netmask if still unset */ - if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST) - mask_in_addr(rt) = 0xffffffff; - - /* Create a socket to the INET kernel. */ - if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - perror("socket"); - return E_SOCK; - } - /* Tell the kernel to accept this route. */ - if (action == RTACTION_DEL) { - if (ioctl(skfd, SIOCDELRT, &rt) < 0) { - perror("SIOCDELRT"); - close(skfd); - return E_SOCK; - } - } else { - if (ioctl(skfd, SIOCADDRT, &rt) < 0) { - perror("SIOCADDRT"); - close(skfd); - return E_SOCK; - } - } - - /* Close the socket. */ - (void) close(skfd); - return EXIT_SUCCESS; -} - -#ifndef RTF_UP -/* Keep this in sync with /usr/src/linux/include/linux/route.h */ -#define RTF_UP 0x0001 /* route usable */ -#define RTF_GATEWAY 0x0002 /* destination is a gateway */ -#define RTF_HOST 0x0004 /* host entry (net otherwise) */ -#define RTF_REINSTATE 0x0008 /* reinstate route after tmout */ -#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */ -#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */ -#define RTF_MTU 0x0040 /* specific MTU for this route */ -#ifndef RTF_MSS -#define RTF_MSS RTF_MTU /* Compatibility :-( */ -#endif -#define RTF_WINDOW 0x0080 /* per route window clamping */ -#define RTF_IRTT 0x0100 /* Initial round trip time */ -#define RTF_REJECT 0x0200 /* Reject route */ -#endif - -static void displayroutes(void) -{ - char buff[256]; - int nl = 0 ; - struct in_addr dest; - struct in_addr gw; - struct in_addr mask; - int flgs, ref, use, metric; - char flags[64]; - unsigned long int d,g,m; - - char sdest[16], sgw[16]; - - - FILE *fp = xfopen("/proc/net/route", "r"); - - while( fgets(buff, sizeof(buff), fp) != NULL ) { - if(nl) { - int ifl = 0; - while(buff[ifl]!=' ' && buff[ifl]!='\t' && buff[ifl]!='\0') - ifl++; - buff[ifl]=0; /* interface */ - if(sscanf(buff+ifl+1, "%lx%lx%X%d%d%d%lx", - &d, &g, &flgs, &ref, &use, &metric, &m)!=7) { - error_msg_and_die( "Unsuported kernel route format\n"); - } - if(nl==1) - printf("Kernel IP routing table\n" - "Destination Gateway Genmask Flags Metric Ref Use Iface\n"); - - ifl = 0; /* parse flags */ - if(flgs&RTF_UP) { - if(flgs&RTF_REJECT) - flags[ifl++]='!'; - else - flags[ifl++]='U'; - if(flgs&RTF_GATEWAY) - flags[ifl++]='G'; - if(flgs&RTF_HOST) - flags[ifl++]='H'; - if(flgs&RTF_REINSTATE) - flags[ifl++]='R'; - if(flgs&RTF_DYNAMIC) - flags[ifl++]='D'; - if(flgs&RTF_MODIFIED) - flags[ifl++]='M'; - flags[ifl]=0; - dest.s_addr = d; - gw.s_addr = g; - mask.s_addr = m; - strcpy(sdest, (dest.s_addr==0 ? "default" : - inet_ntoa(dest))); - strcpy(sgw, (gw.s_addr==0 ? "*" : - inet_ntoa(gw))); - printf("%-16s%-16s%-16s%-6s%-6d %-2d %7d %s\n", - sdest, sgw, - inet_ntoa(mask), - flags, metric, ref, use, buff); - } - } - nl++; - } -} - -int route_main(int argc, char **argv) -{ - int what = 0; - - argc--; - argv++; - - if (*argv == NULL) { - displayroutes(); - return EXIT_SUCCESS; - } else { - /* check verb */ - if (strcmp(*argv, "add")==0) - what = RTACTION_ADD; - else if (strcmp(*argv, "del")==0 || strcmp(*argv, "delete")==0) - what = RTACTION_DEL; - else if (strcmp(*argv, "flush")==0) - what = RTACTION_FLUSH; - else - show_usage(); - } - - return INET_setroute(what, 0, ++argv); -} diff --git a/busybox/rpm2cpio.c b/busybox/rpm2cpio.c deleted file mode 100644 index 8d639d6ad..000000000 --- a/busybox/rpm2cpio.c +++ /dev/null @@ -1,91 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini rpm2cpio implementation for busybox - * - * Copyright (C) 2001 by Laurence Anderson - * - * 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 "busybox.h" -#include /* For ntohl & htonl function */ -#include - -#define RPM_MAGIC "\355\253\356\333" -#define RPM_HEADER_MAGIC "\216\255\350" - -struct rpm_lead { - unsigned char magic[4]; - u_int8_t major, minor; - u_int16_t type; - u_int16_t archnum; - char name[66]; - u_int16_t osnum; - u_int16_t signature_type; - char reserved[16]; -}; - -struct rpm_header { - char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */ - u_int8_t version; /* 1 byte version number */ - u_int32_t reserved; /* 4 bytes reserved */ - u_int32_t entries; /* Number of entries in header (4 bytes) */ - u_int32_t size; /* Size of store (4 bytes) */ -}; - -void skip_header(FILE *rpmfile) -{ - struct rpm_header header; - - fread(&header, sizeof(struct rpm_header), 1, rpmfile); - if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) error_msg_and_die("Invalid RPM header magic"); /* Invalid magic */ - if (header.version != 1) error_msg_and_die("Unsupported RPM header version"); /* This program only supports v1 headers */ - header.entries = ntohl(header.entries); - header.size = ntohl(header.size); - fseek (rpmfile, 16 * header.entries, SEEK_CUR); /* Seek past index entries */ - fseek (rpmfile, header.size, SEEK_CUR); /* Seek past store */ -} - -/* No getopt required */ -extern int rpm2cpio_main(int argc, char **argv) -{ - struct rpm_lead lead; - int gunzip_pid; - FILE *rpmfile, *cpiofile; - - if (argc == 1) { - rpmfile = stdin; - } else { - rpmfile = fopen(argv[1], "r"); - if (!rpmfile) perror_msg_and_die("Can't open rpm file"); - /* set the buffer size */ - setvbuf(rpmfile, NULL, _IOFBF, 0x8000); - } - - fread (&lead, sizeof(struct rpm_lead), 1, rpmfile); - if (strncmp((char *) &lead.magic, RPM_MAGIC, 4) != 0) error_msg_and_die("Invalid RPM magic"); /* Just check the magic, the rest is irrelevant */ - /* Skip the signature header */ - skip_header(rpmfile); - fseek(rpmfile, (8 - (ftell(rpmfile) % 8)) % 8, SEEK_CUR); /* Pad to 8 byte boundary */ - /* Skip the main header */ - skip_header(rpmfile); - - cpiofile = gz_open(rpmfile, &gunzip_pid); - - copyfd(fileno(cpiofile), fileno(stdout)); - gz_close(gunzip_pid); - fclose(rpmfile); - return 0; -} diff --git a/busybox/scripts/depmod.pl b/busybox/scripts/depmod.pl deleted file mode 100755 index e65f07b68..000000000 --- a/busybox/scripts/depmod.pl +++ /dev/null @@ -1,227 +0,0 @@ -#!/usr/bin/perl -w -# vi: set ts=4: -# Copyright (c) 2001 David Schleef -# Copyright (c) 2001 Erik Andersen -# Copyright (c) 2001 Stuart Hughes -# This program is free software; you can redistribute it and/or modify it -# under the same terms as Perl itself. - -# TODO -- use strict mode... -#use strict; - -use Getopt::Long; -use File::Find; - - -# Set up some default values - -my $basedir=""; -my $kernel; -my $kernelsyms; -my $stdout=1; -my $verbose=0; - - -# get command-line options - -my %opt; - -GetOptions( - \%opt, - "help|h", - "basedir|b=s" => \$basedir, - "kernel|k=s" => \$kernel, - "kernelsyms|F=s" => \$kernelsyms, - "stdout|n" => \$stdout, - "verbose|v" => \$verbose, -); - -if (defined $opt{help}) { - print - "$0 [OPTION]... [basedir]\n", - "\t-h --help\t\tShow this help screen\n", - "\t-b --basedir\t\tModules base directory (defaults to /lib/modules)\n", - "\t-k --kernel\t\tKernel binary for the target\n", - "\t-F --kernelsyms\t\tKernel symbol file\n", - "\t-n --stdout\t\tWrite to stdout instead of modules.dep\n", - "\t-v --verbose\t\tPrint out lots of debugging stuff\n", - ; - exit 1; -} - -if($basedir !~ m-/lib/modules-) { - warn "WARNING: base directory does not match ..../lib/modules\n"; -} - -# Find the list of .o files living under $basedir -#if ($verbose) { printf "Locating all modules\n"; } -my($file) = ""; -my(@liblist) = (); -find sub { - if ( -f $_ && ! -d $_ ) { - $file = $File::Find::name; - if ( $file =~ /.o$/ ) { - push(@liblist, $file); - if ($verbose) { printf "$file\n"; } - } - } -}, $basedir; -if ($verbose) { printf "Finished locating modules\n"; } - -foreach $obj ( @liblist, $kernel ){ - # turn the input file name into a target tag name - # vmlinux is a special that is only used to resolve symbols - if($obj =~ /vmlinux/) { - $tgtname = "vmlinux"; - } else { - ($tgtname) = $obj =~ m-(/lib/modules/.*)$-; - } - - warn "MODULE = $tgtname\n" if $verbose; - - # get a list of symbols - @output=`nm $obj`; - $ksymtab=grep m/ __ksymtab/, @output; - - # gather the exported symbols - if($ksymtab){ - # explicitly exported - foreach ( @output ) { - / __ksymtab_(.*)$/ and do { - warn "sym = $1\n" if $verbose; - $exp->{$1} = $tgtname; - }; - } - } else { - # exporting all symbols - foreach ( @output) { - / [ABCDGRST] (.*)$/ and do { - warn "syma = $1\n" if $verbose; - $exp->{$1} = $tgtname; - }; - } - } - # gather the unresolved symbols - foreach ( @output ) { - !/ __this_module/ && / U (.*)$/ and do { - warn "und = $1\n" if $verbose; - push @{$dep->{$tgtname}}, $1; - }; - } -} - - -# reduce dependancies: remove unresolvable and resolved from vmlinux -# remove duplicates -foreach $module (keys %$dep) { - $mod->{$module} = {}; - foreach (@{$dep->{$module}}) { - if( $exp->{$_} ) { - warn "resolved symbol $_ in file $exp->{$_}\n" if $verbose; - next if $exp->{$_} =~ /vmlinux/; - $mod->{$module}{$exp->{$_}} = 1; - } else { - warn "unresolved symbol $_ in file $module\n"; - } - } -} - -# resolve the dependancies for each module -foreach $module ( keys %$mod ) { - print "$module:\t"; - @sorted = sort bydep keys %{$mod->{$module}}; - print join(" \\\n\t",@sorted); -# foreach $m (@sorted ) { -# print "\t$m\n"; -# } - print "\n\n"; -} - -sub bydep -{ - foreach my $f ( keys %{$mod->{$b}} ) { - if($f eq $a) { - return 1; - } - } - return -1; -} - - - -__END__ - -=head1 NAME - -depmod.pl - a cross platform script to generate kernel module dependency - lists which can then be used by modprobe. - -=head1 SYNOPSIS - -depmod.pl [OPTION]... [FILE]... - -Example: - - depmod.pl -F linux/System.map target/lib/modules - -=head1 DESCRIPTION - -The purpose of this script is to automagically generate a list of of kernel -module dependancies. This script produces dependancy lists that should be -identical to the depmod program from the modutils package. Unlike the depmod -binary, however, depmod.pl is designed to be run on your host system, not -on your target system. - -This script was written by David Schleef to be used in -conjunction with the BusyBox modprobe applet. - -=head1 OPTIONS - -=over 4 - -=item B<-h --help> - -This displays the help message. - -=item B<-b --basedir> - -The base directory uner which the target's modules will be found. This -defaults to the /lib/modules directory. - -=item B<-k --kernel> - -Kernel binary for the target. You must either supply a kernel binary -or a kernel symbol file (using the -F option). - -=item B<-F --kernelsyms> - -Kernel symbol file for the target. You must supply either a kernel symbol file -kernel binary for the target (using the -k option). - -=item B<-n --stdout> - -Write to stdout instead of modules.dep. This is currently hard coded... -kernel binary for the target (using the -k option). - -=item B<--verbose> - -Be verbose (not implemented) - -=back - -=head1 COPYRIGHT - -Copyright (c) 2001 David Schleef -Copyright (c) 2001 Erik Andersen -Copyright (c) 2001 Stuart Hughes -This program is free software; you can redistribute it and/or modify it -under the same terms as Perl itself. - -=head1 AUTHOR - -David Schleef - -=cut - -# $Id: depmod.pl,v 1.1 2001/07/30 19:32:03 andersen Exp $ - diff --git a/busybox/scripts/inittab b/busybox/scripts/inittab deleted file mode 100644 index 8e7e945b3..000000000 --- a/busybox/scripts/inittab +++ /dev/null @@ -1,86 +0,0 @@ -# /etc/inittab init(8) configuration for BusyBox -# -# Copyright (C) 1999 by Lineo, inc. Written by Erik Andersen -# , -# -# -# Note, BusyBox init doesn't support runlevels. The runlevels field is -# completely ignored by BusyBox init. If you want runlevels, use sysvinit. -# -# -# Format for each entry: ::: -# -# : WARNING: This field has a non-traditional meaning for BusyBox init! -# -# The id field is used by BusyBox init to specify the controlling tty for -# the specified process to run on. The contents of this field are -# appended to "/dev/" and used as-is. There is no need for this field to -# be unique, although if it isn't you may have strange results. If this -# field is left blank, it is completely ignored. Also note that if -# BusyBox detects that a serial console is in use, then all entries -# containing non-empty id fields will _not_ be run. BusyBox init does -# nothing with utmp. We don't need no stinkin' utmp. -# -# : The runlevels field is completely ignored. -# -# : Valid actions include: sysinit, respawn, askfirst, wait, once, -# ctrlaltdel, and shutdown. -# -# Note: askfirst acts just like respawn, but before running the specified -# process it displays the line "Please press Enter to activate this -# console." and then waits for the user to press enter before starting -# the specified process. -# -# Note: unrecognised actions (like initdefault) will cause init to emit -# an error message, and then go along with its business. -# -# : Specifies the process to be executed and it's command line. -# -# Note: BusyBox init works just fine without an inittab. If no inittab is -# found, it has the following default behavior: -# ::sysinit:/etc/init.d/rcS -# ::askfirst:/bin/sh -# ::ctrlaltdel:/sbin/reboot -# ::shutdown:/sbin/swapoff -a -# ::shutdown:/bin/umount -a -r -# if it detects that /dev/console is _not_ a serial console, it will -# also run: -# tty2::askfirst:/bin/sh -# tty3::askfirst:/bin/sh -# tty4::askfirst:/bin/sh -# -# Boot-time system configuration/initialization script. -# This is run first except when booting in single-user mode. -# -::sysinit:/etc/init.d/rcS - -# /bin/sh invocations on selected ttys -# -# Note below that we prefix the shell commands with a "-" to indicate to the -# shell that it is supposed to be a login shell. Normally this is handled by -# login, but since we are bypassing login in this case, BusyBox lets you do -# this yourself... -# -# Start an "askfirst" shell on the console (whatever that may be) -::askfirst:-/bin/sh -# Start an "askfirst" shell on /dev/tty2-4 -tty2::askfirst:-/bin/sh -tty3::askfirst:-/bin/sh -tty4::askfirst:-/bin/sh - -# /sbin/getty invocations for selected ttys -tty4::respawn:/sbin/getty 38400 tty5 -tty5::respawn:/sbin/getty 38400 tty6 - -# Example of how to put a getty on a serial line (for a terminal) -#::respawn:/sbin/getty -L ttyS0 9600 vt100 -#::respawn:/sbin/getty -L ttyS1 9600 vt100 -# -# Example how to put a getty on a modem line. -#::respawn:/sbin/getty 57600 ttyS2 - -# Stuff to do before rebooting -::ctrlaltdel:/sbin/reboot -::shutdown:/bin/umount -a -r -::shutdown:/sbin/swapoff -a - diff --git a/busybox/scripts/mk2knr.pl b/busybox/scripts/mk2knr.pl deleted file mode 100755 index aaf4963b1..000000000 --- a/busybox/scripts/mk2knr.pl +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/perl -w -# -# @(#) mk2knr.pl - generates a perl script that converts lexemes to K&R-style -# -# How to use this script: -# - In the busybox directory type 'scripts/mk2knr.pl files-you-want-to-convert' -# - Review the 'convertme.pl' script generated and remove / edit any of the -# substitutions in there (please especially check for false positives) -# - Type './convertme.pl same-files-as-before' -# - Compile and see if it works -# -# BUGS: This script does not ignore strings inside comments or strings inside -# quotes (it probably should). - -# set this to something else if you want -$convertme = 'convertme.pl'; - -# internal-use variables (don't touch) -$convert = 0; -%converted = (); - -# if no files were specified, print usage -die "usage: $0 file.c | file.h\n" if scalar(@ARGV) == 0; - -# prepare the "convert me" file -open(CM, ">$convertme") or die "convertme.pl $!"; -print CM "#!/usr/bin/perl -p -i\n\n"; - -# process each file passed on the cmd line -while (<>) { - - # if the line says "getopt" in it anywhere, we don't want to muck with it - # because option lists tend to include strings like "cxtzvOf:" which get - # matched by the "check for mixed case" regexps below - next if /getopt/; - - # tokenize the string into just the variables - while (/([a-zA-Z_][a-zA-Z0-9_]*)/g) { - $var = $1; - - # ignore the word "BusyBox" - next if ($var =~ /BusyBox/); - - # this checks for javaStyle or szHungarianNotation - $convert++ if ($var =~ /^[a-z]+[A-Z][a-z]+/); - - # this checks for PascalStyle - $convert++ if ($var =~ /^[A-Z][a-z]+[A-Z][a-z]+/); - - # if we want to add more checks, we can add 'em here, but the above - # checks catch "just enough" and not too much, so prolly not. - - if ($convert) { - $convert = 0; - - # skip ahead if we've already dealt with this one - next if ($converted{$var}); - - # record that we've dealt with this var - $converted{$var} = 1; - - print CM "s/\\b$var\\b/"; # more to come in just a minute - - # change the first letter to lower-case - $var = lcfirst($var); - - # put underscores before all remaining upper-case letters - $var =~ s/([A-Z])/_$1/g; - - # now change the remaining characters to lower-case - $var = lc($var); - - print CM "$var/g;\n"; - } - } -} - -# tidy up and make the $convertme script executable -close(CM); -chmod 0755, $convertme; - -# print a helpful help message -print "Done. Scheduled name changes are in $convertme.\n"; -print "Please review/modify it and then type ./$convertme to do the search & replace.\n"; diff --git a/busybox/scripts/undeb b/busybox/scripts/undeb deleted file mode 100644 index a72e1e2ba..000000000 --- a/busybox/scripts/undeb +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh -# -# This should work with the GNU version of tar and gzip! -# This should work with the bash or ash shell! -# Requires the programs (ar, tar, gzip, and the pager more or less). -# -usage() { -echo "Usage: undeb -c package.deb " -echo " undeb -l package.deb " -echo " undeb -x package.deb /foo/boo " -exit -} - -deb=$2 - -exist() { -if [ "$deb" = "" ]; then -usage -elif [ ! -s "$deb" ]; then -echo "Can't find $deb!" -exit -fi -} - -if [ "$1" = "" ]; then -usage -elif [ "$1" = "-l" ]; then -exist -type more >/dev/null 2>&1 && pager=more -type less >/dev/null 2>&1 && pager=less -[ "$pager" = "" ] && echo "No pager found!" && exit -(ar -p $deb control.tar.gz | tar -xzO *control ; echo -e "\nPress enter to scroll, q to Quit!\n" ; ar -p $deb data.tar.gz | tar -tzv) | $pager -exit -elif [ "$1" = "-c" ]; then -exist -ar -p $deb control.tar.gz | tar -xzO *control -exit -elif [ "$1" = "-x" ]; then -exist -if [ "$3" = "" ]; then -usage -elif [ ! -d "$3" ]; then -echo "No such directory $3!" -exit -fi -ar -p $deb data.tar.gz | tar -xzvpf - -C $3 || exit -echo -echo "Extracted $deb to $3!" -exit -else -usage -fi diff --git a/busybox/scripts/unrpm b/busybox/scripts/unrpm deleted file mode 100644 index 376286a6f..000000000 --- a/busybox/scripts/unrpm +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh -# -# This should work with the GNU version of cpio and gzip! -# This should work with the bash or ash shell! -# Requires the programs (cpio, gzip, and the pager more or less). -# -usage() { -echo "Usage: unrpm -l package.rpm " -echo " unrpm -x package.rpm /foo/boo " -exit -} - -rpm=$2 - -exist() { -if [ "$rpm" = "" ]; then -usage -elif [ ! -s "$rpm" ]; then -echo "Can't find $rpm!" -exit -fi -} - -if [ "$1" = "" ]; then -usage -elif [ "$1" = "-l" ]; then -exist -type more >/dev/null 2>&1 && pager=more -type less >/dev/null 2>&1 && pager=less -[ "$pager" = "" ] && echo "No pager found!" && exit -(echo -e "\nPress enter to scroll, q to Quit!\n" ; rpm2cpio $rpm | cpio -tv --quiet) | $pager -exit -elif [ "$1" = "-x" ]; then -exist -if [ "$3" = "" ]; then -usage -elif [ ! -d "$3" ]; then -echo "No such directory $3!" -exit -fi -rpm2cpio $rpm | (umask 0 ; cd $3 ; cpio -idmuv) || exit -echo -echo "Extracted $rpm to $3!" -exit -else -usage -fi diff --git a/busybox/sed.c b/busybox/sed.c deleted file mode 100644 index 709fb13a8..000000000 --- a/busybox/sed.c +++ /dev/null @@ -1,850 +0,0 @@ -/* - * sed.c - very minimalist version of sed - * - * 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 - * - */ - -/* - Supported features and commands in this version of sed: - - - comments ('#') - - address matching: num|/matchstr/[,num|/matchstr/|$]command - - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags) - - edit commands: (a)ppend, (i)nsert, (c)hange - - file commands: (r)ead - - backreferences in substitution expressions (\1, \2...\9) - - (Note: Specifying an address (range) to match is *optional*; commands - default to the whole pattern space if no specific address match was - requested.) - - Unsupported features: - - - transliteration (y/source-chars/dest-chars/) (use 'tr') - - no pattern space hold space storing / swapping (x, etc.) - - no labels / branching (: label, b, t, and friends) - - and lots, lots more. -*/ - -#include -#include /* for getopt() */ -#include -#include /* for strdup() */ -#include -#include /* for isspace() */ -#include -#include "busybox.h" - -/* externs */ -extern void xregcomp(regex_t *preg, const char *regex, int cflags); -extern int optind; /* in unistd.h */ -extern char *optarg; /* ditto */ - -/* options */ -static int be_quiet = 0; - - -struct sed_cmd { - - - /* GENERAL FIELDS */ - char delimiter; /* The delimiter used to separate regexps */ - - /* address storage */ - int beg_line; /* 'sed 1p' 0 == no begining line, apply commands to all lines */ - int end_line; /* 'sed 1,3p' 0 == no end line, use only beginning. -1 == $ */ - regex_t *beg_match; /* sed -e '/match/cmd' */ - regex_t *end_match; /* sed -e '/match/,/end_match/cmd' */ - - /* the command */ - char cmd; /* p,d,s (add more at your leisure :-) */ - - - /* SUBSTITUTION COMMAND SPECIFIC FIELDS */ - - /* sed -e 's/sub_match/replace/' */ - regex_t *sub_match; - char *replace; - unsigned int num_backrefs:4; /* how many back references (\1..\9) */ - /* Note: GNU/POSIX sed does not save more than nine backrefs, so - * we only use 4 bits to hold the number */ - unsigned int sub_g:1; /* sed -e 's/foo/bar/g' (global) */ - unsigned int sub_p:2; /* sed -e 's/foo/bar/p' (print substitution) */ - - - /* EDIT COMMAND (a,i,c) SPEICIFIC FIELDS */ - - char *editline; - - - /* FILE COMMAND (r) SPEICIFIC FIELDS */ - - char *filename; -}; - -/* globals */ -static struct sed_cmd *sed_cmds = NULL; /* growable arrary holding a sequence of sed cmds */ -static int ncmds = 0; /* number of sed commands */ - -/*static char *cur_file = NULL;*/ /* file currently being processed XXX: do I need this? */ - -#ifdef BB_FEATURE_CLEAN_UP -static void destroy_cmd_strs() -{ - if (sed_cmds == NULL) - return; - - /* destroy all the elements in the array */ - while (--ncmds >= 0) { - - if (sed_cmds[ncmds].beg_match) { - regfree(sed_cmds[ncmds].beg_match); - free(sed_cmds[ncmds].beg_match); - } - if (sed_cmds[ncmds].end_match) { - regfree(sed_cmds[ncmds].end_match); - free(sed_cmds[ncmds].end_match); - } - if (sed_cmds[ncmds].sub_match) { - regfree(sed_cmds[ncmds].sub_match); - free(sed_cmds[ncmds].sub_match); - } - if (sed_cmds[ncmds].replace) - free(sed_cmds[ncmds].replace); - } - - /* destroy the array */ - free(sed_cmds); - sed_cmds = NULL; -} -#endif - - -/* - * index_of_next_unescaped_regexp_delim - walks left to right through a string - * beginning at a specified index and returns the index of the next regular - * expression delimiter (typically a forward * slash ('/')) not preceeded by - * a backslash ('\'). - */ -static int index_of_next_unescaped_regexp_delim(struct sed_cmd *sed_cmd, const char *str, int idx) -{ - int bracket = -1; - int escaped = 0; - - for ( ; str[idx]; idx++) { - if (bracket != -1) { - if (str[idx] == ']' && !(bracket == idx - 1 || - (bracket == idx - 2 && str[idx-1] == '^'))) - bracket = -1; - } else if (escaped) - escaped = 0; - else if (str[idx] == '\\') - escaped = 1; - else if (str[idx] == '[') - bracket = idx; - else if (str[idx] == sed_cmd->delimiter) - return idx; - } - - /* if we make it to here, we've hit the end of the string */ - return -1; -} - -/* - * returns the index in the string just past where the address ends. - */ -static int get_address(struct sed_cmd *sed_cmd, const char *str, int *linenum, regex_t **regex) -{ - char *my_str = strdup(str); - int idx = 0; - char olddelimiter; - olddelimiter = sed_cmd->delimiter; - sed_cmd->delimiter = '/'; - - if (isdigit(my_str[idx])) { - do { - idx++; - } while (isdigit(my_str[idx])); - my_str[idx] = 0; - *linenum = atoi(my_str); - } - else if (my_str[idx] == '$') { - *linenum = -1; - idx++; - } - else if (my_str[idx] == '/') { - idx = index_of_next_unescaped_regexp_delim(sed_cmd, my_str, ++idx); - if (idx == -1) - error_msg_and_die("unterminated match expression"); - my_str[idx] = '\0'; - *regex = (regex_t *)xmalloc(sizeof(regex_t)); - xregcomp(*regex, my_str+1, REG_NEWLINE); - idx++; /* so it points to the next character after the last '/' */ - } - else { - error_msg("get_address: no address found in string\n" - "\t(you probably didn't check the string you passed me)"); - idx = -1; - } - - free(my_str); - sed_cmd->delimiter = olddelimiter; - return idx; -} - -static int parse_subst_cmd(struct sed_cmd *sed_cmd, const char *substr) -{ - int oldidx, cflags = REG_NEWLINE; - char *match; - int idx = 0; - int j; - - /* - * the string that gets passed to this function should look like this: - * s/match/replace/gIp - * || | ||| - * mandatory optional - * - * (all three of the '/' slashes are mandatory) - */ - - /* verify that the 's' is followed by something. That something - * (typically a 'slash') is now our regexp delimiter... */ - if (!substr[++idx]) - error_msg_and_die("bad format in substitution expression"); - else - sed_cmd->delimiter=substr[idx]; - - /* save the match string */ - oldidx = idx+1; - idx = index_of_next_unescaped_regexp_delim(sed_cmd, substr, ++idx); - if (idx == -1) - error_msg_and_die("bad format in substitution expression"); - match = xstrndup(substr + oldidx, idx - oldidx); - - /* determine the number of back references in the match string */ - /* Note: we compute this here rather than in the do_subst_command() - * function to save processor time, at the expense of a little more memory - * (4 bits) per sed_cmd */ - - /* sed_cmd->num_backrefs = 0; */ /* XXX: not needed? --apparently not */ - for (j = 0; match[j]; j++) { - /* GNU/POSIX sed does not save more than nine backrefs */ - if (match[j] == '\\' && match[j+1] == '(' && sed_cmd->num_backrefs <= 9) - sed_cmd->num_backrefs++; - } - - /* save the replacement string */ - oldidx = idx+1; - idx = index_of_next_unescaped_regexp_delim(sed_cmd, substr, ++idx); - if (idx == -1) - error_msg_and_die("bad format in substitution expression"); - sed_cmd->replace = xstrndup(substr + oldidx, idx - oldidx); - - /* process the flags */ - while (substr[++idx]) { - switch (substr[idx]) { - case 'g': - sed_cmd->sub_g = 1; - break; - case 'I': - cflags |= REG_ICASE; - break; - case 'p': - sed_cmd->sub_p = 1; - break; - default: - /* any whitespace or semicolon trailing after a s/// is ok */ - if (strchr("; \t\v\n\r", substr[idx])) - goto out; - /* else */ - error_msg_and_die("bad option in substitution expression"); - } - } - -out: - /* compile the match string into a regex */ - sed_cmd->sub_match = (regex_t *)xmalloc(sizeof(regex_t)); - xregcomp(sed_cmd->sub_match, match, cflags); - free(match); - - return idx; -} - -static int parse_edit_cmd(struct sed_cmd *sed_cmd, const char *editstr) -{ - int idx = 0; - int slashes_eaten = 0; - char *ptr; /* shorthand */ - - /* - * the string that gets passed to this function should look like this: - * - * need one of these - * | - * | this backslash (immediately following the edit command) is mandatory - * | | - * [aic]\ - * TEXT1\ - * TEXT2\ - * TEXTN - * - * as soon as we hit a TEXT line that has no trailing '\', we're done. - * this means a command like: - * - * i\ - * INSERTME - * - * is a-ok. - * - */ - - if (editstr[1] != '\\' && (editstr[2] != '\n' || editstr[2] != '\r')) - error_msg_and_die("bad format in edit expression"); - - /* store the edit line text */ - /* make editline big enough to accomodate the extra '\n' we will tack on - * to the end */ - sed_cmd->editline = xmalloc(strlen(&editstr[3]) + 2); - strcpy(sed_cmd->editline, &editstr[3]); - ptr = sed_cmd->editline; - - /* now we need to go through * and: s/\\[\r\n]$/\n/g on the edit line */ - while (ptr[idx]) { - while (ptr[idx] != '\\' || (ptr[idx+1] != '\n' && ptr[idx+1] != '\r')) { - idx++; - if (!ptr[idx]) { - goto out; - } - } - /* move the newline over the '\' before it (effectively eats the '\') */ - memmove(&ptr[idx], &ptr[idx+1], strlen(&ptr[idx+1])); - ptr[strlen(ptr)-1] = 0; - slashes_eaten++; - /* substitue \r for \n if needed */ - if (ptr[idx] == '\r') - ptr[idx] = '\n'; - } - -out: - /* this accounts for discrepancies between the modified string and the - * original string passed in to this function */ - idx += slashes_eaten; - - /* figure out if we need to add a newline */ - if (ptr[idx-1] != '\n') { - ptr[idx] = '\n'; - idx++; - } - - /* terminate string */ - ptr[idx]= 0; - /* adjust for opening 2 chars [aic]\ */ - idx += 2; - - return idx; -} - - -static int parse_file_cmd(struct sed_cmd *sed_cmd, const char *filecmdstr) -{ - int idx = 0; - int filenamelen = 0; - - /* - * the string that gets passed to this function should look like this: - * '[ ]filename' - * | | - * | a filename - * | - * optional whitespace - - * re: the file to be read, the GNU manual says the following: "Note that - * if filename cannot be read, it is treated as if it were an empty file, - * without any error indication." Thus, all of the following commands are - * perfectly leagal: - * - * sed -e '1r noexist' - * sed -e '1r ;' - * sed -e '1r' - */ - - /* the file command may be followed by whitespace; move past it. */ - while (isspace(filecmdstr[++idx])) - { ; } - - /* the first non-whitespace we get is a filename. the filename ends when we - * hit a normal sed command terminator or end of string */ - filenamelen = strcspn(&filecmdstr[idx], "; \n\r\t\v\0"); - sed_cmd->filename = xmalloc(filenamelen + 1); - safe_strncpy(sed_cmd->filename, &filecmdstr[idx], filenamelen + 1); - - return idx + filenamelen; -} - - -static char *parse_cmd_str(struct sed_cmd *sed_cmd, const char *cmdstr) -{ - int idx = 0; - - /* parse the command - * format is: [addr][,addr]cmd - * |----||-----||-| - * part1 part2 part3 - */ - - /* first part (if present) is an address: either a number or a /regex/ */ - if (isdigit(cmdstr[idx]) || cmdstr[idx] == '/') - idx = get_address(sed_cmd, cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); - - /* second part (if present) will begin with a comma */ - if (cmdstr[idx] == ',') - idx += get_address(sed_cmd, &cmdstr[++idx], &sed_cmd->end_line, &sed_cmd->end_match); - - /* last part (mandatory) will be a command */ - if (cmdstr[idx] == '\0') - error_msg_and_die("missing command"); - sed_cmd->cmd = cmdstr[idx]; - - /* if it was a single-letter command that takes no arguments (such as 'p' - * or 'd') all we need to do is increment the index past that command */ - if (strchr("pd", cmdstr[idx])) { - idx++; - } - /* handle (s)ubstitution command */ - else if (sed_cmd->cmd == 's') { - idx += parse_subst_cmd(sed_cmd, &cmdstr[idx]); - } - /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ - else if (strchr("aic", sed_cmd->cmd)) { - if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c') - error_msg_and_die("only a beginning address can be specified for edit commands"); - idx += parse_edit_cmd(sed_cmd, &cmdstr[idx]); - } - /* handle file cmds: (r)ead */ - else if (sed_cmd->cmd == 'r') { - if (sed_cmd->end_line || sed_cmd->end_match) - error_msg_and_die("Command only uses one address"); - idx += parse_file_cmd(sed_cmd, &cmdstr[idx]); - } - else { - error_msg_and_die("invalid command"); - } - - /* give back whatever's left over */ - return (char *)&cmdstr[idx]; -} - -static void add_cmd_str(const char *cmdstr) -{ - char *mystr = (char *)cmdstr; - - do { - - /* trim leading whitespace and semicolons */ - memmove(mystr, &mystr[strspn(mystr, "; \n\r\t\v")], strlen(mystr)); - /* if we ate the whole thing, that means there was just trailing - * whitespace or a final / no-op semicolon. either way, get out */ - if (strlen(mystr) == 0) - return; - /* if this is a comment, jump past it and keep going */ - if (mystr[0] == '#') { - mystr = strpbrk(mystr, ";\n\r"); - continue; - } - /* grow the array */ - sed_cmds = xrealloc(sed_cmds, sizeof(struct sed_cmd) * (++ncmds)); - /* zero new element */ - memset(&sed_cmds[ncmds-1], 0, sizeof(struct sed_cmd)); - /* load command string into new array element, get remainder */ - mystr = parse_cmd_str(&sed_cmds[ncmds-1], mystr); - - } while (mystr && strlen(mystr)); -} - - -static void load_cmd_file(char *filename) -{ - FILE *cmdfile; - char *line; - char *nextline; - - cmdfile = xfopen(filename, "r"); - - while ((line = get_line_from_file(cmdfile)) != NULL) { - /* if a line ends with '\' it needs the next line appended to it */ - while (line[strlen(line)-2] == '\\' && - (nextline = get_line_from_file(cmdfile)) != NULL) { - line = xrealloc(line, strlen(line) + strlen(nextline) + 1); - strcat(line, nextline); - free(nextline); - } - /* eat trailing newline (if any) --if I don't do this, edit commands - * (aic) will print an extra newline */ - chomp(line); - add_cmd_str(line); - free(line); - } -} - -#define PIPE_MAGIC 0x7f -#define PIPE_GROW 64 -#define pipeputc(c) \ -{ if (pipeline[pipeline_idx] == PIPE_MAGIC) { \ - pipeline = xrealloc(pipeline, pipeline_len+PIPE_GROW); \ - memset(pipeline+pipeline_len, 0, PIPE_GROW); \ - pipeline_len += PIPE_GROW; \ - pipeline[pipeline_len-1] = PIPE_MAGIC; } \ - pipeline[pipeline_idx++] = (c); } - -static void print_subst_w_backrefs(const char *line, const char *replace, - regmatch_t *regmatch, char **pipeline_p, int *pipeline_idx_p, - int *pipeline_len_p, int matches) -{ - char *pipeline = *pipeline_p; - int pipeline_idx = *pipeline_idx_p; - int pipeline_len = *pipeline_len_p; - int i; - - /* go through the replacement string */ - for (i = 0; replace[i]; i++) { - /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */ - if (replace[i] == '\\' && isdigit(replace[i+1])) { - int j; - char tmpstr[2]; - int backref; - ++i; /* i now indexes the backref number, instead of the leading slash */ - tmpstr[0] = replace[i]; - tmpstr[1] = 0; - backref = atoi(tmpstr); - /* print out the text held in regmatch[backref] */ - if (backref <= matches && regmatch[backref].rm_so != -1) - for (j = regmatch[backref].rm_so; j < regmatch[backref].rm_eo; j++) - pipeputc(line[j]); - } - - /* if we find a backslash escaped character, print the character */ - else if (replace[i] == '\\') { - ++i; - pipeputc(replace[i]); - } - - /* if we find an unescaped '&' print out the whole matched text. - * fortunately, regmatch[0] contains the indicies to the whole matched - * expression (kinda seems like it was designed for just such a - * purpose...) */ - else if (replace[i] == '&' && replace[i-1] != '\\') { - int j; - for (j = regmatch[0].rm_so; j < regmatch[0].rm_eo; j++) - pipeputc(line[j]); - } - /* nothing special, just print this char of the replacement string to stdout */ - else - pipeputc(replace[i]); - } - *pipeline_p = pipeline; - *pipeline_idx_p = pipeline_idx; - *pipeline_len_p = pipeline_len; -} - -static int do_subst_command(const struct sed_cmd *sed_cmd, char **line) -{ - char *hackline = *line; - char *pipeline = 0; - int pipeline_idx = 0; - int pipeline_len = 0; - int altered = 0; - regmatch_t *regmatch = NULL; - - /* we only proceed if the substitution 'search' expression matches */ - if (regexec(sed_cmd->sub_match, hackline, 0, NULL, 0) == REG_NOMATCH) - return 0; - - /* whaddaya know, it matched. get the number of back references */ - regmatch = xmalloc(sizeof(regmatch_t) * (sed_cmd->num_backrefs+1)); - - /* allocate more PIPE_GROW bytes - if replaced string is larger than original */ - pipeline_len = strlen(hackline)+PIPE_GROW; - pipeline = xmalloc(pipeline_len); - memset(pipeline, 0, pipeline_len); - /* buffer magic */ - pipeline[pipeline_len-1] = PIPE_MAGIC; - - /* and now, as long as we've got a line to try matching and if we can match - * the search string, we make substitutions */ - while ((*hackline || !altered) && (regexec(sed_cmd->sub_match, hackline, - sed_cmd->num_backrefs+1, regmatch, 0) != REG_NOMATCH) ) { - int i; - - /* print everything before the match */ - for (i = 0; i < regmatch[0].rm_so; i++) - pipeputc(hackline[i]); - - /* then print the substitution string */ - print_subst_w_backrefs(hackline, sed_cmd->replace, regmatch, - &pipeline, &pipeline_idx, &pipeline_len, - sed_cmd->num_backrefs); - - /* advance past the match */ - hackline += regmatch[0].rm_eo; - /* flag that something has changed */ - altered++; - - /* if we're not doing this globally, get out now */ - if (!sed_cmd->sub_g) - break; - } - - for (; *hackline; hackline++) pipeputc(*hackline); - if (pipeline[pipeline_idx] == PIPE_MAGIC) pipeline[pipeline_idx] = 0; - - /* cleanup */ - free(regmatch); - - free(*line); - *line = pipeline; - return altered; -} - - -static void process_file(FILE *file) -{ - char *line = NULL; - static int linenum = 0; /* GNU sed does not restart counting lines at EOF */ - unsigned int still_in_range = 0; - int altered; - int i; - - /* go through every line in the file */ - while ((line = get_line_from_file(file)) != NULL) { - - chomp(line); - linenum++; - altered = 0; - - /* for every line, go through all the commands */ - for (i = 0; i < ncmds; i++) { - - - /* - * entry point into sedding... - */ - if ( - /* no range necessary */ - (sed_cmds[i].beg_line == 0 && sed_cmds[i].end_line == 0 && - sed_cmds[i].beg_match == NULL && - sed_cmds[i].end_match == NULL) || - /* this line number is the first address we're looking for */ - (sed_cmds[i].beg_line && (sed_cmds[i].beg_line == linenum)) || - /* this line matches our first address regex */ - (sed_cmds[i].beg_match && (regexec(sed_cmds[i].beg_match, line, 0, NULL, 0) == 0)) || - /* we are currently within the beginning & ending address range */ - still_in_range - ) { - - /* - * actual sedding - */ - switch (sed_cmds[i].cmd) { - - case 'p': - puts(line); - break; - - case 'd': - altered++; - break; - - case 's': - - /* - * Some special cases for 's' printing to make it compliant with - * GNU sed printing behavior (aka "The -n | s///p Matrix"): - * - * -n ONLY = never print anything regardless of any successful - * substitution - * - * s///p ONLY = always print successful substitutions, even if - * the line is going to be printed anyway (line will be printed - * twice). - * - * -n AND s///p = print ONLY a successful substitution ONE TIME; - * no other lines are printed - this is the reason why the 'p' - * flag exists in the first place. - */ - - /* if the user specified that they didn't want anything printed (i.e., a -n - * flag and no 'p' flag after the s///), then there's really no point doing - * anything here. */ - if (be_quiet && !sed_cmds[i].sub_p) - break; - - /* we print the line once, unless we were told to be quiet */ - if (!be_quiet) - altered |= do_subst_command(&sed_cmds[i], &line); - - /* we also print the line if we were given the 'p' flag - * (this is quite possibly the second printing) */ - if (sed_cmds[i].sub_p) - altered |= do_subst_command(&sed_cmds[i], &line); - if (altered && (i+1 >= ncmds || sed_cmds[i+1].cmd != 's')) - puts(line); - - break; - - case 'a': - puts(line); - fputs(sed_cmds[i].editline, stdout); - altered++; - break; - - case 'i': - fputs(sed_cmds[i].editline, stdout); - break; - - case 'c': - /* single-address case */ - if (sed_cmds[i].end_match == NULL && sed_cmds[i].end_line == 0) { - fputs(sed_cmds[i].editline, stdout); - } - /* multi-address case */ - else { - /* matching text */ - if (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0)) - fputs(sed_cmds[i].editline, stdout); - /* matching line numbers */ - if (sed_cmds[i].end_line > 0 && sed_cmds[i].end_line == linenum) - fputs(sed_cmds[i].editline, stdout); - } - altered++; - - break; - - case 'r': { - FILE *outfile; - puts(line); - outfile = fopen(sed_cmds[i].filename, "r"); - if (outfile) - print_file(outfile); - /* else if we couldn't open the output file, - * no biggie, just don't print anything */ - altered++; - } - break; - } - - /* - * exit point from sedding... - */ - if ( - /* this is a single-address command or... */ - (sed_cmds[i].end_line == 0 && sed_cmds[i].end_match == NULL) || ( - /* we were in the middle of our address range (this - * isn't the first time through) and.. */ - (still_in_range == 1) && ( - /* this line number is the last address we're looking for or... */ - (sed_cmds[i].end_line && (sed_cmds[i].end_line == linenum)) || - /* this line matches our last address regex */ - (sed_cmds[i].end_match && (regexec(sed_cmds[i].end_match, line, 0, NULL, 0) == 0)) - ) - ) - ) { - /* we're out of our address range */ - still_in_range = 0; - } - - /* didn't hit the exit? then we're still in the middle of an address range */ - else { - still_in_range = 1; - } - } - } - - /* we will print the line unless we were told to be quiet or if the - * line was altered (via a 'd'elete or 's'ubstitution), in which case - * the altered line was already printed */ - if (!be_quiet && !altered) - puts(line); - - free(line); - } -} - -extern int sed_main(int argc, char **argv) -{ - int opt; - -#ifdef BB_FEATURE_CLEAN_UP - /* destroy command strings on exit */ - if (atexit(destroy_cmd_strs) == -1) - perror_msg_and_die("atexit"); -#endif - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "ne:f:")) > 0) { - switch (opt) { - case 'n': - be_quiet++; - break; - case 'e': - add_cmd_str(optarg); - break; - case 'f': - load_cmd_file(optarg); - break; - default: - show_usage(); - } - } - - /* if we didn't get a pattern from a -e and no command file was specified, - * argv[optind] should be the pattern. no pattern, no worky */ - if (ncmds == 0) { - if (argv[optind] == NULL) - show_usage(); - else { - add_cmd_str(argv[optind]); - optind++; - } - } - - - /* 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)) { - process_file(stdin); - } - else { - int i; - FILE *file; - for (i = optind; i < argc; i++) { - file = fopen(argv[i], "r"); - if (file == NULL) { - perror_msg("%s", argv[i]); - } else { - process_file(file); - fclose(file); - } - } - } - - return 0; -} diff --git a/busybox/setkeycodes.c b/busybox/setkeycodes.c deleted file mode 100644 index c3c7e09aa..000000000 --- a/busybox/setkeycodes.c +++ /dev/null @@ -1,72 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * setkeycodes - * - * Copyright (C) 1994-1998 Andries E. Brouwer - * - * Adjusted for BusyBox 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 - * - */ - -#include -#include -#include -#include -#include "busybox.h" - - -/* From */ -struct kbkeycode { - unsigned int scancode, keycode; -}; -static const int KDSETKEYCODE = 0x4B4D; /* write kernel keycode table entry */ - -extern int -setkeycodes_main(int argc, char** argv) -{ - char *ep; - int fd, sc; - struct kbkeycode a; - - if (argc % 2 != 1 || argc < 2) { - show_usage(); - } - - fd = get_console_fd("/dev/console"); - - while (argc > 2) { - a.keycode = atoi(argv[2]); - a.scancode = sc = strtol(argv[1], &ep, 16); - if (*ep) { - error_msg_and_die("error reading SCANCODE: '%s'", argv[1]); - } - if (a.scancode > 127) { - a.scancode -= 0xe000; - a.scancode += 128; - } - if (a.scancode > 255 || a.keycode > 127) { - error_msg_and_die("SCANCODE or KEYCODE outside bounds"); - } - if (ioctl(fd,KDSETKEYCODE,&a)) { - perror("KDSETKEYCODE"); - error_msg_and_die("failed to set SCANCODE %x to KEYCODE %d", sc, a.keycode); - } - argc -= 2; - argv += 2; - } - return EXIT_SUCCESS; -} diff --git a/busybox/shell/ash.c b/busybox/shell/ash.c deleted file mode 100644 index c0d47559d..000000000 --- a/busybox/shell/ash.c +++ /dev/null @@ -1,12888 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * ash shell port for busybox - * - * Copyright (c) 1989, 1991, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * 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 - * - * This version of ash is adapted from the source in Debian's ash 0.3.8-5 - * package. - * - * Modified by Erik Andersen and - * Vladimir Oleynik to be used in busybox - * - * - * Original copyright notice is retained at the end of this file. - */ - - -/* These defines allow you to adjust the feature set to be compiled - * into the ash shell. As a rule, enabling these options will make - * ash get bigger... With all of these options off, ash adds about - * 60k to busybox on an x86 system.*/ - - -/* Enable job control. This allows you to run jobs in the background, - * which is great when ash is being used as an interactive shell, but - * it completely useless for is all you are doing is running scripts. - * This adds about 2.5k on an x86 system. */ -#undef JOBS - -/* This enables alias support in ash. If you want to support things - * like "alias ls='ls -l'" with ash, enable this. This is only useful - * when ash is used as an intractive shell. This adds about 1.5k */ -#define ASH_ALIAS - -/* If you need ash to act as a full Posix shell, with full math - * support, enable this. This adds a bit over 2k an x86 system. */ -//#undef ASH_MATH_SUPPORT -#define ASH_MATH_SUPPORT - -/* Getopts is used by shell procedures to parse positional parameters. - * You probably want to leave this disabled, and use the busybox getopt - * applet if you want to do this sort of thing. There are some scripts - * out there that use it, so if you need it, enable it. Most people will - * leave this disabled. This adds 1k on an x86 system. */ -#undef ASH_GETOPTS - -/* This allows you to override shell builtins and use whatever is on - * the filesystem. This is most useful when ash is acting as a - * standalone shell. Adds about 272 bytes. */ -#undef ASH_CMDCMD - - -/* Optimize size vs speed as size */ -#define ASH_OPTIMIZE_FOR_SIZE - -/* Enable this to compile in extra debugging noise. When debugging is - * on, debugging info will be written to $HOME/trace and a quit signal - * will generate a core dump. */ -#undef DEBUG - -/* These are here to work with glibc -- Don't change these... */ -#undef FNMATCH_BROKEN -#undef GLOB_BROKEN -#define IFS_BROKEN - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#if !defined(FNMATCH_BROKEN) -#include -#endif -#if !defined(GLOB_BROKEN) -#include -#endif - -#ifdef JOBS -#include -#endif - -#include "busybox.h" -#include "cmdedit.h" - -/* - * This file was generated by the mksyntax program. - */ - -/* Syntax classes */ -#define CWORD 0 /* character is nothing special */ -#define CNL 1 /* newline character */ -#define CBACK 2 /* a backslash character */ -#define CSQUOTE 3 /* single quote */ -#define CDQUOTE 4 /* double quote */ -#define CENDQUOTE 5 /* a terminating quote */ -#define CBQUOTE 6 /* backwards single quote */ -#define CVAR 7 /* a dollar sign */ -#define CENDVAR 8 /* a '}' character */ -#define CLP 9 /* a left paren in arithmetic */ -#define CRP 10 /* a right paren in arithmetic */ -#define CENDFILE 11 /* end of file */ -#define CCTL 12 /* like CWORD, except it must be escaped */ -#define CSPCL 13 /* these terminate a word */ -#define CIGN 14 /* character should be ignored */ - -/* Syntax classes for is_ functions */ -#define ISDIGIT 01 /* a digit */ -#define ISUPPER 02 /* an upper case letter */ -#define ISLOWER 04 /* a lower case letter */ -#define ISUNDER 010 /* an underscore */ -#define ISSPECL 020 /* the name of a special parameter */ - -#define SYNBASE 130 -#define PEOF -130 - -#define PEOA -129 - -#define TEOF 0 -#define TNL 1 -#define TSEMI 2 -#define TBACKGND 3 -#define TAND 4 -#define TOR 5 -#define TPIPE 6 -#define TLP 7 -#define TRP 8 -#define TENDCASE 9 -#define TENDBQUOTE 10 -#define TREDIR 11 -#define TWORD 12 -#define TASSIGN 13 -#define TNOT 14 -#define TCASE 15 -#define TDO 16 -#define TDONE 17 -#define TELIF 18 -#define TELSE 19 -#define TESAC 20 -#define TFI 21 -#define TFOR 22 -#define TIF 23 -#define TIN 24 -#define TTHEN 25 -#define TUNTIL 26 -#define TWHILE 27 -#define TBEGIN 28 -#define TEND 29 - - -#define BASESYNTAX (basesyntax + SYNBASE) -#define DQSYNTAX (dqsyntax + SYNBASE) -#define SQSYNTAX (sqsyntax + SYNBASE) -#define ARISYNTAX (arisyntax + SYNBASE) - -/* control characters in argument strings */ -#define CTLESC '\201' -#define CTLVAR '\202' -#define CTLENDVAR '\203' -#define CTLBACKQ '\204' -#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ -/* CTLBACKQ | CTLQUOTE == '\205' */ -#define CTLARI '\206' -#define CTLENDARI '\207' -#define CTLQUOTEMARK '\210' - -#define is_digit(c) ((c)>='0' && (c)<='9') -#define is_alpha(c) (((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c))) -#define is_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c)))) -#define is_in_name(c) (((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c)))) -#define is_special(c) ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT)) -#define digit_val(c) ((c) - '0') - - -#define _DIAGASSERT(x) - - - -#define S_DFL 1 /* default signal handling (SIG_DFL) */ -#define S_CATCH 2 /* signal is caught */ -#define S_IGN 3 /* signal is ignored (SIG_IGN) */ -#define S_HARD_IGN 4 /* signal is ignored permenantly */ -#define S_RESET 5 /* temporary - to reset a hard ignored sig */ - - -/* variable substitution byte (follows CTLVAR) */ -#define VSTYPE 0x0f /* type of variable substitution */ -#define VSNUL 0x10 /* colon--treat the empty string as unset */ -#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ - -/* values of VSTYPE field */ -#define VSNORMAL 0x1 /* normal variable: $var or ${var} */ -#define VSMINUS 0x2 /* ${var-text} */ -#define VSPLUS 0x3 /* ${var+text} */ -#define VSQUESTION 0x4 /* ${var?message} */ -#define VSASSIGN 0x5 /* ${var=text} */ -#define VSTRIMLEFT 0x6 /* ${var#pattern} */ -#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */ -#define VSTRIMRIGHT 0x8 /* ${var%pattern} */ -#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */ -#define VSLENGTH 0xa /* ${#var} */ - -/* flags passed to redirect */ -#define REDIR_PUSH 01 /* save previous values of file descriptors */ -#define REDIR_BACKQ 02 /* save the command output to pipe */ - -/* - * BSD setjmp saves the signal mask, which violates ANSI C and takes time, - * so we use _setjmp instead. - */ - -#if defined(BSD) -#define setjmp(jmploc) _setjmp(jmploc) -#define longjmp(jmploc, val) _longjmp(jmploc, val) -#endif - -/* - * Most machines require the value returned from malloc to be aligned - * in some way. The following macro will get this right on many machines. - */ - -#ifndef ALIGN -union align { - int i; - char *cp; -}; - -#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1)) -#endif - -#ifdef BB_LOCALE_SUPPORT -#include -static void change_lc_all(const char *value); -static void change_lc_ctype(const char *value); -#endif - -/* - * These macros allow the user to suspend the handling of interrupt signals - * over a period of time. This is similar to SIGHOLD to or sigblock, but - * much more efficient and portable. (But hacking the kernel is so much - * more fun than worrying about efficiency and portability. :-)) - */ - -static void onint (void); -static volatile int suppressint; -static volatile int intpending; - -#define INTOFF suppressint++ -#ifndef ASH_OPTIMIZE_FOR_SIZE -#define INTON { if (--suppressint == 0 && intpending) onint(); } -#define FORCEINTON {suppressint = 0; if (intpending) onint();} -#else -static void __inton (void); -static void forceinton (void); -#define INTON __inton() -#define FORCEINTON forceinton() -#endif - -#define CLEAR_PENDING_INT intpending = 0 -#define int_pending() intpending - - -typedef void *pointer; -#ifndef NULL -#define NULL (void *)0 -#endif - -static inline pointer ckmalloc (int sz) { return xmalloc(sz); } -static inline pointer ckrealloc(void *p, int sz) { return xrealloc(p, sz); } -static inline char * savestr (const char *s) { return xstrdup(s); } - -static pointer stalloc (int); -static void stunalloc (pointer); -static void ungrabstackstr (char *, char *); -static char * growstackstr(void); -static char * makestrspace(size_t newlen); -static char *sstrdup (const char *); - -/* - * Parse trees for commands are allocated in lifo order, so we use a stack - * to make this more efficient, and also to avoid all sorts of exception - * handling code to handle interrupts in the middle of a parse. - * - * The size 504 was chosen because the Ultrix malloc handles that size - * well. - */ - -#define MINSIZE 504 /* minimum size of a block */ - - -struct stack_block { - struct stack_block *prev; - char space[MINSIZE]; -}; - -static struct stack_block stackbase; -static struct stack_block *stackp = &stackbase; -static struct stackmark *markp; -static char *stacknxt = stackbase.space; -static int stacknleft = MINSIZE; - - -#define equal(s1, s2) (strcmp(s1, s2) == 0) - -#define stackblock() stacknxt -#define stackblocksize() stacknleft -#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize() - -#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c))) -#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(n); } -#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0')) - - -#define USTPUTC(c, p) (--sstrnleft, *p++ = (c)) -#define STUNPUTC(p) (++sstrnleft, --p) -#define STTOPC(p) p[-1] -#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount)) -#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft) - -#define ckfree(p) free((pointer)(p)) - - -#ifdef DEBUG -#define TRACE(param) trace param -static void trace (const char *, ...); -static void trargs (char **); -static void showtree (union node *); -static void trputc (int); -static void trputs (const char *); -static void opentrace (void); -#else -#define TRACE(param) -#endif - -#define NSEMI 0 -#define NCMD 1 -#define NPIPE 2 -#define NREDIR 3 -#define NBACKGND 4 -#define NSUBSHELL 5 -#define NAND 6 -#define NOR 7 -#define NIF 8 -#define NWHILE 9 -#define NUNTIL 10 -#define NFOR 11 -#define NCASE 12 -#define NCLIST 13 -#define NDEFUN 14 -#define NARG 15 -#define NTO 16 -#define NFROM 17 -#define NFROMTO 18 -#define NAPPEND 19 -#define NTOOV 20 -#define NTOFD 21 -#define NFROMFD 22 -#define NHERE 23 -#define NXHERE 24 -#define NNOT 25 - -/* - * expandarg() flags - */ -#define EXP_FULL 0x1 /* perform word splitting & file globbing */ -#define EXP_TILDE 0x2 /* do normal tilde expansion */ -#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ -#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ -#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ -#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */ - - -#define NOPTS 16 - -static char optet_vals[NOPTS]; - -static const char * const optlist[NOPTS] = { - "e" "errexit", - "f" "noglob", - "I" "ignoreeof", - "i" "interactive", - "m" "monitor", - "n" "noexec", - "s" "stdin", - "x" "xtrace", - "v" "verbose", - "V" "vi", - "E" "emacs", - "C" "noclobber", - "a" "allexport", - "b" "notify", - "u" "nounset", - "q" "quietprofile" -}; - -#define optent_name(optent) (optent+1) -#define optent_letter(optent) optent[0] -#define optent_val(optent) optet_vals[optent] - -#define eflag optent_val(0) -#define fflag optent_val(1) -#define Iflag optent_val(2) -#define iflag optent_val(3) -#define mflag optent_val(4) -#define nflag optent_val(5) -#define sflag optent_val(6) -#define xflag optent_val(7) -#define vflag optent_val(8) -#define Vflag optent_val(9) -#define Eflag optent_val(10) -#define Cflag optent_val(11) -#define aflag optent_val(12) -#define bflag optent_val(13) -#define uflag optent_val(14) -#define qflag optent_val(15) - - -/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ -#define FORK_FG 0 -#define FORK_BG 1 -#define FORK_NOJOB 2 - - -struct nbinary { - int type; - union node *ch1; - union node *ch2; -}; - - -struct ncmd { - int type; - int backgnd; - union node *assign; - union node *args; - union node *redirect; -}; - - -struct npipe { - int type; - int backgnd; - struct nodelist *cmdlist; -}; - - -struct nredir { - int type; - union node *n; - union node *redirect; -}; - - -struct nif { - int type; - union node *test; - union node *ifpart; - union node *elsepart; -}; - - -struct nfor { - int type; - union node *args; - union node *body; - char *var; -}; - - -struct ncase { - int type; - union node *expr; - union node *cases; -}; - - -struct nclist { - int type; - union node *next; - union node *pattern; - union node *body; -}; - - -struct narg { - int type; - union node *next; - char *text; - struct nodelist *backquote; -}; - - -struct nfile { - int type; - union node *next; - int fd; - union node *fname; - char *expfname; -}; - - -struct ndup { - int type; - union node *next; - int fd; - int dupfd; - union node *vname; -}; - - -struct nhere { - int type; - union node *next; - int fd; - union node *doc; -}; - - -struct nnot { - int type; - union node *com; -}; - - -union node { - int type; - struct nbinary nbinary; - struct ncmd ncmd; - struct npipe npipe; - struct nredir nredir; - struct nif nif; - struct nfor nfor; - struct ncase ncase; - struct nclist nclist; - struct narg narg; - struct nfile nfile; - struct ndup ndup; - struct nhere nhere; - struct nnot nnot; -}; - - -struct nodelist { - struct nodelist *next; - union node *n; -}; - -struct backcmd { /* result of evalbackcmd */ - int fd; /* file descriptor to read from */ - char *buf; /* buffer */ - int nleft; /* number of chars in buffer */ - struct job *jp; /* job structure for command */ -}; - -struct cmdentry { - int cmdtype; - union param { - int index; - union node *func; - const struct builtincmd *cmd; - } u; -}; - -struct strlist { - struct strlist *next; - char *text; -}; - - -struct arglist { - struct strlist *list; - struct strlist **lastp; -}; - -struct strpush { - struct strpush *prev; /* preceding string on stack */ - char *prevstring; - int prevnleft; -#ifdef ASH_ALIAS - struct alias *ap; /* if push was associated with an alias */ -#endif - char *string; /* remember the string since it may change */ -}; - -struct parsefile { - struct parsefile *prev; /* preceding file on stack */ - int linno; /* current line */ - int fd; /* file descriptor (or -1 if string) */ - int nleft; /* number of chars left in this line */ - int lleft; /* number of chars left in this buffer */ - char *nextc; /* next char in buffer */ - char *buf; /* input buffer */ - struct strpush *strpush; /* for pushing strings at this level */ - struct strpush basestrpush; /* so pushing one is fast */ -}; - -struct stackmark { - struct stack_block *stackp; - char *stacknxt; - int stacknleft; - struct stackmark *marknext; -}; - -struct shparam { - int nparam; /* # of positional parameters (without $0) */ - unsigned char malloc; /* if parameter list dynamically allocated */ - char **p; /* parameter list */ - int optind; /* next parameter to be processed by getopts */ - int optoff; /* used by getopts */ -}; - -/* - * When commands are first encountered, they are entered in a hash table. - * This ensures that a full path search will not have to be done for them - * on each invocation. - * - * We should investigate converting to a linear search, even though that - * would make the command name "hash" a misnomer. - */ -#define CMDTABLESIZE 31 /* should be prime */ -#define ARB 1 /* actual size determined at run time */ - - - -struct tblentry { - struct tblentry *next; /* next entry in hash chain */ - union param param; /* definition of builtin function */ - short cmdtype; /* index identifying command */ - char rehash; /* if set, cd done since entry created */ - char cmdname[ARB]; /* name of command */ -}; - - -static struct tblentry *cmdtable[CMDTABLESIZE]; -static int builtinloc = -1; /* index in path of %builtin, or -1 */ -static int exerrno = 0; /* Last exec error */ - - -static void tryexec (char *, char **, char **); -static void printentry (struct tblentry *, int); -static void clearcmdentry (int); -static struct tblentry *cmdlookup (const char *, int); -static void delete_cmd_entry (void); -static int path_change (const char *, int *); - - -static void flushall (void); -static void out2fmt (const char *, ...) - __attribute__((__format__(__printf__,1,2))); -static int xwrite (int, const char *, int); - -static void outstr (const char *p, FILE *file) { fputs(p, file); } -static void out1str(const char *p) { outstr(p, stdout); } -static void out2str(const char *p) { outstr(p, stderr); } - -#ifndef ASH_OPTIMIZE_FOR_SIZE -#define out2c(c) putc((c), stderr) -#else -static void out2c(int c) { putc(c, stderr); } -#endif - -/* syntax table used when not in quotes */ -static const char basesyntax[257] = { - CENDFILE, CSPCL, CWORD, CCTL, - CCTL, CCTL, CCTL, CCTL, - CCTL, CCTL, CCTL, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CSPCL, - CNL, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CSPCL, CWORD, - CDQUOTE, CWORD, CVAR, CWORD, - CSPCL, CSQUOTE, CSPCL, CSPCL, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CSPCL, CSPCL, CWORD, - CSPCL, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CBACK, CWORD, - CWORD, CWORD, CBQUOTE, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CSPCL, CENDVAR, - CWORD -}; - -/* syntax table used when in double quotes */ -static const char dqsyntax[257] = { - CENDFILE, CIGN, CWORD, CCTL, - CCTL, CCTL, CCTL, CCTL, - CCTL, CCTL, CCTL, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CNL, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CCTL, - CENDQUOTE,CWORD, CVAR, CWORD, - CWORD, CWORD, CWORD, CWORD, - CCTL, CWORD, CWORD, CCTL, - CWORD, CCTL, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CCTL, CWORD, CWORD, CCTL, - CWORD, CCTL, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CCTL, CBACK, CCTL, - CWORD, CWORD, CBQUOTE, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CENDVAR, - CCTL -}; - -/* syntax table used when in single quotes */ -static const char sqsyntax[257] = { - CENDFILE, CIGN, CWORD, CCTL, - CCTL, CCTL, CCTL, CCTL, - CCTL, CCTL, CCTL, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CNL, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CCTL, - CWORD, CWORD, CWORD, CWORD, - CWORD, CENDQUOTE,CWORD, CWORD, - CCTL, CWORD, CWORD, CCTL, - CWORD, CCTL, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CCTL, CWORD, CWORD, CCTL, - CWORD, CCTL, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CCTL, CCTL, CCTL, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CCTL -}; - -/* syntax table used when in arithmetic */ -static const char arisyntax[257] = { - CENDFILE, CIGN, CWORD, CCTL, - CCTL, CCTL, CCTL, CCTL, - CCTL, CCTL, CCTL, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CNL, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CDQUOTE, CWORD, CVAR, CWORD, - CWORD, CSQUOTE, CLP, CRP, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CBACK, CWORD, - CWORD, CWORD, CBQUOTE, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CWORD, - CWORD, CWORD, CWORD, CENDVAR, - CWORD -}; - -/* character classification table */ -static const char is_type[257] = { - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, ISSPECL, - 0, ISSPECL, ISSPECL, 0, - 0, 0, 0, 0, - ISSPECL, 0, 0, ISSPECL, - 0, 0, ISDIGIT, ISDIGIT, - ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, - ISDIGIT, ISDIGIT, ISDIGIT, ISDIGIT, - 0, 0, 0, 0, - 0, ISSPECL, ISSPECL, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, ISUPPER, ISUPPER, ISUPPER, - ISUPPER, 0, 0, 0, - 0, ISUNDER, 0, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, ISLOWER, ISLOWER, ISLOWER, - ISLOWER, 0, 0, 0, - 0 -}; - -/* Array indicating which tokens mark the end of a list */ -static const char tokendlist[] = { - 1, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 1, - 0, - 0, - 0, - 1, -}; - -static const char *const tokname[] = { - "end of file", - "newline", - "\";\"", - "\"&\"", - "\"&&\"", - "\"||\"", - "\"|\"", - "\"(\"", - "\")\"", - "\";;\"", - "\"`\"", - "redirection", - "word", - "assignment", - "\"!\"", - "\"case\"", - "\"do\"", - "\"done\"", - "\"elif\"", - "\"else\"", - "\"esac\"", - "\"fi\"", - "\"for\"", - "\"if\"", - "\"in\"", - "\"then\"", - "\"until\"", - "\"while\"", - "\"{\"", - "\"}\"", -}; - -#define KWDOFFSET 14 - -static const char *const parsekwd[] = { - "!", - "case", - "do", - "done", - "elif", - "else", - "esac", - "fi", - "for", - "if", - "in", - "then", - "until", - "while", - "{", - "}" -}; - - -static int plinno = 1; /* input line number */ - -static int parselleft; /* copy of parsefile->lleft */ - -static struct parsefile basepf; /* top level input file */ -static char basebuf[BUFSIZ]; /* buffer for top level input file */ -static struct parsefile *parsefile = &basepf; /* current input file */ - -/* - * NEOF is returned by parsecmd when it encounters an end of file. It - * must be distinct from NULL, so we use the address of a variable that - * happens to be handy. - */ - -static int tokpushback; /* last token pushed back */ -#define NEOF ((union node *)&tokpushback) -static int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ - - -static void error (const char *, ...) __attribute__((__noreturn__)); -static void exerror (int, const char *, ...) __attribute__((__noreturn__)); -static void shellexec (char **, char **, const char *, int) - __attribute__((noreturn)); -static void exitshell (int) __attribute__((noreturn)); - -static int goodname(const char *); -static void ignoresig (int); -static void onsig (int); -static void dotrap (void); -static int decode_signal (const char *, int); - -static void shprocvar(void); -static void deletefuncs(void); -static void setparam (char **); -static void freeparam (volatile struct shparam *); - -/* reasons for skipping commands (see comment on breakcmd routine) */ -#define SKIPBREAK 1 -#define SKIPCONT 2 -#define SKIPFUNC 3 -#define SKIPFILE 4 - -/* values of cmdtype */ -#define CMDUNKNOWN -1 /* no entry in table for command */ -#define CMDNORMAL 0 /* command is an executable program */ -#define CMDBUILTIN 1 /* command is a shell builtin */ -#define CMDFUNCTION 2 /* command is a shell function */ - -#define DO_ERR 1 /* find_command prints errors */ -#define DO_ABS 2 /* find_command checks absolute paths */ -#define DO_NOFUN 4 /* find_command ignores functions */ -#define DO_BRUTE 8 /* find_command ignores hash table */ - -/* - * Shell variables. - */ - -/* flags */ -#define VEXPORT 0x01 /* variable is exported */ -#define VREADONLY 0x02 /* variable cannot be modified */ -#define VSTRFIXED 0x04 /* variable struct is staticly allocated */ -#define VTEXTFIXED 0x08 /* text is staticly allocated */ -#define VSTACK 0x10 /* text is allocated on the stack */ -#define VUNSET 0x20 /* the variable is not set */ -#define VNOFUNC 0x40 /* don't call the callback function */ - - -struct var { - struct var *next; /* next entry in hash list */ - int flags; /* flags are defined above */ - char *text; /* name=value */ - void (*func) (const char *); - /* function to be called when */ - /* the variable gets set/unset */ -}; - -struct localvar { - struct localvar *next; /* next local variable in list */ - struct var *vp; /* the variable that was made local */ - int flags; /* saved flags */ - char *text; /* saved text */ -}; - - -#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) -#define rmescapes(p) _rmescapes((p), 0) -static char *_rmescapes (char *, int); -#else -static void rmescapes (char *); -#endif - -static int casematch (union node *, const char *); -static void clearredir(void); -static void popstring(void); -static void readcmdfile (const char *); - -static int number (const char *); -static int is_number (const char *, int *num); -static char *single_quote (const char *); -static int nextopt (const char *); - -static void redirect (union node *, int); -static void popredir (void); -static int dup_as_newfd (int, int); - -static void changepath(const char *newval); -static void getoptsreset(const char *value); - - -static int parsenleft; /* copy of parsefile->nleft */ -static char *parsenextc; /* copy of parsefile->nextc */ -static int rootpid; /* pid of main shell */ -static int rootshell; /* true if we aren't a child of the main shell */ - -static const char spcstr[] = " "; -static const char snlfmt[] = "%s\n"; - -static int sstrnleft; -static int herefd = -1; - -static struct localvar *localvars; - -static struct var vifs; -static struct var vmail; -static struct var vmpath; -static struct var vpath; -static struct var vps1; -static struct var vps2; -static struct var voptind; -#ifdef BB_LOCALE_SUPPORT -static struct var vlc_all; -static struct var vlc_ctype; -#endif - -struct varinit { - struct var *var; - int flags; - const char *text; - void (*func) (const char *); -}; - -static const char defpathvar[] = - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; -#define defpath (defpathvar + 5) - -#ifdef IFS_BROKEN -static const char defifsvar[] = "IFS= \t\n"; -#define defifs (defifsvar + 4) -#else -static const char defifs[] = " \t\n"; -#endif - -static const struct varinit varinit[] = { -#ifdef IFS_BROKEN - { &vifs, VSTRFIXED|VTEXTFIXED, defifsvar, -#else - { &vifs, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS=", -#endif - NULL }, - { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=", - NULL }, - { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=", - NULL }, - { &vpath, VSTRFIXED|VTEXTFIXED, defpathvar, - changepath }, - /* - * vps1 depends on uid - */ - { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ", - NULL }, - { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1", - getoptsreset }, -#ifdef BB_LOCALE_SUPPORT - { &vlc_all, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL=", - change_lc_all }, - { &vlc_ctype, VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE=", - change_lc_ctype }, -#endif - { NULL, 0, NULL, - NULL } -}; - -#define VTABSIZE 39 - -static struct var *vartab[VTABSIZE]; - -/* - * The following macros access the values of the above variables. - * They have to skip over the name. They return the null string - * for unset variables. - */ - -#define ifsval() (vifs.text + 4) -#define ifsset() ((vifs.flags & VUNSET) == 0) -#define mailval() (vmail.text + 5) -#define mpathval() (vmpath.text + 9) -#define pathval() (vpath.text + 5) -#define ps1val() (vps1.text + 4) -#define ps2val() (vps2.text + 4) -#define optindval() (voptind.text + 7) - -#define mpathset() ((vmpath.flags & VUNSET) == 0) - -static void initvar (void); -static void setvar (const char *, const char *, int); -static void setvareq (char *, int); -static void listsetvar (struct strlist *); -static const char *lookupvar (const char *); -static const char *bltinlookup (const char *); -static char **environment (void); -static int showvarscmd (int, char **); -static void mklocal (char *); -static void poplocalvars (void); -static int unsetvar (const char *); -static int varequal (const char *, const char *); - - -static char *arg0; /* value of $0 */ -static struct shparam shellparam; /* current positional parameters */ -static char **argptr; /* argument list for builtin commands */ -static char *optionarg; /* set by nextopt (like getopt) */ -static char *optptr; /* used by nextopt */ -static char *minusc; /* argument to -c option */ - - -#ifdef ASH_ALIAS - -#define ALIASINUSE 1 -#define ALIASDEAD 2 - -#define ATABSIZE 39 - -struct alias { - struct alias *next; - char *name; - char *val; - int flag; -}; - -static struct alias *atab[ATABSIZE]; - -static void setalias (char *, char *); -static struct alias **hashalias (const char *); -static struct alias *freealias (struct alias *); -static struct alias **__lookupalias (const char *); - -static void -setalias(name, val) - char *name, *val; -{ - struct alias *ap, **app; - - app = __lookupalias(name); - ap = *app; - INTOFF; - if (ap) { - if (!(ap->flag & ALIASINUSE)) { - ckfree(ap->val); - } - ap->val = savestr(val); - ap->flag &= ~ALIASDEAD; - } else { - /* not found */ - ap = ckmalloc(sizeof (struct alias)); - ap->name = savestr(name); - ap->val = savestr(val); - ap->flag = 0; - ap->next = 0; - *app = ap; - } - INTON; -} - -static int -unalias(char *name) -{ - struct alias **app; - - app = __lookupalias(name); - - if (*app) { - INTOFF; - *app = freealias(*app); - INTON; - return (0); - } - - return (1); -} - -static void -rmaliases(void) -{ - struct alias *ap, **app; - int i; - - INTOFF; - for (i = 0; i < ATABSIZE; i++) { - app = &atab[i]; - for (ap = *app; ap; ap = *app) { - *app = freealias(*app); - if (ap == *app) { - app = &ap->next; - } - } - } - INTON; -} - -static struct alias * -lookupalias(const char *name, int check) -{ - struct alias *ap = *__lookupalias(name); - - if (check && ap && (ap->flag & ALIASINUSE)) - return (NULL); - return (ap); -} - -static void -printalias(const struct alias *ap) { - char *p; - - p = single_quote(ap->val); - printf("alias %s=%s\n", ap->name, p); - stunalloc(p); -} - - -/* - * TODO - sort output - */ -static int -aliascmd(int argc, char **argv) -{ - char *n, *v; - int ret = 0; - struct alias *ap; - - if (argc == 1) { - int i; - - for (i = 0; i < ATABSIZE; i++) - for (ap = atab[i]; ap; ap = ap->next) { - printalias(ap); - } - return (0); - } - while ((n = *++argv) != NULL) { - if ((v = strchr(n+1, '=')) == NULL) { /* n+1: funny ksh stuff */ - if ((ap = *__lookupalias(n)) == NULL) { - out2fmt("%s: %s not found\n", "alias", n); - ret = 1; - } else - printalias(ap); - } - else { - *v++ = '\0'; - setalias(n, v); - } - } - - return (ret); -} - -static int -unaliascmd(int argc, char **argv) -{ - int i; - - while ((i = nextopt("a")) != '\0') { - if (i == 'a') { - rmaliases(); - return (0); - } - } - for (i = 0; *argptr; argptr++) { - if (unalias(*argptr)) { - out2fmt("%s: %s not found\n", "unalias", *argptr); - i = 1; - } - } - - return (i); -} - -static struct alias ** -hashalias(p) - const char *p; - { - unsigned int hashval; - - hashval = *p << 4; - while (*p) - hashval+= *p++; - return &atab[hashval % ATABSIZE]; -} - -static struct alias * -freealias(struct alias *ap) { - struct alias *next; - - if (ap->flag & ALIASINUSE) { - ap->flag |= ALIASDEAD; - return ap; - } - - next = ap->next; - ckfree(ap->name); - ckfree(ap->val); - ckfree(ap); - return next; -} - - -static struct alias ** -__lookupalias(const char *name) { - struct alias **app = hashalias(name); - - for (; *app; app = &(*app)->next) { - if (equal(name, (*app)->name)) { - break; - } - } - - return app; -} -#endif - -#ifdef ASH_MATH_SUPPORT -/* The generated file arith.c has been replaced with a custom hand - * written implementation written by Aaron Lehmann . - * This is now part of libbb, so that it can be used by all the shells - * in busybox. */ -#define ARITH_NUM 257 -#define ARITH_LPAREN 258 -#define ARITH_RPAREN 259 -#define ARITH_OR 260 -#define ARITH_AND 261 -#define ARITH_BOR 262 -#define ARITH_BXOR 263 -#define ARITH_BAND 264 -#define ARITH_EQ 265 -#define ARITH_NE 266 -#define ARITH_LT 267 -#define ARITH_GT 268 -#define ARITH_GE 269 -#define ARITH_LE 270 -#define ARITH_LSHIFT 271 -#define ARITH_RSHIFT 272 -#define ARITH_ADD 273 -#define ARITH_SUB 274 -#define ARITH_MUL 275 -#define ARITH_DIV 276 -#define ARITH_REM 277 -#define ARITH_UNARYMINUS 278 -#define ARITH_UNARYPLUS 279 -#define ARITH_NOT 280 -#define ARITH_BNOT 281 - -static void expari (int); -#endif - -static char *trap[NSIG]; /* trap handler commands */ -static char sigmode[NSIG - 1]; /* current value of signal */ -static char gotsig[NSIG - 1]; /* indicates specified signal received */ -static int pendingsigs; /* indicates some signal received */ - -/* - * This file was generated by the mkbuiltins program. - */ - -#ifdef JOBS -static int bgcmd (int, char **); -static int fgcmd (int, char **); -static int killcmd (int, char **); -#endif -static int bltincmd (int, char **); -static int cdcmd (int, char **); -static int breakcmd (int, char **); -#ifdef ASH_CMDCMD -static int commandcmd (int, char **); -#endif -static int dotcmd (int, char **); -static int evalcmd (int, char **); -static int execcmd (int, char **); -static int exitcmd (int, char **); -static int exportcmd (int, char **); -static int histcmd (int, char **); -static int hashcmd (int, char **); -static int helpcmd (int, char **); -static int jobscmd (int, char **); -static int localcmd (int, char **); -#ifndef BB_PWD -static int pwdcmd (int, char **); -#endif -static int readcmd (int, char **); -static int returncmd (int, char **); -static int setcmd (int, char **); -static int setvarcmd (int, char **); -static int shiftcmd (int, char **); -static int trapcmd (int, char **); -static int umaskcmd (int, char **); -#ifdef ASH_ALIAS -static int aliascmd (int, char **); -static int unaliascmd (int, char **); -#endif -static int unsetcmd (int, char **); -static int waitcmd (int, char **); -static int ulimitcmd (int, char **); -static int timescmd (int, char **); -#ifdef ASH_MATH_SUPPORT -static int letcmd (int, char **); -#endif -static int typecmd (int, char **); -#ifdef ASH_GETOPTS -static int getoptscmd (int, char **); -#endif - -#ifndef BB_TRUE_FALSE -static int true_main (int, char **); -static int false_main (int, char **); -#endif - -static void setpwd (const char *, int); - - -#define BUILTIN_NOSPEC "0" -#define BUILTIN_SPECIAL "1" -#define BUILTIN_REGULAR "2" -#define BUILTIN_ASSIGN "4" -#define BUILTIN_SPEC_ASSG "5" -#define BUILTIN_REG_ASSG "6" - -#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1) -#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2) -#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4) - -struct builtincmd { - const char *name; - int (*const builtinfunc) (int, char **); - //unsigned flags; -}; - - -/* It is CRUCIAL that this listing be kept in ascii order, otherwise - * the binary search in find_builtin() will stop working. If you value - * your kneecaps, you'll be sure to *make sure* that any changes made - * to this array result in the listing remaining in ascii order. You - * have been warned. - */ -static const struct builtincmd builtincmds[] = { - { BUILTIN_SPECIAL ".", dotcmd }, /* first, see declare DOTCMD */ - { BUILTIN_SPECIAL ":", true_main }, -#ifdef ASH_ALIAS - { BUILTIN_REG_ASSG "alias", aliascmd }, -#endif -#ifdef JOBS - { BUILTIN_REGULAR "bg", bgcmd }, -#endif - { BUILTIN_SPECIAL "break", breakcmd }, - { BUILTIN_SPECIAL "builtin", bltincmd }, - { BUILTIN_REGULAR "cd", cdcmd }, - { BUILTIN_NOSPEC "chdir", cdcmd }, -#ifdef ASH_CMDCMD - { BUILTIN_REGULAR "command", commandcmd }, -#endif - { BUILTIN_SPECIAL "continue", breakcmd }, - { BUILTIN_SPECIAL "eval", evalcmd }, - { BUILTIN_SPECIAL "exec", execcmd }, - { BUILTIN_SPECIAL "exit", exitcmd }, - { BUILTIN_SPEC_ASSG "export", exportcmd }, - { BUILTIN_REGULAR "false", false_main }, - { BUILTIN_REGULAR "fc", histcmd }, -#ifdef JOBS - { BUILTIN_REGULAR "fg", fgcmd }, -#endif -#ifdef ASH_GETOPTS - { BUILTIN_REGULAR "getopts", getoptscmd }, -#endif - { BUILTIN_NOSPEC "hash", hashcmd }, - { BUILTIN_NOSPEC "help", helpcmd }, - { BUILTIN_REGULAR "jobs", jobscmd }, -#ifdef JOBS - { BUILTIN_REGULAR "kill", killcmd }, -#endif -#ifdef ASH_MATH_SUPPORT - { BUILTIN_REGULAR "let", letcmd }, -#endif - { BUILTIN_ASSIGN "local", localcmd }, -#ifndef BB_PWD - { BUILTIN_NOSPEC "pwd", pwdcmd }, -#endif - { BUILTIN_REGULAR "read", readcmd }, - { BUILTIN_SPEC_ASSG "readonly", exportcmd }, - { BUILTIN_SPECIAL "return", returncmd }, - { BUILTIN_SPECIAL "set", setcmd }, - { BUILTIN_NOSPEC "setvar", setvarcmd }, - { BUILTIN_SPECIAL "shift", shiftcmd }, - { BUILTIN_SPECIAL "times", timescmd }, - { BUILTIN_SPECIAL "trap", trapcmd }, - { BUILTIN_REGULAR "true", true_main }, - { BUILTIN_NOSPEC "type", typecmd }, - { BUILTIN_NOSPEC "ulimit", ulimitcmd }, - { BUILTIN_REGULAR "umask", umaskcmd }, -#ifdef ASH_ALIAS - { BUILTIN_REGULAR "unalias", unaliascmd }, -#endif - { BUILTIN_SPECIAL "unset", unsetcmd }, - { BUILTIN_REGULAR "wait", waitcmd }, -}; -#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) ) - -static const struct builtincmd *DOTCMD = &builtincmds[0]; -static struct builtincmd *BLTINCMD; -static struct builtincmd *EXECCMD; -static struct builtincmd *EVALCMD; - -/* states */ -#define JOBSTOPPED 1 /* all procs are stopped */ -#define JOBDONE 2 /* all procs are completed */ - -/* - * A job structure contains information about a job. A job is either a - * single process or a set of processes contained in a pipeline. In the - * latter case, pidlist will be non-NULL, and will point to a -1 terminated - * array of pids. - */ - -struct procstat { - pid_t pid; /* process id */ - int status; /* status flags (defined above) */ - char *cmd; /* text of command being run */ -}; - - -static int job_warning; /* user was warned about stopped jobs */ - -#ifdef JOBS -static void setjobctl(int enable); -#else -#define setjobctl(on) /* do nothing */ -#endif - - -struct job { - struct procstat ps0; /* status of process */ - struct procstat *ps; /* status or processes when more than one */ - short nprocs; /* number of processes */ - short pgrp; /* process group of this job */ - char state; /* true if job is finished */ - char used; /* true if this entry is in used */ - char changed; /* true if status has changed */ -#ifdef JOBS - char jobctl; /* job running under job control */ -#endif -}; - -static struct job *jobtab; /* array of jobs */ -static int njobs; /* size of array */ -static int backgndpid = -1; /* pid of last background process */ -#ifdef JOBS -static int initialpgrp; /* pgrp of shell on invocation */ -static int curjob; /* current job */ -static int jobctl; -#endif -static int intreceived; - -static struct job *makejob (const union node *, int); -static int forkshell (struct job *, const union node *, int); -static int waitforjob (struct job *); - -static int docd (char *, int); -static char *getcomponent (void); -static void updatepwd (const char *); -static void getpwd (void); - -static char *padvance (const char **, const char *); - -static char nullstr[1]; /* zero length string */ -static char *curdir = nullstr; /* current working directory */ -static char *cdcomppath; - -static int -cdcmd(argc, argv) - int argc; - char **argv; -{ - const char *dest; - const char *path; - char *p; - struct stat statb; - int print = 0; - - nextopt(nullstr); - if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL) - error("HOME not set"); - if (*dest == '\0') - dest = "."; - if (dest[0] == '-' && dest[1] == '\0') { - dest = bltinlookup("OLDPWD"); - if (!dest || !*dest) { - dest = curdir; - } - print = 1; - if (dest) - print = 1; - else - dest = "."; - } - if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL) - path = nullstr; - while ((p = padvance(&path, dest)) != NULL) { - if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { - if (!print) { - /* - * XXX - rethink - */ - if (p[0] == '.' && p[1] == '/' && p[2] != '\0') - p += 2; - print = strcmp(p, dest); - } - if (docd(p, print) >= 0) - return 0; - - } - } - error("can't cd to %s", dest); - /* NOTREACHED */ -} - - -/* - * Actually do the chdir. In an interactive shell, print the - * directory name if "print" is nonzero. - */ - -static int -docd(dest, print) - char *dest; - int print; -{ - char *p; - char *q; - char *component; - struct stat statb; - int first; - int badstat; - - TRACE(("docd(\"%s\", %d) called\n", dest, print)); - - /* - * Check each component of the path. If we find a symlink or - * something we can't stat, clear curdir to force a getcwd() - * next time we get the value of the current directory. - */ - badstat = 0; - cdcomppath = sstrdup(dest); - STARTSTACKSTR(p); - if (*dest == '/') { - STPUTC('/', p); - cdcomppath++; - } - first = 1; - while ((q = getcomponent()) != NULL) { - if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0')) - continue; - if (! first) - STPUTC('/', p); - first = 0; - component = q; - while (*q) - STPUTC(*q++, p); - if (equal(component, "..")) - continue; - STACKSTRNUL(p); - if ((lstat(stackblock(), &statb) < 0) - || (S_ISLNK(statb.st_mode))) { - /* print = 1; */ - badstat = 1; - break; - } - } - - INTOFF; - if (chdir(dest) < 0) { - INTON; - return -1; - } - updatepwd(badstat ? NULL : dest); - INTON; - if (print && iflag) - printf(snlfmt, curdir); - return 0; -} - - -/* - * Get the next component of the path name pointed to by cdcomppath. - * This routine overwrites the string pointed to by cdcomppath. - */ - -static char * -getcomponent() { - char *p; - char *start; - - if ((p = cdcomppath) == NULL) - return NULL; - start = cdcomppath; - while (*p != '/' && *p != '\0') - p++; - if (*p == '\0') { - cdcomppath = NULL; - } else { - *p++ = '\0'; - cdcomppath = p; - } - return start; -} - - - -/* - * Update curdir (the name of the current directory) in response to a - * cd command. We also call hashcd to let the routines in exec.c know - * that the current directory has changed. - */ - -static void hashcd (void); - -static void -updatepwd(const char *dir) -{ - char *new; - char *p; - size_t len; - - hashcd(); /* update command hash table */ - - /* - * If our argument is NULL, we don't know the current directory - * any more because we traversed a symbolic link or something - * we couldn't stat(). - */ - if (dir == NULL || curdir == nullstr) { - setpwd(0, 1); - return; - } - len = strlen(dir); - cdcomppath = sstrdup(dir); - STARTSTACKSTR(new); - if (*dir != '/') { - p = curdir; - while (*p) - STPUTC(*p++, new); - if (p[-1] == '/') - STUNPUTC(new); - } - while ((p = getcomponent()) != NULL) { - if (equal(p, "..")) { - while (new > stackblock() && (STUNPUTC(new), *new) != '/'); - } else if (*p != '\0' && ! equal(p, ".")) { - STPUTC('/', new); - while (*p) - STPUTC(*p++, new); - } - } - if (new == stackblock()) - STPUTC('/', new); - STACKSTRNUL(new); - setpwd(stackblock(), 1); -} - - -#ifndef BB_PWD -static int -pwdcmd(argc, argv) - int argc; - char **argv; -{ - printf(snlfmt, curdir); - return 0; -} -#endif - -/* - * Find out what the current directory is. If we already know the current - * directory, this routine returns immediately. - */ -static void -getpwd(void) -{ - curdir = xgetcwd(0); - if(curdir==0) - curdir = nullstr; -} - -static void -setpwd(const char *val, int setold) -{ - if (setold) { - setvar("OLDPWD", curdir, VEXPORT); - } - INTOFF; - if (curdir != nullstr) { - free(curdir); - curdir = nullstr; - } - if (!val) { - getpwd(); - } else { - curdir = savestr(val); - } - INTON; - setvar("PWD", curdir, VEXPORT); -} - -/* - * Errors and exceptions. - */ - -/* - * Code to handle exceptions in C. - */ - -/* - * We enclose jmp_buf in a structure so that we can declare pointers to - * jump locations. The global variable handler contains the location to - * jump to when an exception occurs, and the global variable exception - * contains a code identifying the exeception. To implement nested - * exception handlers, the user should save the value of handler on entry - * to an inner scope, set handler to point to a jmploc structure for the - * inner scope, and restore handler on exit from the scope. - */ - -struct jmploc { - jmp_buf loc; -}; - -/* exceptions */ -#define EXINT 0 /* SIGINT received */ -#define EXERROR 1 /* a generic error */ -#define EXSHELLPROC 2 /* execute a shell procedure */ -#define EXEXEC 3 /* command execution failed */ - -static struct jmploc *handler; -static int exception; - -static void exverror (int, const char *, va_list) - __attribute__((__noreturn__)); - -/* - * Called to raise an exception. Since C doesn't include exceptions, we - * just do a longjmp to the exception handler. The type of exception is - * stored in the global variable "exception". - */ - -static void exraise (int) __attribute__((__noreturn__)); - -static void -exraise(int e) -{ -#ifdef DEBUG - if (handler == NULL) - abort(); -#endif - flushall(); - exception = e; - longjmp(handler->loc, 1); -} - - -/* - * Called from trap.c when a SIGINT is received. (If the user specifies - * that SIGINT is to be trapped or ignored using the trap builtin, then - * this routine is not called.) Suppressint is nonzero when interrupts - * are held using the INTOFF macro. The call to _exit is necessary because - * there is a short period after a fork before the signal handlers are - * set to the appropriate value for the child. (The test for iflag is - * just defensive programming.) - */ - -static void -onint(void) { - sigset_t mysigset; - - if (suppressint) { - intpending++; - return; - } - intpending = 0; - sigemptyset(&mysigset); - sigprocmask(SIG_SETMASK, &mysigset, NULL); - if (rootshell && iflag) - exraise(EXINT); - else { - signal(SIGINT, SIG_DFL); - raise(SIGINT); - } - /* NOTREACHED */ -} - - -static char *commandname; /* currently executing command */ - -/* - * Exverror is called to raise the error exception. If the first argument - * is not NULL then error prints an error message using printf style - * formatting. It then raises the error exception. - */ -static void -exverror(int cond, const char *msg, va_list ap) -{ - CLEAR_PENDING_INT; - INTOFF; - -#ifdef DEBUG - if (msg) - TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid())); - else - TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid())); -#endif - if (msg) { - if (commandname) - out2fmt("%s: ", commandname); - vfprintf(stderr, msg, ap); - out2c('\n'); - } - exraise(cond); - /* NOTREACHED */ -} - - -static void -error(const char *msg, ...) -{ - va_list ap; - va_start(ap, msg); - exverror(EXERROR, msg, ap); - /* NOTREACHED */ - va_end(ap); -} - - -static void -exerror(int cond, const char *msg, ...) -{ - va_list ap; - va_start(ap, msg); - exverror(cond, msg, ap); - /* NOTREACHED */ - va_end(ap); -} - - - -/* - * Table of error messages. - */ - -struct errname { - short errcode; /* error number */ - char action; /* operation which encountered the error */ -}; - -/* - * Types of operations (passed to the errmsg routine). - */ - -#define E_OPEN 01 /* opening a file */ -#define E_CREAT 02 /* creating a file */ -#define E_EXEC 04 /* executing a program */ - -#define ALL (E_OPEN|E_CREAT|E_EXEC) - -static const struct errname errormsg[] = { - { EINTR, ALL }, - { EACCES, ALL }, - { EIO, ALL }, - { ENOENT, E_OPEN }, - { ENOENT, E_CREAT }, - { ENOENT, E_EXEC }, - { ENOTDIR, E_OPEN }, - { ENOTDIR, E_CREAT }, - { ENOTDIR, E_EXEC }, - { EISDIR, ALL }, - { EEXIST, E_CREAT }, -#ifdef EMFILE - { EMFILE, ALL }, -#endif - { ENFILE, ALL }, - { ENOSPC, ALL }, -#ifdef EDQUOT - { EDQUOT, ALL }, -#endif -#ifdef ENOSR - { ENOSR, ALL }, -#endif - { ENXIO, ALL }, - { EROFS, ALL }, - { ETXTBSY, ALL }, -#ifdef EAGAIN - { EAGAIN, E_EXEC }, -#endif - { ENOMEM, ALL }, -#ifdef ENOLINK - { ENOLINK, ALL }, -#endif -#ifdef EMULTIHOP - { EMULTIHOP, ALL }, -#endif -#ifdef ECOMM - { ECOMM, ALL }, -#endif -#ifdef ESTALE - { ESTALE, ALL }, -#endif -#ifdef ETIMEDOUT - { ETIMEDOUT, ALL }, -#endif -#ifdef ELOOP - { ELOOP, ALL }, -#endif - { E2BIG, E_EXEC }, -#ifdef ELIBACC - { ELIBACC, E_EXEC }, -#endif -}; - -#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname)) - -/* - * Return a string describing an error. The returned string may be a - * pointer to a static buffer that will be overwritten on the next call. - * Action describes the operation that got the error. - */ - -static const char * -errmsg(int e, int action) -{ - struct errname const *ep; - static char buf[12]; - - for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) { - if (ep->errcode == e && (ep->action & action) != 0) - return strerror(e); - } - - snprintf(buf, sizeof buf, "error %d", e); - return buf; -} - - -#ifdef ASH_OPTIMIZE_FOR_SIZE -static void -__inton() { - if (--suppressint == 0 && intpending) { - onint(); - } -} -static void forceinton (void) { - suppressint = 0; - if (intpending) - onint(); -} -#endif - -/* flags in argument to evaltree */ -#define EV_EXIT 01 /* exit after evaluating tree */ -#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ -#define EV_BACKCMD 04 /* command executing within back quotes */ - -static int evalskip; /* set if we are skipping commands */ -static int skipcount; /* number of levels to skip */ -static int loopnest; /* current loop nesting level */ -static int funcnest; /* depth of function calls */ - - -static struct strlist *cmdenviron; /* environment for builtin command */ -static int exitstatus; /* exit status of last command */ -static int oexitstatus; /* saved exit status */ - -static void evalsubshell (const union node *, int); -static void expredir (union node *); -static void prehash (union node *); -static void eprintlist (struct strlist *); - -static union node *parsecmd(int); -/* - * Called to reset things after an exception. - */ - -/* - * The eval commmand. - */ -static void evalstring (char *, int); - -static int -evalcmd(argc, argv) - int argc; - char **argv; -{ - char *p; - char *concat; - char **ap; - - if (argc > 1) { - p = argv[1]; - if (argc > 2) { - STARTSTACKSTR(concat); - ap = argv + 2; - for (;;) { - while (*p) - STPUTC(*p++, concat); - if ((p = *ap++) == NULL) - break; - STPUTC(' ', concat); - } - STPUTC('\0', concat); - p = grabstackstr(concat); - } - evalstring(p, EV_TESTED); - } - return exitstatus; -} - -/* - * Execute a command or commands contained in a string. - */ - -static void evaltree (union node *, int); -static void setinputstring (char *); -static void popfile (void); -static void setstackmark(struct stackmark *mark); -static void popstackmark(struct stackmark *mark); - - -static void -evalstring(char *s, int flag) -{ - union node *n; - struct stackmark smark; - - setstackmark(&smark); - setinputstring(s); - while ((n = parsecmd(0)) != NEOF) { - evaltree(n, flag); - popstackmark(&smark); - } - popfile(); - popstackmark(&smark); -} - -static struct builtincmd *find_builtin (const char *); -static void expandarg (union node *, struct arglist *, int); -static void calcsize (const union node *); -static union node *copynode (const union node *); - -/* - * Make a copy of a parse tree. - */ - -static int funcblocksize; /* size of structures in function */ -static int funcstringsize; /* size of strings in node */ -static pointer funcblock; /* block to allocate function from */ -static char *funcstring; /* block to allocate strings from */ - - -static inline union node * -copyfunc(union node *n) -{ - if (n == NULL) - return NULL; - funcblocksize = 0; - funcstringsize = 0; - calcsize(n); - funcblock = ckmalloc(funcblocksize + funcstringsize); - funcstring = (char *) funcblock + funcblocksize; - return copynode(n); -} - -/* - * Free a parse tree. - */ - -static void -freefunc(union node *n) -{ - if (n) - ckfree(n); -} - - -/* - * Add a new command entry, replacing any existing command entry for - * the same name. - */ - -static inline void -addcmdentry(char *name, struct cmdentry *entry) -{ - struct tblentry *cmdp; - - INTOFF; - cmdp = cmdlookup(name, 1); - if (cmdp->cmdtype == CMDFUNCTION) { - freefunc(cmdp->param.func); - } - cmdp->cmdtype = entry->cmdtype; - cmdp->param = entry->u; - INTON; -} - -static inline void -evalloop(const union node *n, int flags) -{ - int status; - - loopnest++; - status = 0; - for (;;) { - evaltree(n->nbinary.ch1, EV_TESTED); - if (evalskip) { -skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { - evalskip = 0; - continue; - } - if (evalskip == SKIPBREAK && --skipcount <= 0) - evalskip = 0; - break; - } - if (n->type == NWHILE) { - if (exitstatus != 0) - break; - } else { - if (exitstatus == 0) - break; - } - evaltree(n->nbinary.ch2, flags & EV_TESTED); - status = exitstatus; - if (evalskip) - goto skipping; - } - loopnest--; - exitstatus = status; -} - -static void -evalfor(const union node *n, int flags) -{ - struct arglist arglist; - union node *argp; - struct strlist *sp; - struct stackmark smark; - - setstackmark(&smark); - arglist.lastp = &arglist.list; - for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { - oexitstatus = exitstatus; - expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); - if (evalskip) - goto out; - } - *arglist.lastp = NULL; - - exitstatus = 0; - loopnest++; - for (sp = arglist.list ; sp ; sp = sp->next) { - setvar(n->nfor.var, sp->text, 0); - evaltree(n->nfor.body, flags & EV_TESTED); - if (evalskip) { - if (evalskip == SKIPCONT && --skipcount <= 0) { - evalskip = 0; - continue; - } - if (evalskip == SKIPBREAK && --skipcount <= 0) - evalskip = 0; - break; - } - } - loopnest--; -out: - popstackmark(&smark); -} - -static inline void -evalcase(const union node *n, int flags) -{ - union node *cp; - union node *patp; - struct arglist arglist; - struct stackmark smark; - - setstackmark(&smark); - arglist.lastp = &arglist.list; - oexitstatus = exitstatus; - expandarg(n->ncase.expr, &arglist, EXP_TILDE); - for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { - for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { - if (casematch(patp, arglist.list->text)) { - if (evalskip == 0) { - evaltree(cp->nclist.body, flags); - } - goto out; - } - } - } -out: - popstackmark(&smark); -} - -/* - * Evaluate a pipeline. All the processes in the pipeline are children - * of the process creating the pipeline. (This differs from some versions - * of the shell, which make the last process in a pipeline the parent - * of all the rest.) - */ - -static inline void -evalpipe(n) - union node *n; -{ - struct job *jp; - struct nodelist *lp; - int pipelen; - int prevfd; - int pip[2]; - - TRACE(("evalpipe(0x%lx) called\n", (long)n)); - pipelen = 0; - for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) - pipelen++; - INTOFF; - jp = makejob(n, pipelen); - prevfd = -1; - for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { - prehash(lp->n); - pip[1] = -1; - if (lp->next) { - if (pipe(pip) < 0) { - close(prevfd); - error("Pipe call failed"); - } - } - if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { - INTON; - if (prevfd > 0) { - close(0); - dup_as_newfd(prevfd, 0); - close(prevfd); - if (pip[0] == 0) { - pip[0] = -1; - } - } - if (pip[1] >= 0) { - if (pip[0] >= 0) { - close(pip[0]); - } - if (pip[1] != 1) { - close(1); - dup_as_newfd(pip[1], 1); - close(pip[1]); - } - } - evaltree(lp->n, EV_EXIT); - } - if (prevfd >= 0) - close(prevfd); - prevfd = pip[0]; - close(pip[1]); - } - INTON; - if (n->npipe.backgnd == 0) { - INTOFF; - exitstatus = waitforjob(jp); - TRACE(("evalpipe: job done exit status %d\n", exitstatus)); - INTON; - } -} - -static void find_command (const char *, struct cmdentry *, int, const char *); - -static int -isassignment(const char *word) { - if (!is_name(*word)) { - return 0; - } - do { - word++; - } while (is_in_name(*word)); - return *word == '='; -} - - -static void -evalcommand(union node *cmd, int flags) -{ - struct stackmark smark; - union node *argp; - struct arglist arglist; - struct arglist varlist; - char **argv; - int argc; - char **envp; - struct strlist *sp; - int mode; - struct cmdentry cmdentry; - struct job *jp; - char *volatile savecmdname; - volatile struct shparam saveparam; - struct localvar *volatile savelocalvars; - volatile int e; - char *lastarg; - const char *path; - const struct builtincmd *firstbltin; - struct jmploc *volatile savehandler; - struct jmploc jmploc; -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &argv; - (void) &argc; - (void) &lastarg; - (void) &flags; -#endif - - /* First expand the arguments. */ - TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); - setstackmark(&smark); - arglist.lastp = &arglist.list; - varlist.lastp = &varlist.list; - arglist.list = 0; - oexitstatus = exitstatus; - exitstatus = 0; - path = pathval(); - for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { - expandarg(argp, &varlist, EXP_VARTILDE); - } - for ( - argp = cmd->ncmd.args; argp && !arglist.list; - argp = argp->narg.next - ) { - expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); - } - if (argp) { - struct builtincmd *bcmd; - int pseudovarflag; - bcmd = find_builtin(arglist.list->text); - pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd); - for (; argp; argp = argp->narg.next) { - if (pseudovarflag && isassignment(argp->narg.text)) { - expandarg(argp, &arglist, EXP_VARTILDE); - continue; - } - expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); - } - } - *arglist.lastp = NULL; - *varlist.lastp = NULL; - expredir(cmd->ncmd.redirect); - argc = 0; - for (sp = arglist.list ; sp ; sp = sp->next) - argc++; - argv = stalloc(sizeof (char *) * (argc + 1)); - - for (sp = arglist.list ; sp ; sp = sp->next) { - TRACE(("evalcommand arg: %s\n", sp->text)); - *argv++ = sp->text; - } - *argv = NULL; - lastarg = NULL; - if (iflag && funcnest == 0 && argc > 0) - lastarg = argv[-1]; - argv -= argc; - - /* Print the command if xflag is set. */ - if (xflag) { - out2c('+'); - eprintlist(varlist.list); - eprintlist(arglist.list); - out2c('\n'); - } - - /* Now locate the command. */ - if (argc == 0) { - cmdentry.cmdtype = CMDBUILTIN; - firstbltin = cmdentry.u.cmd = BLTINCMD; - } else { - const char *oldpath; - int findflag = DO_ERR; - int oldfindflag; - - /* - * Modify the command lookup path, if a PATH= assignment - * is present - */ - for (sp = varlist.list ; sp ; sp = sp->next) - if (varequal(sp->text, defpathvar)) { - path = sp->text + 5; - findflag |= DO_BRUTE; - } - oldpath = path; - oldfindflag = findflag; - firstbltin = 0; - for(;;) { - find_command(argv[0], &cmdentry, findflag, path); - if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ - exitstatus = 127; - goto out; - } - /* implement bltin and command here */ - if (cmdentry.cmdtype != CMDBUILTIN) { - break; - } - if (!firstbltin) { - firstbltin = cmdentry.u.cmd; - } - if (cmdentry.u.cmd == BLTINCMD) { - for(;;) { - struct builtincmd *bcmd; - - argv++; - if (--argc == 0) - goto found; - if (!(bcmd = find_builtin(*argv))) { - out2fmt("%s: not found\n", *argv); - exitstatus = 127; - goto out; - } - cmdentry.u.cmd = bcmd; - if (bcmd != BLTINCMD) - break; - } - } - if (cmdentry.u.cmd == find_builtin("command")) { - argv++; - if (--argc == 0) { - goto found; - } - if (*argv[0] == '-') { - if (!equal(argv[0], "-p")) { - argv--; - argc++; - break; - } - argv++; - if (--argc == 0) { - goto found; - } - path = defpath; - findflag |= DO_BRUTE; - } else { - path = oldpath; - findflag = oldfindflag; - } - findflag |= DO_NOFUN; - continue; - } -found: - break; - } - } - - /* Fork off a child process if necessary. */ - if (cmd->ncmd.backgnd - || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0) - ) { - jp = makejob(cmd, 1); - mode = cmd->ncmd.backgnd; - if (forkshell(jp, cmd, mode) != 0) - goto parent; /* at end of routine */ - flags |= EV_EXIT; - } - - /* This is the child process if a fork occurred. */ - /* Execute the command. */ - if (cmdentry.cmdtype == CMDFUNCTION) { -#ifdef DEBUG - trputs("Shell function: "); trargs(argv); -#endif - exitstatus = oexitstatus; - redirect(cmd->ncmd.redirect, REDIR_PUSH); - saveparam = shellparam; - shellparam.malloc = 0; - shellparam.nparam = argc - 1; - shellparam.p = argv + 1; - INTOFF; - savelocalvars = localvars; - localvars = NULL; - INTON; - if (setjmp(jmploc.loc)) { - if (exception == EXSHELLPROC) { - freeparam((volatile struct shparam *) - &saveparam); - } else { - saveparam.optind = shellparam.optind; - saveparam.optoff = shellparam.optoff; - freeparam(&shellparam); - shellparam = saveparam; - } - poplocalvars(); - localvars = savelocalvars; - handler = savehandler; - longjmp(handler->loc, 1); - } - savehandler = handler; - handler = &jmploc; - for (sp = varlist.list ; sp ; sp = sp->next) - mklocal(sp->text); - funcnest++; - evaltree(cmdentry.u.func, flags & EV_TESTED); - funcnest--; - INTOFF; - poplocalvars(); - localvars = savelocalvars; - saveparam.optind = shellparam.optind; - saveparam.optoff = shellparam.optoff; - freeparam(&shellparam); - shellparam = saveparam; - handler = savehandler; - popredir(); - INTON; - if (evalskip == SKIPFUNC) { - evalskip = 0; - skipcount = 0; - } - if (flags & EV_EXIT) - exitshell(exitstatus); - } else if (cmdentry.cmdtype == CMDBUILTIN) { -#ifdef DEBUG - trputs("builtin command: "); trargs(argv); -#endif - mode = (cmdentry.u.cmd == EXECCMD)? 0 : REDIR_PUSH; - redirect(cmd->ncmd.redirect, mode); - savecmdname = commandname; - if (IS_BUILTIN_SPECIAL(firstbltin)) { - listsetvar(varlist.list); - } else { - cmdenviron = varlist.list; - } - e = -1; - if (setjmp(jmploc.loc)) { - e = exception; - exitstatus = (e == EXINT)? SIGINT+128 : 2; - goto cmddone; - } - savehandler = handler; - handler = &jmploc; - commandname = argv[0]; - argptr = argv + 1; - optptr = NULL; /* initialize nextopt */ - exitstatus = (*cmdentry.u.cmd->builtinfunc)(argc, argv); - flushall(); -cmddone: - cmdenviron = NULL; - if (e != EXSHELLPROC) { - commandname = savecmdname; - if (flags & EV_EXIT) - exitshell(exitstatus); - } - handler = savehandler; - if (e != -1) { - if ((e != EXERROR && e != EXEXEC) - || cmdentry.u.cmd == BLTINCMD - || cmdentry.u.cmd == DOTCMD - || cmdentry.u.cmd == EVALCMD - || cmdentry.u.cmd == EXECCMD) - exraise(e); - FORCEINTON; - } - if (cmdentry.u.cmd != EXECCMD) - popredir(); - } else { -#ifdef DEBUG - trputs("normal command: "); trargs(argv); -#endif - redirect(cmd->ncmd.redirect, 0); - clearredir(); - for (sp = varlist.list ; sp ; sp = sp->next) - setvareq(sp->text, VEXPORT|VSTACK); - envp = environment(); - shellexec(argv, envp, path, cmdentry.u.index); - } - goto out; - -parent: /* parent process gets here (if we forked) */ - if (mode == 0) { /* argument to fork */ - INTOFF; - exitstatus = waitforjob(jp); - INTON; - } - -out: - if (lastarg) - setvar("_", lastarg, 0); - popstackmark(&smark); -} - -/* - * Evaluate a parse tree. The value is left in the global variable - * exitstatus. - */ -static void -evaltree(n, flags) - union node *n; - int flags; -{ - int checkexit = 0; - if (n == NULL) { - TRACE(("evaltree(NULL) called\n")); - goto out; - } - TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type)); - switch (n->type) { - case NSEMI: - evaltree(n->nbinary.ch1, flags & EV_TESTED); - if (evalskip) - goto out; - evaltree(n->nbinary.ch2, flags); - break; - case NAND: - evaltree(n->nbinary.ch1, EV_TESTED); - if (evalskip || exitstatus != 0) - goto out; - evaltree(n->nbinary.ch2, flags); - break; - case NOR: - evaltree(n->nbinary.ch1, EV_TESTED); - if (evalskip || exitstatus == 0) - goto out; - evaltree(n->nbinary.ch2, flags); - break; - case NREDIR: - expredir(n->nredir.redirect); - redirect(n->nredir.redirect, REDIR_PUSH); - evaltree(n->nredir.n, flags); - popredir(); - break; - case NSUBSHELL: - evalsubshell(n, flags); - break; - case NBACKGND: - evalsubshell(n, flags); - break; - case NIF: { - evaltree(n->nif.test, EV_TESTED); - if (evalskip) - goto out; - if (exitstatus == 0) - evaltree(n->nif.ifpart, flags); - else if (n->nif.elsepart) - evaltree(n->nif.elsepart, flags); - else - exitstatus = 0; - break; - } - case NWHILE: - case NUNTIL: - evalloop(n, flags); - break; - case NFOR: - evalfor(n, flags); - break; - case NCASE: - evalcase(n, flags); - break; - case NDEFUN: { - struct builtincmd *bcmd; - struct cmdentry entry; - if ( - (bcmd = find_builtin(n->narg.text)) && - IS_BUILTIN_SPECIAL(bcmd) - ) { - out2fmt("%s is a special built-in\n", n->narg.text); - exitstatus = 1; - break; - } - entry.cmdtype = CMDFUNCTION; - entry.u.func = copyfunc(n->narg.next); - addcmdentry(n->narg.text, &entry); - exitstatus = 0; - break; - } - case NNOT: - evaltree(n->nnot.com, EV_TESTED); - exitstatus = !exitstatus; - break; - - case NPIPE: - evalpipe(n); - checkexit = 1; - break; - case NCMD: - evalcommand(n, flags); - checkexit = 1; - break; -#ifdef DEBUG - default: - printf("Node type = %d\n", n->type); - break; -#endif - } -out: - if (pendingsigs) - dotrap(); - if ( - flags & EV_EXIT || - (checkexit && eflag && exitstatus && !(flags & EV_TESTED)) - ) - exitshell(exitstatus); -} - -/* - * Kick off a subshell to evaluate a tree. - */ - -static void -evalsubshell(const union node *n, int flags) -{ - struct job *jp; - int backgnd = (n->type == NBACKGND); - - expredir(n->nredir.redirect); - jp = makejob(n, 1); - if (forkshell(jp, n, backgnd) == 0) { - if (backgnd) - flags &=~ EV_TESTED; - redirect(n->nredir.redirect, 0); - evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ - } - if (! backgnd) { - INTOFF; - exitstatus = waitforjob(jp); - INTON; - } -} - -/* - * Compute the names of the files in a redirection list. - */ - -static void fixredir(union node *n, const char *text, int err); - -static void -expredir(union node *n) -{ - union node *redir; - - for (redir = n ; redir ; redir = redir->nfile.next) { - struct arglist fn; - fn.lastp = &fn.list; - oexitstatus = exitstatus; - switch (redir->type) { - case NFROMTO: - case NFROM: - case NTO: - case NAPPEND: - case NTOOV: - expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); - redir->nfile.expfname = fn.list->text; - break; - case NFROMFD: - case NTOFD: - if (redir->ndup.vname) { - expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); - fixredir(redir, fn.list->text, 1); - } - break; - } - } -} - - -/* - * Execute a command inside back quotes. If it's a builtin command, we - * want to save its output in a block obtained from malloc. Otherwise - * we fork off a subprocess and get the output of the command via a pipe. - * Should be called with interrupts off. - */ - -static void -evalbackcmd(union node *n, struct backcmd *result) -{ - int pip[2]; - struct job *jp; - struct stackmark smark; /* unnecessary */ - - setstackmark(&smark); - result->fd = -1; - result->buf = NULL; - result->nleft = 0; - result->jp = NULL; - if (n == NULL) { - exitstatus = 0; - goto out; - } - exitstatus = 0; - if (pipe(pip) < 0) - error("Pipe call failed"); - jp = makejob(n, 1); - if (forkshell(jp, n, FORK_NOJOB) == 0) { - FORCEINTON; - close(pip[0]); - if (pip[1] != 1) { - close(1); - dup_as_newfd(pip[1], 1); - close(pip[1]); - } - eflag = 0; - evaltree(n, EV_EXIT); - } - close(pip[1]); - result->fd = pip[0]; - result->jp = jp; -out: - popstackmark(&smark); - TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", - result->fd, result->buf, result->nleft, result->jp)); -} - - -/* - * Execute a simple command. - */ - -/* - * Search for a command. This is called before we fork so that the - * location of the command will be available in the parent as well as - * the child. The check for "goodname" is an overly conservative - * check that the name will not be subject to expansion. - */ - -static void -prehash(n) - union node *n; -{ - struct cmdentry entry; - - if (n->type == NCMD && n->ncmd.args) - if (goodname(n->ncmd.args->narg.text)) - find_command(n->ncmd.args->narg.text, &entry, 0, - pathval()); -} - - -/* - * Builtin commands. Builtin commands whose functions are closely - * tied to evaluation are implemented here. - */ - -/* - * No command given, or a bltin command with no arguments. Set the - * specified variables. - */ - -int -bltincmd(argc, argv) - int argc; - char **argv; -{ - /* - * Preserve exitstatus of a previous possible redirection - * as POSIX mandates - */ - return exitstatus; -} - - -/* - * Handle break and continue commands. Break, continue, and return are - * all handled by setting the evalskip flag. The evaluation routines - * above all check this flag, and if it is set they start skipping - * commands rather than executing them. The variable skipcount is - * the number of loops to break/continue, or the number of function - * levels to return. (The latter is always 1.) It should probably - * be an error to break out of more loops than exist, but it isn't - * in the standard shell so we don't make it one here. - */ - -static int -breakcmd(argc, argv) - int argc; - char **argv; -{ - int n = argc > 1 ? number(argv[1]) : 1; - - if (n > loopnest) - n = loopnest; - if (n > 0) { - evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; - skipcount = n; - } - return 0; -} - - -/* - * The return command. - */ - -static int -returncmd(argc, argv) - int argc; - char **argv; -{ - int ret = argc > 1 ? number(argv[1]) : oexitstatus; - - if (funcnest) { - evalskip = SKIPFUNC; - skipcount = 1; - return ret; - } - else { - /* Do what ksh does; skip the rest of the file */ - evalskip = SKIPFILE; - skipcount = 1; - return ret; - } -} - - -#ifndef BB_TRUE_FALSE -static int -false_main(argc, argv) - int argc; - char **argv; -{ - return 1; -} - - -static int -true_main(argc, argv) - int argc; - char **argv; -{ - return 0; -} -#endif - -/* - * Controls whether the shell is interactive or not. - */ - -static void setsignal(int signo); -static void chkmail(int silent); - - -static void -setinteractive(int on) -{ - static int is_interactive; - static int do_banner=0; - - if (on == is_interactive) - return; - setsignal(SIGINT); - setsignal(SIGQUIT); - setsignal(SIGTERM); - chkmail(1); - is_interactive = on; - if (do_banner==0 && is_interactive) { - /* Looks like they want an interactive shell */ - printf( "\n\n" BB_BANNER " Built-in shell (ash)\n"); - printf( "Enter 'help' for a list of built-in commands.\n\n"); - do_banner=1; - } -} - -static void -optschanged(void) -{ - setinteractive(iflag); - setjobctl(mflag); -} - - -static int -execcmd(argc, argv) - int argc; - char **argv; -{ - if (argc > 1) { - struct strlist *sp; - - iflag = 0; /* exit on error */ - mflag = 0; - optschanged(); - for (sp = cmdenviron; sp ; sp = sp->next) - setvareq(sp->text, VEXPORT|VSTACK); - shellexec(argv + 1, environment(), pathval(), 0); - } - return 0; -} - -static void -eprintlist(struct strlist *sp) -{ - for (; sp; sp = sp->next) { - out2fmt(" %s",sp->text); - } -} - -/* - * Exec a program. Never returns. If you change this routine, you may - * have to change the find_command routine as well. - */ - -static const char *pathopt; /* set by padvance */ - -static void -shellexec(argv, envp, path, idx) - char **argv, **envp; - const char *path; - int idx; -{ - char *cmdname; - int e; - - if (strchr(argv[0], '/') != NULL) { - tryexec(argv[0], argv, envp); - e = errno; - } else { - e = ENOENT; - while ((cmdname = padvance(&path, argv[0])) != NULL) { - if (--idx < 0 && pathopt == NULL) { - tryexec(cmdname, argv, envp); - if (errno != ENOENT && errno != ENOTDIR) - e = errno; - } - stunalloc(cmdname); - } - } - - /* Map to POSIX errors */ - switch (e) { - case EACCES: - exerrno = 126; - break; - case ENOENT: - exerrno = 127; - break; - default: - exerrno = 2; - break; - } - exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC)); - /* NOTREACHED */ -} - -/* - * Clear traps on a fork. - */ -static void -clear_traps(void) { - char **tp; - - for (tp = trap ; tp < &trap[NSIG] ; tp++) { - if (*tp && **tp) { /* trap not NULL or SIG_IGN */ - INTOFF; - ckfree(*tp); - *tp = NULL; - if (tp != &trap[0]) - setsignal(tp - trap); - INTON; - } - } -} - - -static void -initshellproc(void) { - -#ifdef ASH_ALIAS - /* from alias.c: */ - { - rmaliases(); - } -#endif - /* from eval.c: */ - { - exitstatus = 0; - } - - /* from exec.c: */ - { - deletefuncs(); - } - - /* from jobs.c: */ - { - backgndpid = -1; -#ifdef JOBS - jobctl = 0; -#endif - } - - /* from options.c: */ - { - int i; - - for (i = 0; i < NOPTS; i++) - optent_val(i) = 0; - optschanged(); - - } - - /* from redir.c: */ - { - clearredir(); - } - - /* from trap.c: */ - { - char *sm; - - clear_traps(); - for (sm = sigmode ; sm < sigmode + NSIG - 1; sm++) { - if (*sm == S_IGN) - *sm = S_HARD_IGN; - } - } - - /* from var.c: */ - { - shprocvar(); - } -} - -static int preadbuffer(void); -static void pushfile (void); - -/* - * Read a character from the script, returning PEOF on end of file. - * Nul characters in the input are silently discarded. - */ - -#ifndef ASH_OPTIMIZE_FOR_SIZE -#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer()) -static int -pgetc(void) -{ - return pgetc_macro(); -} -#else -static int -pgetc_macro(void) -{ - return --parsenleft >= 0? *parsenextc++ : preadbuffer(); -} - -static inline int -pgetc(void) -{ - return pgetc_macro(); -} -#endif - - -/* - * Undo the last call to pgetc. Only one character may be pushed back. - * PEOF may be pushed back. - */ - -static void -pungetc() { - parsenleft++; - parsenextc--; -} - - -static void -popfile(void) { - struct parsefile *pf = parsefile; - - INTOFF; - if (pf->fd >= 0) - close(pf->fd); - if (pf->buf) - ckfree(pf->buf); - while (pf->strpush) - popstring(); - parsefile = pf->prev; - ckfree(pf); - parsenleft = parsefile->nleft; - parselleft = parsefile->lleft; - parsenextc = parsefile->nextc; - plinno = parsefile->linno; - INTON; -} - - -/* - * Return to top level. - */ - -static void -popallfiles(void) { - while (parsefile != &basepf) - popfile(); -} - -/* - * Close the file(s) that the shell is reading commands from. Called - * after a fork is done. - */ - -static void -closescript() { - popallfiles(); - if (parsefile->fd > 0) { - close(parsefile->fd); - parsefile->fd = 0; - } -} - - -/* - * Like setinputfile, but takes an open file descriptor. Call this with - * interrupts off. - */ - -static void -setinputfd(fd, push) - int fd, push; -{ - (void) fcntl(fd, F_SETFD, FD_CLOEXEC); - if (push) { - pushfile(); - parsefile->buf = 0; - } else { - closescript(); - while (parsefile->strpush) - popstring(); - } - parsefile->fd = fd; - if (parsefile->buf == NULL) - parsefile->buf = ckmalloc(BUFSIZ); - parselleft = parsenleft = 0; - plinno = 1; -} - - -/* - * Set the input to take input from a file. If push is set, push the - * old input onto the stack first. - */ - -static void -setinputfile(const char *fname, int push) -{ - int fd; - int myfileno2; - - INTOFF; - if ((fd = open(fname, O_RDONLY)) < 0) - error("Can't open %s", fname); - if (fd < 10) { - myfileno2 = dup_as_newfd(fd, 10); - close(fd); - if (myfileno2 < 0) - error("Out of file descriptors"); - fd = myfileno2; - } - setinputfd(fd, push); - INTON; -} - - -static void -tryexec(char *cmd, char **argv, char **envp) -{ - int e; - -#ifdef BB_FEATURE_SH_STANDALONE_SHELL - char *name = cmd; - char** argv_l=argv; - int argc_l; -#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN - name = get_last_path_component(name); -#endif - argv_l=envp; - for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++) - putenv(*argv_l); - argv_l=argv; - for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++) - optind = 1; - run_applet_by_name(name, argc_l, argv); -#endif - execve(cmd, argv, envp); - e = errno; - if (e == ENOEXEC) { - INTOFF; - initshellproc(); - setinputfile(cmd, 0); - commandname = arg0 = savestr(argv[0]); - setparam(argv + 1); - exraise(EXSHELLPROC); - } - errno = e; -} - -static char *commandtext (const union node *); - -/* - * Do a path search. The variable path (passed by reference) should be - * set to the start of the path before the first call; padvance will update - * this value as it proceeds. Successive calls to padvance will return - * the possible path expansions in sequence. If an option (indicated by - * a percent sign) appears in the path entry then the global variable - * pathopt will be set to point to it; otherwise pathopt will be set to - * NULL. - */ - -static const char *pathopt; - -static void growstackblock(void); - - -static char * -padvance(const char **path, const char *name) -{ - const char *p; - char *q; - const char *start; - int len; - - if (*path == NULL) - return NULL; - start = *path; - for (p = start ; *p && *p != ':' && *p != '%' ; p++); - len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ - while (stackblocksize() < len) - growstackblock(); - q = stackblock(); - if (p != start) { - memcpy(q, start, p - start); - q += p - start; - *q++ = '/'; - } - strcpy(q, name); - pathopt = NULL; - if (*p == '%') { - pathopt = ++p; - while (*p && *p != ':') p++; - } - if (*p == ':') - *path = p + 1; - else - *path = NULL; - return stalloc(len); -} - -/* - * Wrapper around strcmp for qsort/bsearch/... - */ -static int -pstrcmp(const void *a, const void *b) -{ - return strcmp((const char *) a, *(const char *const *) b); -} - -/* - * Find a keyword is in a sorted array. - */ - -static const char *const * -findkwd(const char *s) -{ - return bsearch(s, parsekwd, sizeof(parsekwd) / sizeof(const char *), - sizeof(const char *), pstrcmp); -} - - -/*** Command hashing code ***/ - - -static int -hashcmd(argc, argv) - int argc; - char **argv; -{ - struct tblentry **pp; - struct tblentry *cmdp; - int c; - int verbose; - struct cmdentry entry; - char *name; -#ifdef ASH_ALIAS - const struct alias *ap; -#endif - - verbose = 0; - while ((c = nextopt("rvV")) != '\0') { - if (c == 'r') { - clearcmdentry(0); - return 0; - } else if (c == 'v' || c == 'V') { - verbose = c; - } - } - if (*argptr == NULL) { - for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { - for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { - if (cmdp->cmdtype != CMDBUILTIN) { - printentry(cmdp, verbose); - } - } - } - return 0; - } - c = 0; - while ((name = *argptr++) != NULL) { - if ((cmdp = cmdlookup(name, 0)) != NULL - && (cmdp->cmdtype == CMDNORMAL - || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) - delete_cmd_entry(); -#ifdef ASH_ALIAS - /* Then look at the aliases */ - if ((ap = lookupalias(name, 0)) != NULL) { - if (verbose=='v') - printf("%s is an alias for %s\n", name, ap->val); - else - printalias(ap); - continue; - } -#endif - /* First look at the keywords */ - if (findkwd(name)!=0) { - if (verbose=='v') - printf("%s is a shell keyword\n", name); - else - printf(snlfmt, name); - continue; - } - - find_command(name, &entry, DO_ERR, pathval()); - if (entry.cmdtype == CMDUNKNOWN) c = 1; - else if (verbose) { - cmdp = cmdlookup(name, 0); - if (cmdp) printentry(cmdp, verbose=='v'); - flushall(); - } - } - return c; -} - -static void -printentry(cmdp, verbose) - struct tblentry *cmdp; - int verbose; - { - int idx; - const char *path; - char *name; - - printf("%s%s", cmdp->cmdname, (verbose ? " is " : "")); - if (cmdp->cmdtype == CMDNORMAL) { - idx = cmdp->param.index; - path = pathval(); - do { - name = padvance(&path, cmdp->cmdname); - stunalloc(name); - } while (--idx >= 0); - if(verbose) - out1str(name); - } else if (cmdp->cmdtype == CMDBUILTIN) { - if(verbose) - out1str("a shell builtin"); - } else if (cmdp->cmdtype == CMDFUNCTION) { - if (verbose) { - INTOFF; - out1str("a function\n"); - name = commandtext(cmdp->param.func); - printf("%s() {\n %s\n}", cmdp->cmdname, name); - ckfree(name); - INTON; - } -#ifdef DEBUG - } else { - error("internal error: cmdtype %d", cmdp->cmdtype); -#endif - } - printf(snlfmt, cmdp->rehash ? "*" : nullstr); -} - - - -/*** List the available builtins ***/ - - -static int helpcmd(int argc, char** argv) -{ - int col, i; - - printf("\nBuilt-in commands:\n-------------------\n"); - for (col=0, i=0; i < NUMBUILTINS; i++) { - col += printf("%c%s", ((col == 0) ? '\t' : ' '), - builtincmds[i].name+1); - if (col > 60) { - printf("\n"); - col = 0; - } - } -#ifdef BB_FEATURE_SH_STANDALONE_SHELL - { - extern const struct BB_applet applets[]; - extern const size_t NUM_APPLETS; - - for (i=0; i < NUM_APPLETS; i++) { - - col += printf("%c%s", ((col == 0) ? '\t' : ' '), - applets[i].name); - if (col > 60) { - printf("\n"); - col = 0; - } - } - } -#endif - printf("\n\n"); - return EXIT_SUCCESS; -} - -/* - * Resolve a command name. If you change this routine, you may have to - * change the shellexec routine as well. - */ - -static int prefix (const char *, const char *); - -static void -find_command(const char *name, struct cmdentry *entry, int act, const char *path) -{ - struct tblentry *cmdp; - int idx; - int prev; - char *fullname; - struct stat statb; - int e; - int bltin; - int firstchange; - int updatetbl; - int regular; - struct builtincmd *bcmd; - - /* If name contains a slash, don't use the hash table */ - if (strchr(name, '/') != NULL) { - if (act & DO_ABS) { - while (stat(name, &statb) < 0) { - if (errno != ENOENT && errno != ENOTDIR) - e = errno; - entry->cmdtype = CMDUNKNOWN; - entry->u.index = -1; - return; - } - entry->cmdtype = CMDNORMAL; - entry->u.index = -1; - return; - } - entry->cmdtype = CMDNORMAL; - entry->u.index = 0; - return; - } - - updatetbl = 1; - if (act & DO_BRUTE) { - firstchange = path_change(path, &bltin); - } else { - bltin = builtinloc; - firstchange = 9999; - } - - /* If name is in the table, and not invalidated by cd, we're done */ - if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0) { - if (cmdp->cmdtype == CMDFUNCTION) { - if (act & DO_NOFUN) { - updatetbl = 0; - } else { - goto success; - } - } else if (act & DO_BRUTE) { - if ((cmdp->cmdtype == CMDNORMAL && - cmdp->param.index >= firstchange) || - (cmdp->cmdtype == CMDBUILTIN && - ((builtinloc < 0 && bltin >= 0) ? - bltin : builtinloc) >= firstchange)) { - /* need to recompute the entry */ - } else { - goto success; - } - } else { - goto success; - } - } - - bcmd = find_builtin(name); - regular = bcmd && IS_BUILTIN_REGULAR(bcmd); - - if (regular) { - if (cmdp && (cmdp->cmdtype == CMDBUILTIN)) { - goto success; - } - } else if (act & DO_BRUTE) { - if (firstchange == 0) { - updatetbl = 0; - } - } - - /* If %builtin not in path, check for builtin next */ - if (regular || (bltin < 0 && bcmd)) { -builtin: - if (!updatetbl) { - entry->cmdtype = CMDBUILTIN; - entry->u.cmd = bcmd; - return; - } - INTOFF; - cmdp = cmdlookup(name, 1); - cmdp->cmdtype = CMDBUILTIN; - cmdp->param.cmd = bcmd; - INTON; - goto success; - } - - /* We have to search path. */ - prev = -1; /* where to start */ - if (cmdp && cmdp->rehash) { /* doing a rehash */ - if (cmdp->cmdtype == CMDBUILTIN) - prev = builtinloc; - else - prev = cmdp->param.index; - } - - e = ENOENT; - idx = -1; -loop: - while ((fullname = padvance(&path, name)) != NULL) { - stunalloc(fullname); - idx++; - if (idx >= firstchange) { - updatetbl = 0; - } - if (pathopt) { - if (prefix("builtin", pathopt)) { - if ((bcmd = find_builtin(name))) { - goto builtin; - } - continue; - } else if (!(act & DO_NOFUN) && - prefix("func", pathopt)) { - /* handled below */ - } else { - continue; /* ignore unimplemented options */ - } - } - /* if rehash, don't redo absolute path names */ - if (fullname[0] == '/' && idx <= prev && - idx < firstchange) { - if (idx < prev) - continue; - TRACE(("searchexec \"%s\": no change\n", name)); - goto success; - } - while (stat(fullname, &statb) < 0) { - if (errno != ENOENT && errno != ENOTDIR) - e = errno; - goto loop; - } - e = EACCES; /* if we fail, this will be the error */ - if (!S_ISREG(statb.st_mode)) - continue; - if (pathopt) { /* this is a %func directory */ - stalloc(strlen(fullname) + 1); - readcmdfile(fullname); - if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION) - error("%s not defined in %s", name, fullname); - stunalloc(fullname); - goto success; - } - TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); - /* If we aren't called with DO_BRUTE and cmdp is set, it must - be a function and we're being called with DO_NOFUN */ - if (!updatetbl) { - entry->cmdtype = CMDNORMAL; - entry->u.index = idx; - return; - } - INTOFF; - cmdp = cmdlookup(name, 1); - cmdp->cmdtype = CMDNORMAL; - cmdp->param.index = idx; - INTON; - goto success; - } - - /* We failed. If there was an entry for this command, delete it */ - if (cmdp && updatetbl) - delete_cmd_entry(); - if (act & DO_ERR) - out2fmt("%s: %s\n", name, errmsg(e, E_EXEC)); - entry->cmdtype = CMDUNKNOWN; - return; - -success: - cmdp->rehash = 0; - entry->cmdtype = cmdp->cmdtype; - entry->u = cmdp->param; -} - - - -/* - * Search the table of builtin commands. - */ - -static int -bstrcmp(const void *name, const void *b) -{ - return strcmp((const char *)name, (*(const char *const *) b)+1); -} - -static struct builtincmd * -find_builtin(const char *name) -{ - struct builtincmd *bp; - - bp = bsearch(name, builtincmds, NUMBUILTINS, sizeof(struct builtincmd), - bstrcmp - ); - return bp; -} - - -/* - * Called when a cd is done. Marks all commands so the next time they - * are executed they will be rehashed. - */ - -static void -hashcd(void) { - struct tblentry **pp; - struct tblentry *cmdp; - - for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { - for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { - if (cmdp->cmdtype == CMDNORMAL - || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)) - cmdp->rehash = 1; - } - } -} - - - -/* - * Called before PATH is changed. The argument is the new value of PATH; - * pathval() still returns the old value at this point. Called with - * interrupts off. - */ - -static void -changepath(const char *newval) -{ - int firstchange; - int bltin; - - firstchange = path_change(newval, &bltin); - if (builtinloc < 0 && bltin >= 0) - builtinloc = bltin; /* zap builtins */ - clearcmdentry(firstchange); - builtinloc = bltin; -} - - -/* - * Clear out command entries. The argument specifies the first entry in - * PATH which has changed. - */ - -static void -clearcmdentry(firstchange) - int firstchange; -{ - struct tblentry **tblp; - struct tblentry **pp; - struct tblentry *cmdp; - - INTOFF; - for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) { - pp = tblp; - while ((cmdp = *pp) != NULL) { - if ((cmdp->cmdtype == CMDNORMAL && - cmdp->param.index >= firstchange) - || (cmdp->cmdtype == CMDBUILTIN && - builtinloc >= firstchange)) { - *pp = cmdp->next; - ckfree(cmdp); - } else { - pp = &cmdp->next; - } - } - } - INTON; -} - - -/* - * Delete all functions. - */ - -static void -deletefuncs(void) { - struct tblentry **tblp; - struct tblentry **pp; - struct tblentry *cmdp; - - INTOFF; - for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) { - pp = tblp; - while ((cmdp = *pp) != NULL) { - if (cmdp->cmdtype == CMDFUNCTION) { - *pp = cmdp->next; - freefunc(cmdp->param.func); - ckfree(cmdp); - } else { - pp = &cmdp->next; - } - } - } - INTON; -} - - - -/* - * Locate a command in the command hash table. If "add" is nonzero, - * add the command to the table if it is not already present. The - * variable "lastcmdentry" is set to point to the address of the link - * pointing to the entry, so that delete_cmd_entry can delete the - * entry. - */ - -static struct tblentry **lastcmdentry; - -static struct tblentry * -cmdlookup(const char *name, int add) -{ - int hashval; - const char *p; - struct tblentry *cmdp; - struct tblentry **pp; - - p = name; - hashval = *p << 4; - while (*p) - hashval += *p++; - hashval &= 0x7FFF; - pp = &cmdtable[hashval % CMDTABLESIZE]; - for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { - if (equal(cmdp->cmdname, name)) - break; - pp = &cmdp->next; - } - if (add && cmdp == NULL) { - INTOFF; - cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB - + strlen(name) + 1); - cmdp->next = NULL; - cmdp->cmdtype = CMDUNKNOWN; - cmdp->rehash = 0; - strcpy(cmdp->cmdname, name); - INTON; - } - lastcmdentry = pp; - return cmdp; -} - -/* - * Delete the command entry returned on the last lookup. - */ - -static void -delete_cmd_entry() { - struct tblentry *cmdp; - - INTOFF; - cmdp = *lastcmdentry; - *lastcmdentry = cmdp->next; - ckfree(cmdp); - INTON; -} - - - - - -static const short nodesize[26] = { - ALIGN(sizeof (struct nbinary)), - ALIGN(sizeof (struct ncmd)), - ALIGN(sizeof (struct npipe)), - ALIGN(sizeof (struct nredir)), - ALIGN(sizeof (struct nredir)), - ALIGN(sizeof (struct nredir)), - ALIGN(sizeof (struct nbinary)), - ALIGN(sizeof (struct nbinary)), - ALIGN(sizeof (struct nif)), - ALIGN(sizeof (struct nbinary)), - ALIGN(sizeof (struct nbinary)), - ALIGN(sizeof (struct nfor)), - ALIGN(sizeof (struct ncase)), - ALIGN(sizeof (struct nclist)), - ALIGN(sizeof (struct narg)), - ALIGN(sizeof (struct narg)), - ALIGN(sizeof (struct nfile)), - ALIGN(sizeof (struct nfile)), - ALIGN(sizeof (struct nfile)), - ALIGN(sizeof (struct nfile)), - ALIGN(sizeof (struct nfile)), - ALIGN(sizeof (struct ndup)), - ALIGN(sizeof (struct ndup)), - ALIGN(sizeof (struct nhere)), - ALIGN(sizeof (struct nhere)), - ALIGN(sizeof (struct nnot)), -}; - - - -/* - * Delete a function if it exists. - */ - -static void -unsetfunc(char *name) -{ - struct tblentry *cmdp; - - if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) { - freefunc(cmdp->param.func); - delete_cmd_entry(); - } -} - - -/* - * Locate and print what a word is... - */ - -static int -typecmd(int argc, char **argv) -{ - int i; - int err = 0; - char *argv_a[2]; - - argv_a[1] = 0; - - for (i = 1; i < argc; i++) { - argv_a[0] = argv[i]; - argptr = argv_a; - optptr = "v"; - err |= hashcmd(argc, argv); - } - return err; -} - -#ifdef ASH_CMDCMD -static int -commandcmd(argc, argv) - int argc; - char **argv; -{ - int c; - int default_path = 0; - int verify_only = 0; - int verbose_verify_only = 0; - - while ((c = nextopt("pvV")) != '\0') - switch (c) { - case 'p': - default_path = 1; - break; - case 'v': - verify_only = 1; - break; - case 'V': - verbose_verify_only = 1; - break; - } - - if (default_path + verify_only + verbose_verify_only > 1 || - !*argptr) { - out2str( - "command [-p] command [arg ...]\n" - "command {-v|-V} command\n"); - return EX_USAGE; - } - - if (verify_only || verbose_verify_only) { - char *argv_a[2]; - - argv_a[1] = 0; - argv_a[0] = *argptr; - argptr = argv_a; - optptr = verbose_verify_only ? "v" : "V"; /* reverse special */ - return hashcmd(argc, argv); - } - - return 0; -} -#endif - -static int -path_change(newval, bltin) - const char *newval; - int *bltin; -{ - const char *old, *new; - int idx; - int firstchange; - - old = pathval(); - new = newval; - firstchange = 9999; /* assume no change */ - idx = 0; - *bltin = -1; - for (;;) { - if (*old != *new) { - firstchange = idx; - if ((*old == '\0' && *new == ':') - || (*old == ':' && *new == '\0')) - firstchange++; - old = new; /* ignore subsequent differences */ - } - if (*new == '\0') - break; - if (*new == '%' && *bltin < 0 && prefix("builtin", new + 1)) - *bltin = idx; - if (*new == ':') { - idx++; - } - new++, old++; - } - if (builtinloc >= 0 && *bltin < 0) - firstchange = 0; - return firstchange; -} -/* - * Routines to expand arguments to commands. We have to deal with - * backquotes, shell variables, and file metacharacters. - */ -/* - * _rmescape() flags - */ -#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ -#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ - -/* - * Structure specifying which parts of the string should be searched - * for IFS characters. - */ - -struct ifsregion { - struct ifsregion *next; /* next region in list */ - int begoff; /* offset of start of region */ - int endoff; /* offset of end of region */ - int nulonly; /* search for nul bytes only */ -}; - - -static char *expdest; /* output of current string */ -static struct nodelist *argbackq; /* list of back quote expressions */ -static struct ifsregion ifsfirst; /* first struct in list of ifs regions */ -static struct ifsregion *ifslastp; /* last struct in list */ -static struct arglist exparg; /* holds expanded arg list */ - -static void argstr (char *, int); -static char *exptilde (char *, int); -static void expbackq (union node *, int, int); -static int subevalvar (char *, char *, int, int, int, int, int); -static int varisset (char *, int); -static void strtodest (const char *, const char *, int); -static void varvalue (char *, int, int); -static void recordregion (int, int, int); -static void removerecordregions (int); -static void ifsbreakup (char *, struct arglist *); -static void ifsfree (void); -static void expandmeta (struct strlist *, int); -#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) -#define preglob(p) _rmescapes((p), RMESCAPE_ALLOC | RMESCAPE_GLOB) -#if !defined(GLOB_BROKEN) -static void addglob (const glob_t *); -#endif -#endif -#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) -static void expmeta (char *, char *); -#endif -#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) -static struct strlist *expsort (struct strlist *); -static struct strlist *msort (struct strlist *, int); -#endif -static int patmatch (char *, char *, int); -#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) -static int patmatch2 (char *, char *, int); -#else -static int pmatch (char *, char *, int); -#define patmatch2 patmatch -#endif -static char *cvtnum (int, char *); - -/* - * Expand shell variables and backquotes inside a here document. - */ - -/* arg: the document, fd: where to write the expanded version */ -static inline void -expandhere(union node *arg, int fd) -{ - herefd = fd; - expandarg(arg, (struct arglist *)NULL, 0); - xwrite(fd, stackblock(), expdest - stackblock()); -} - - -/* - * Perform variable substitution and command substitution on an argument, - * placing the resulting list of arguments in arglist. If EXP_FULL is true, - * perform splitting and file name expansion. When arglist is NULL, perform - * here document expansion. - */ - -static void -expandarg(arg, arglist, flag) - union node *arg; - struct arglist *arglist; - int flag; -{ - struct strlist *sp; - char *p; - - argbackq = arg->narg.backquote; - STARTSTACKSTR(expdest); - ifsfirst.next = NULL; - ifslastp = NULL; - argstr(arg->narg.text, flag); - if (arglist == NULL) { - return; /* here document expanded */ - } - STPUTC('\0', expdest); - p = grabstackstr(expdest); - exparg.lastp = &exparg.list; - /* - * TODO - EXP_REDIR - */ - if (flag & EXP_FULL) { - ifsbreakup(p, &exparg); - *exparg.lastp = NULL; - exparg.lastp = &exparg.list; - expandmeta(exparg.list, flag); - } else { - if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ - rmescapes(p); - sp = (struct strlist *)stalloc(sizeof (struct strlist)); - sp->text = p; - *exparg.lastp = sp; - exparg.lastp = &sp->next; - } - ifsfree(); - *exparg.lastp = NULL; - if (exparg.list) { - *arglist->lastp = exparg.list; - arglist->lastp = exparg.lastp; - } -} - - -/* - * Expand a variable, and return a pointer to the next character in the - * input string. - */ - -static inline char * -evalvar(p, flag) - char *p; - int flag; -{ - int subtype; - int varflags; - char *var; - const char *val; - int patloc; - int c; - int set; - int special; - int startloc; - int varlen; - int easy; - int quotes = flag & (EXP_FULL | EXP_CASE); - - varflags = *p++; - subtype = varflags & VSTYPE; - var = p; - special = 0; - if (! is_name(*p)) - special = 1; - p = strchr(p, '=') + 1; -again: /* jump here after setting a variable with ${var=text} */ - if (special) { - set = varisset(var, varflags & VSNUL); - val = NULL; - } else { - val = lookupvar(var); - if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { - val = NULL; - set = 0; - } else - set = 1; - } - varlen = 0; - startloc = expdest - stackblock(); - if (set && subtype != VSPLUS) { - /* insert the value of the variable */ - if (special) { - varvalue(var, varflags & VSQUOTE, flag); - if (subtype == VSLENGTH) { - varlen = expdest - stackblock() - startloc; - STADJUST(-varlen, expdest); - } - } else { - if (subtype == VSLENGTH) { - varlen = strlen(val); - } else { - strtodest( - val, - varflags & VSQUOTE ? - DQSYNTAX : BASESYNTAX, - quotes - ); - } - } - } - - if (subtype == VSPLUS) - set = ! set; - - easy = ((varflags & VSQUOTE) == 0 || - (*var == '@' && shellparam.nparam != 1)); - - - switch (subtype) { - case VSLENGTH: - expdest = cvtnum(varlen, expdest); - goto record; - - case VSNORMAL: - if (!easy) - break; -record: - recordregion(startloc, expdest - stackblock(), - varflags & VSQUOTE); - break; - - case VSPLUS: - case VSMINUS: - if (!set) { - argstr(p, flag); - break; - } - if (easy) - goto record; - break; - - case VSTRIMLEFT: - case VSTRIMLEFTMAX: - case VSTRIMRIGHT: - case VSTRIMRIGHTMAX: - if (!set) - break; - /* - * Terminate the string and start recording the pattern - * right after it - */ - STPUTC('\0', expdest); - patloc = expdest - stackblock(); - if (subevalvar(p, NULL, patloc, subtype, - startloc, varflags, quotes) == 0) { - int amount = (expdest - stackblock() - patloc) + 1; - STADJUST(-amount, expdest); - } - /* Remove any recorded regions beyond start of variable */ - removerecordregions(startloc); - goto record; - - case VSASSIGN: - case VSQUESTION: - if (!set) { - if (subevalvar(p, var, 0, subtype, startloc, - varflags, quotes)) { - varflags &= ~VSNUL; - /* - * Remove any recorded regions beyond - * start of variable - */ - removerecordregions(startloc); - goto again; - } - break; - } - if (easy) - goto record; - break; - -#ifdef DEBUG - default: - abort(); -#endif - } - - if (subtype != VSNORMAL) { /* skip to end of alternative */ - int nesting = 1; - for (;;) { - if ((c = *p++) == CTLESC) - p++; - else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { - if (set) - argbackq = argbackq->next; - } else if (c == CTLVAR) { - if ((*p++ & VSTYPE) != VSNORMAL) - nesting++; - } else if (c == CTLENDVAR) { - if (--nesting == 0) - break; - } - } - } - return p; -} - - -/* - * Perform variable and command substitution. If EXP_FULL is set, output CTLESC - * characters to allow for further processing. Otherwise treat - * $@ like $* since no splitting will be performed. - */ - -static void -argstr(p, flag) - char *p; - int flag; -{ - char c; - int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ - int firsteq = 1; - - if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE))) - p = exptilde(p, flag); - for (;;) { - switch (c = *p++) { - case '\0': - case CTLENDVAR: /* ??? */ - goto breakloop; - case CTLQUOTEMARK: - /* "$@" syntax adherence hack */ - if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=') - break; - if ((flag & EXP_FULL) != 0) - STPUTC(c, expdest); - break; - case CTLESC: - if (quotes) - STPUTC(c, expdest); - c = *p++; - STPUTC(c, expdest); - break; - case CTLVAR: - p = evalvar(p, flag); - break; - case CTLBACKQ: - case CTLBACKQ|CTLQUOTE: - expbackq(argbackq->n, c & CTLQUOTE, flag); - argbackq = argbackq->next; - break; -#ifdef ASH_MATH_SUPPORT - case CTLENDARI: - expari(flag); - break; -#endif - case ':': - case '=': - /* - * sort of a hack - expand tildes in variable - * assignments (after the first '=' and after ':'s). - */ - STPUTC(c, expdest); - if (flag & EXP_VARTILDE && *p == '~') { - if (c == '=') { - if (firsteq) - firsteq = 0; - else - break; - } - p = exptilde(p, flag); - } - break; - default: - STPUTC(c, expdest); - } - } -breakloop:; - return; -} - -static char * -exptilde(p, flag) - char *p; - int flag; -{ - char c, *startp = p; - struct passwd *pw; - const char *home; - int quotes = flag & (EXP_FULL | EXP_CASE); - - while ((c = *p) != '\0') { - switch(c) { - case CTLESC: - return (startp); - case CTLQUOTEMARK: - return (startp); - case ':': - if (flag & EXP_VARTILDE) - goto done; - break; - case '/': - goto done; - } - p++; - } -done: - *p = '\0'; - if (*(startp+1) == '\0') { - if ((home = lookupvar("HOME")) == NULL) - goto lose; - } else { - if ((pw = getpwnam(startp+1)) == NULL) - goto lose; - home = pw->pw_dir; - } - if (*home == '\0') - goto lose; - *p = c; - strtodest(home, SQSYNTAX, quotes); - return (p); -lose: - *p = c; - return (startp); -} - - -static void -removerecordregions(int endoff) -{ - if (ifslastp == NULL) - return; - - if (ifsfirst.endoff > endoff) { - while (ifsfirst.next != NULL) { - struct ifsregion *ifsp; - INTOFF; - ifsp = ifsfirst.next->next; - ckfree(ifsfirst.next); - ifsfirst.next = ifsp; - INTON; - } - if (ifsfirst.begoff > endoff) - ifslastp = NULL; - else { - ifslastp = &ifsfirst; - ifsfirst.endoff = endoff; - } - return; - } - - ifslastp = &ifsfirst; - while (ifslastp->next && ifslastp->next->begoff < endoff) - ifslastp=ifslastp->next; - while (ifslastp->next != NULL) { - struct ifsregion *ifsp; - INTOFF; - ifsp = ifslastp->next->next; - ckfree(ifslastp->next); - ifslastp->next = ifsp; - INTON; - } - if (ifslastp->endoff > endoff) - ifslastp->endoff = endoff; -} - - -#ifdef ASH_MATH_SUPPORT -/* - * Expand arithmetic expression. Backup to start of expression, - * evaluate, place result in (backed up) result, adjust string position. - */ -static void -expari(int flag) -{ - char *p, *start; - int errcode; - int result; - int begoff; - int quotes = flag & (EXP_FULL | EXP_CASE); - int quoted; - - /* ifsfree(); */ - - /* - * This routine is slightly over-complicated for - * efficiency. First we make sure there is - * enough space for the result, which may be bigger - * than the expression if we add exponentation. Next we - * scan backwards looking for the start of arithmetic. If the - * next previous character is a CTLESC character, then we - * have to rescan starting from the beginning since CTLESC - * characters have to be processed left to right. - */ - CHECKSTRSPACE(10, expdest); - USTPUTC('\0', expdest); - start = stackblock(); - p = expdest - 1; - while (*p != CTLARI && p >= start) - --p; - if (*p != CTLARI) - error("missing CTLARI (shouldn't happen)"); - if (p > start && *(p-1) == CTLESC) - for (p = start; *p != CTLARI; p++) - if (*p == CTLESC) - p++; - - if (p[1] == '"') - quoted=1; - else - quoted=0; - begoff = p - start; - removerecordregions(begoff); - if (quotes) - rmescapes(p+2); - result = arith(p+2, &errcode); - if (errcode < 0) { - if(errcode == -2) - error("divide by zero"); - else - error("syntax error: \"%s\"\n", p+2); - } - snprintf(p, 12, "%d", result); - - while (*p++) - ; - - if (quoted == 0) - recordregion(begoff, p - 1 - start, 0); - result = expdest - p + 1; - STADJUST(-result, expdest); -} -#endif - -/* - * Expand stuff in backwards quotes. - */ - -static void -expbackq(cmd, quoted, flag) - union node *cmd; - int quoted; - int flag; -{ - volatile struct backcmd in; - int i; - char buf[128]; - char *p; - char *dest = expdest; - volatile struct ifsregion saveifs; - struct ifsregion *volatile savelastp; - struct nodelist *volatile saveargbackq; - char lastc; - int startloc = dest - stackblock(); - char const *syntax = quoted? DQSYNTAX : BASESYNTAX; - volatile int saveherefd; - int quotes = flag & (EXP_FULL | EXP_CASE); - struct jmploc jmploc; - struct jmploc *volatile savehandler; - int ex; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &dest; - (void) &syntax; -#endif - - in.fd = -1; - in.buf = 0; - in.jp = 0; - - INTOFF; - saveifs = ifsfirst; - savelastp = ifslastp; - saveargbackq = argbackq; - saveherefd = herefd; - herefd = -1; - if ((ex = setjmp(jmploc.loc))) { - goto err1; - } - savehandler = handler; - handler = &jmploc; - INTON; - p = grabstackstr(dest); - evalbackcmd(cmd, (struct backcmd *) &in); - ungrabstackstr(p, dest); -err1: - INTOFF; - ifsfirst = saveifs; - ifslastp = savelastp; - argbackq = saveargbackq; - herefd = saveherefd; - if (ex) { - goto err2; - } - - p = in.buf; - lastc = '\0'; - for (;;) { - if (--in.nleft < 0) { - if (in.fd < 0) - break; - i = safe_read(in.fd, buf, sizeof buf); - TRACE(("expbackq: read returns %d\n", i)); - if (i <= 0) - break; - p = buf; - in.nleft = i - 1; - } - lastc = *p++; - if (lastc != '\0') { - if (quotes && syntax[(int)lastc] == CCTL) - STPUTC(CTLESC, dest); - STPUTC(lastc, dest); - } - } - - /* Eat all trailing newlines */ - for (; dest > stackblock() && dest[-1] == '\n';) - STUNPUTC(dest); - -err2: - if (in.fd >= 0) - close(in.fd); - if (in.buf) - ckfree(in.buf); - if (in.jp) - exitstatus = waitforjob(in.jp); - handler = savehandler; - if (ex) { - longjmp(handler->loc, 1); - } - if (quoted == 0) - recordregion(startloc, dest - stackblock(), 0); - TRACE(("evalbackq: size=%d: \"%.*s\"\n", - (dest - stackblock()) - startloc, - (dest - stackblock()) - startloc, - stackblock() + startloc)); - expdest = dest; - INTON; -} - -static int -subevalvar(p, str, strloc, subtype, startloc, varflags, quotes) - char *p; - char *str; - int strloc; - int subtype; - int startloc; - int varflags; - int quotes; -{ - char *startp; - char *loc = NULL; - char *q; - int c = 0; - int saveherefd = herefd; - struct nodelist *saveargbackq = argbackq; - int amount; - - herefd = -1; - argstr(p, subtype != VSASSIGN && subtype != VSQUESTION ? EXP_CASE : 0); - STACKSTRNUL(expdest); - herefd = saveherefd; - argbackq = saveargbackq; - startp = stackblock() + startloc; - if (str == NULL) - str = stackblock() + strloc; - - switch (subtype) { - case VSASSIGN: - setvar(str, startp, 0); - amount = startp - expdest; - STADJUST(amount, expdest); - varflags &= ~VSNUL; - if (c != 0) - *loc = c; - return 1; - - case VSQUESTION: - if (*p != CTLENDVAR) { - out2fmt(snlfmt, startp); - error((char *)NULL); - } - error("%.*s: parameter %snot set", p - str - 1, - str, (varflags & VSNUL) ? "null or " - : nullstr); - /* NOTREACHED */ - - case VSTRIMLEFT: - for (loc = startp; loc < str; loc++) { - c = *loc; - *loc = '\0'; - if (patmatch2(str, startp, quotes)) - goto recordleft; - *loc = c; - if (quotes && *loc == CTLESC) - loc++; - } - return 0; - - case VSTRIMLEFTMAX: - for (loc = str - 1; loc >= startp;) { - c = *loc; - *loc = '\0'; - if (patmatch2(str, startp, quotes)) - goto recordleft; - *loc = c; - loc--; - if (quotes && loc > startp && *(loc - 1) == CTLESC) { - for (q = startp; q < loc; q++) - if (*q == CTLESC) - q++; - if (q > loc) - loc--; - } - } - return 0; - - case VSTRIMRIGHT: - for (loc = str - 1; loc >= startp;) { - if (patmatch2(str, loc, quotes)) - goto recordright; - loc--; - if (quotes && loc > startp && *(loc - 1) == CTLESC) { - for (q = startp; q < loc; q++) - if (*q == CTLESC) - q++; - if (q > loc) - loc--; - } - } - return 0; - - case VSTRIMRIGHTMAX: - for (loc = startp; loc < str - 1; loc++) { - if (patmatch2(str, loc, quotes)) - goto recordright; - if (quotes && *loc == CTLESC) - loc++; - } - return 0; - -#ifdef DEBUG - default: - abort(); -#endif - } - -recordleft: - *loc = c; - amount = ((str - 1) - (loc - startp)) - expdest; - STADJUST(amount, expdest); - while (loc != str - 1) - *startp++ = *loc++; - return 1; - -recordright: - amount = loc - expdest; - STADJUST(amount, expdest); - STPUTC('\0', expdest); - STADJUST(-1, expdest); - return 1; -} - - -/* - * Test whether a specialized variable is set. - */ - -static int -varisset(name, nulok) - char *name; - int nulok; -{ - if (*name == '!') - return backgndpid != -1; - else if (*name == '@' || *name == '*') { - if (*shellparam.p == NULL) - return 0; - - if (nulok) { - char **av; - - for (av = shellparam.p; *av; av++) - if (**av != '\0') - return 1; - return 0; - } - } else if (is_digit(*name)) { - char *ap; - int num = atoi(name); - - if (num > shellparam.nparam) - return 0; - - if (num == 0) - ap = arg0; - else - ap = shellparam.p[num - 1]; - - if (nulok && (ap == NULL || *ap == '\0')) - return 0; - } - return 1; -} - -/* - * Put a string on the stack. - */ - -static void -strtodest(p, syntax, quotes) - const char *p; - const char *syntax; - int quotes; -{ - while (*p) { - if (quotes && syntax[(int) *p] == CCTL) - STPUTC(CTLESC, expdest); - STPUTC(*p++, expdest); - } -} - -/* - * Add the value of a specialized variable to the stack string. - */ - -static void -varvalue(name, quoted, flags) - char *name; - int quoted; - int flags; -{ - int num; - char *p; - int i; - int sep; - int sepq = 0; - char **ap; - char const *syntax; - int allow_split = flags & EXP_FULL; - int quotes = flags & (EXP_FULL | EXP_CASE); - - syntax = quoted ? DQSYNTAX : BASESYNTAX; - switch (*name) { - case '$': - num = rootpid; - goto numvar; - case '?': - num = oexitstatus; - goto numvar; - case '#': - num = shellparam.nparam; - goto numvar; - case '!': - num = backgndpid; -numvar: - expdest = cvtnum(num, expdest); - break; - case '-': - for (i = 0 ; i < NOPTS ; i++) { - if (optent_val(i)) - STPUTC(optent_letter(optlist[i]), expdest); - } - break; - case '@': - if (allow_split && quoted) { - sep = 1 << CHAR_BIT; - goto param; - } - /* fall through */ - case '*': - sep = ifsset() ? ifsval()[0] : ' '; - if (quotes) { - sepq = syntax[(int) sep] == CCTL; - } -param: - for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { - strtodest(p, syntax, quotes); - if (*ap && sep) { - if (sepq) - STPUTC(CTLESC, expdest); - STPUTC(sep, expdest); - } - } - break; - case '0': - strtodest(arg0, syntax, quotes); - break; - default: - num = atoi(name); - if (num > 0 && num <= shellparam.nparam) { - strtodest(shellparam.p[num - 1], syntax, quotes); - } - break; - } -} - - -/* - * Record the fact that we have to scan this region of the - * string for IFS characters. - */ - -static void -recordregion(start, end, nulonly) - int start; - int end; - int nulonly; -{ - struct ifsregion *ifsp; - - if (ifslastp == NULL) { - ifsp = &ifsfirst; - } else { - INTOFF; - ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); - ifsp->next = NULL; - ifslastp->next = ifsp; - INTON; - } - ifslastp = ifsp; - ifslastp->begoff = start; - ifslastp->endoff = end; - ifslastp->nulonly = nulonly; -} - - - -/* - * Break the argument string into pieces based upon IFS and add the - * strings to the argument list. The regions of the string to be - * searched for IFS characters have been stored by recordregion. - */ -static void -ifsbreakup(string, arglist) - char *string; - struct arglist *arglist; - { - struct ifsregion *ifsp; - struct strlist *sp; - char *start; - char *p; - char *q; - const char *ifs, *realifs; - int ifsspc; - int nulonly; - - - start = string; - ifsspc = 0; - nulonly = 0; - realifs = ifsset() ? ifsval() : defifs; - if (ifslastp != NULL) { - ifsp = &ifsfirst; - do { - p = string + ifsp->begoff; - nulonly = ifsp->nulonly; - ifs = nulonly ? nullstr : realifs; - ifsspc = 0; - while (p < string + ifsp->endoff) { - q = p; - if (*p == CTLESC) - p++; - if (strchr(ifs, *p)) { - if (!nulonly) - ifsspc = (strchr(defifs, *p) != NULL); - /* Ignore IFS whitespace at start */ - if (q == start && ifsspc) { - p++; - start = p; - continue; - } - *q = '\0'; - sp = (struct strlist *)stalloc(sizeof *sp); - sp->text = start; - *arglist->lastp = sp; - arglist->lastp = &sp->next; - p++; - if (!nulonly) { - for (;;) { - if (p >= string + ifsp->endoff) { - break; - } - q = p; - if (*p == CTLESC) - p++; - if (strchr(ifs, *p) == NULL ) { - p = q; - break; - } else if (strchr(defifs, *p) == NULL) { - if (ifsspc) { - p++; - ifsspc = 0; - } else { - p = q; - break; - } - } else - p++; - } - } - start = p; - } else - p++; - } - } while ((ifsp = ifsp->next) != NULL); - if (!(*start || (!ifsspc && start > string && nulonly))) { - return; - } - } - - sp = (struct strlist *)stalloc(sizeof *sp); - sp->text = start; - *arglist->lastp = sp; - arglist->lastp = &sp->next; -} - -static void -ifsfree() -{ - while (ifsfirst.next != NULL) { - struct ifsregion *ifsp; - INTOFF; - ifsp = ifsfirst.next->next; - ckfree(ifsfirst.next); - ifsfirst.next = ifsp; - INTON; - } - ifslastp = NULL; - ifsfirst.next = NULL; -} - -/* - * Add a file name to the list. - */ - -static void -addfname(const char *name) -{ - char *p; - struct strlist *sp; - - p = sstrdup(name); - sp = (struct strlist *)stalloc(sizeof *sp); - sp->text = p; - *exparg.lastp = sp; - exparg.lastp = &sp->next; -} - -/* - * Expand shell metacharacters. At this point, the only control characters - * should be escapes. The results are stored in the list exparg. - */ - -#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) -static void -expandmeta(str, flag) - struct strlist *str; - int flag; -{ - const char *p; - glob_t pglob; - /* TODO - EXP_REDIR */ - - while (str) { - if (fflag) - goto nometa; - p = preglob(str->text); - INTOFF; - switch (glob(p, 0, 0, &pglob)) { - case 0: - if(pglob.gl_pathv[1]==0 && !strcmp(p, pglob.gl_pathv[0])) - goto nometa2; - addglob(&pglob); - globfree(&pglob); - INTON; - break; - case GLOB_NOMATCH: -nometa2: - globfree(&pglob); - INTON; -nometa: - *exparg.lastp = str; - rmescapes(str->text); - exparg.lastp = &str->next; - break; - default: /* GLOB_NOSPACE */ - error("Out of space"); - } - str = str->next; - } -} - - -/* - * Add the result of glob(3) to the list. - */ - -static void -addglob(pglob) - const glob_t *pglob; -{ - char **p = pglob->gl_pathv; - - do { - addfname(*p); - } while (*++p); -} - - -#else /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */ -static char *expdir; - - -static void -expandmeta(str, flag) - struct strlist *str; - int flag; -{ - char *p; - struct strlist **savelastp; - struct strlist *sp; - char c; - /* TODO - EXP_REDIR */ - - while (str) { - if (fflag) - goto nometa; - p = str->text; - for (;;) { /* fast check for meta chars */ - if ((c = *p++) == '\0') - goto nometa; - if (c == '*' || c == '?' || c == '[' || c == '!') - break; - } - savelastp = exparg.lastp; - INTOFF; - if (expdir == NULL) { - int i = strlen(str->text); - expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ - } - - expmeta(expdir, str->text); - ckfree(expdir); - expdir = NULL; - INTON; - if (exparg.lastp == savelastp) { - /* - * no matches - */ -nometa: - *exparg.lastp = str; - rmescapes(str->text); - exparg.lastp = &str->next; - } else { - *exparg.lastp = NULL; - *savelastp = sp = expsort(*savelastp); - while (sp->next != NULL) - sp = sp->next; - exparg.lastp = &sp->next; - } - str = str->next; - } -} - - -/* - * Do metacharacter (i.e. *, ?, [...]) expansion. - */ - -static void -expmeta(enddir, name) - char *enddir; - char *name; - { - char *p; - const char *cp; - char *q; - char *start; - char *endname; - int metaflag; - struct stat statb; - DIR *dirp; - struct dirent *dp; - int atend; - int matchdot; - - metaflag = 0; - start = name; - for (p = name ; ; p++) { - if (*p == '*' || *p == '?') - metaflag = 1; - else if (*p == '[') { - q = p + 1; - if (*q == '!') - q++; - for (;;) { - while (*q == CTLQUOTEMARK) - q++; - if (*q == CTLESC) - q++; - if (*q == '/' || *q == '\0') - break; - if (*++q == ']') { - metaflag = 1; - break; - } - } - } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) { - metaflag = 1; - } else if (*p == '\0') - break; - else if (*p == CTLQUOTEMARK) - continue; - else if (*p == CTLESC) - p++; - if (*p == '/') { - if (metaflag) - break; - start = p + 1; - } - } - if (metaflag == 0) { /* we've reached the end of the file name */ - if (enddir != expdir) - metaflag++; - for (p = name ; ; p++) { - if (*p == CTLQUOTEMARK) - continue; - if (*p == CTLESC) - p++; - *enddir++ = *p; - if (*p == '\0') - break; - } - if (metaflag == 0 || lstat(expdir, &statb) >= 0) - addfname(expdir); - return; - } - endname = p; - if (start != name) { - p = name; - while (p < start) { - while (*p == CTLQUOTEMARK) - p++; - if (*p == CTLESC) - p++; - *enddir++ = *p++; - } - } - if (enddir == expdir) { - cp = "."; - } else if (enddir == expdir + 1 && *expdir == '/') { - cp = "/"; - } else { - cp = expdir; - enddir[-1] = '\0'; - } - if ((dirp = opendir(cp)) == NULL) - return; - if (enddir != expdir) - enddir[-1] = '/'; - if (*endname == 0) { - atend = 1; - } else { - atend = 0; - *endname++ = '\0'; - } - matchdot = 0; - p = start; - while (*p == CTLQUOTEMARK) - p++; - if (*p == CTLESC) - p++; - if (*p == '.') - matchdot++; - while (! int_pending() && (dp = readdir(dirp)) != NULL) { - if (dp->d_name[0] == '.' && ! matchdot) - continue; - if (patmatch(start, dp->d_name, 0)) { - if (atend) { - strcpy(enddir, dp->d_name); - addfname(expdir); - } else { - for (p = enddir, cp = dp->d_name; - (*p++ = *cp++) != '\0';) - continue; - p[-1] = '/'; - expmeta(p, endname); - } - } - } - closedir(dirp); - if (! atend) - endname[-1] = '/'; -} -#endif /* defined(__GLIBC__) && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN) */ - - - -#if !(defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) && !defined(GLOB_BROKEN)) -/* - * Sort the results of file name expansion. It calculates the number of - * strings to sort and then calls msort (short for merge sort) to do the - * work. - */ - -static struct strlist * -expsort(str) - struct strlist *str; - { - int len; - struct strlist *sp; - - len = 0; - for (sp = str ; sp ; sp = sp->next) - len++; - return msort(str, len); -} - - -static struct strlist * -msort(list, len) - struct strlist *list; - int len; -{ - struct strlist *p, *q = NULL; - struct strlist **lpp; - int half; - int n; - - if (len <= 1) - return list; - half = len >> 1; - p = list; - for (n = half ; --n >= 0 ; ) { - q = p; - p = p->next; - } - q->next = NULL; /* terminate first half of list */ - q = msort(list, half); /* sort first half of list */ - p = msort(p, len - half); /* sort second half */ - lpp = &list; - for (;;) { - if (strcmp(p->text, q->text) < 0) { - *lpp = p; - lpp = &p->next; - if ((p = *lpp) == NULL) { - *lpp = q; - break; - } - } else { - *lpp = q; - lpp = &q->next; - if ((q = *lpp) == NULL) { - *lpp = p; - break; - } - } - } - return list; -} -#endif - - - -/* - * Returns true if the pattern matches the string. - */ - -#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) -/* squoted: string might have quote chars */ -static int -patmatch(char *pattern, char *string, int squoted) -{ - const char *p; - char *q; - - p = preglob(pattern); - q = squoted ? _rmescapes(string, RMESCAPE_ALLOC) : string; - - return !fnmatch(p, q, 0); -} - - -static int -patmatch2(char *pattern, char *string, int squoted) -{ - char *p; - int res; - - sstrnleft--; - p = grabstackstr(expdest); - res = patmatch(pattern, string, squoted); - ungrabstackstr(p, expdest); - return res; -} -#else -static int -patmatch(char *pattern, char *string, int squoted) { - return pmatch(pattern, string, squoted); -} - - -static int -pmatch(char *pattern, char *string, int squoted) -{ - char *p, *q; - char c; - - p = pattern; - q = string; - for (;;) { - switch (c = *p++) { - case '\0': - goto breakloop; - case CTLESC: - if (squoted && *q == CTLESC) - q++; - if (*q++ != *p++) - return 0; - break; - case CTLQUOTEMARK: - continue; - case '?': - if (squoted && *q == CTLESC) - q++; - if (*q++ == '\0') - return 0; - break; - case '*': - c = *p; - while (c == CTLQUOTEMARK || c == '*') - c = *++p; - if (c != CTLESC && c != CTLQUOTEMARK && - c != '?' && c != '*' && c != '[') { - while (*q != c) { - if (squoted && *q == CTLESC && - q[1] == c) - break; - if (*q == '\0') - return 0; - if (squoted && *q == CTLESC) - q++; - q++; - } - } - do { - if (pmatch(p, q, squoted)) - return 1; - if (squoted && *q == CTLESC) - q++; - } while (*q++ != '\0'); - return 0; - case '[': { - char *endp; - int invert, found; - char chr; - - endp = p; - if (*endp == '!') - endp++; - for (;;) { - while (*endp == CTLQUOTEMARK) - endp++; - if (*endp == '\0') - goto dft; /* no matching ] */ - if (*endp == CTLESC) - endp++; - if (*++endp == ']') - break; - } - invert = 0; - if (*p == '!') { - invert++; - p++; - } - found = 0; - chr = *q++; - if (squoted && chr == CTLESC) - chr = *q++; - if (chr == '\0') - return 0; - c = *p++; - do { - if (c == CTLQUOTEMARK) - continue; - if (c == CTLESC) - c = *p++; - if (*p == '-' && p[1] != ']') { - p++; - while (*p == CTLQUOTEMARK) - p++; - if (*p == CTLESC) - p++; - if (chr >= c && chr <= *p) - found = 1; - p++; - } else { - if (chr == c) - found = 1; - } - } while ((c = *p++) != ']'); - if (found == invert) - return 0; - break; - } -dft: default: - if (squoted && *q == CTLESC) - q++; - if (*q++ != c) - return 0; - break; - } - } -breakloop: - if (*q != '\0') - return 0; - return 1; -} -#endif - - - -/* - * Remove any CTLESC characters from a string. - */ - -#if defined(__GLIBC__) && __GLIBC__ >= 2 && !defined(FNMATCH_BROKEN) -static char * -_rmescapes(char *str, int flag) -{ - char *p, *q, *r; - static const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 }; - - p = strpbrk(str, qchars); - if (!p) { - return str; - } - q = p; - r = str; - if (flag & RMESCAPE_ALLOC) { - size_t len = p - str; - q = r = stalloc(strlen(p) + len + 1); - if (len > 0) { - memcpy(q, str, len); - q += len; - } - } - while (*p) { - if (*p == CTLQUOTEMARK) { - p++; - continue; - } - if (*p == CTLESC) { - p++; - if (flag & RMESCAPE_GLOB && *p != '/') { - *q++ = '\\'; - } - } - *q++ = *p++; - } - *q = '\0'; - return r; -} -#else -static void -rmescapes(str) - char *str; -{ - char *p, *q; - - p = str; - while (*p != CTLESC && *p != CTLQUOTEMARK) { - if (*p++ == '\0') - return; - } - q = p; - while (*p) { - if (*p == CTLQUOTEMARK) { - p++; - continue; - } - if (*p == CTLESC) - p++; - *q++ = *p++; - } - *q = '\0'; -} -#endif - - - -/* - * See if a pattern matches in a case statement. - */ - -static int -casematch(union node *pattern, const char *val) -{ - struct stackmark smark; - int result; - char *p; - - setstackmark(&smark); - argbackq = pattern->narg.backquote; - STARTSTACKSTR(expdest); - ifslastp = NULL; - argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); - STPUTC('\0', expdest); - p = grabstackstr(expdest); - result = patmatch(p, (char *)val, 0); - popstackmark(&smark); - return result; -} - -/* - * Our own itoa(). - */ - -static char * -cvtnum(num, buf) - int num; - char *buf; - { - int len; - - CHECKSTRSPACE(32, buf); - len = sprintf(buf, "%d", num); - STADJUST(len, buf); - return buf; -} -/* - * Editline and history functions (and glue). - */ -static int histcmd(argc, argv) - int argc; - char **argv; -{ - error("not compiled with history support"); - /* NOTREACHED */ -} - - -struct redirtab { - struct redirtab *next; - short renamed[10]; /* Current ash support only 0-9 descriptors */ - /* char on arm (and others) can't be negative */ -}; - -static struct redirtab *redirlist; - -extern char **environ; - - - -/* - * Initialization code. - */ - -static void -init(void) { - - /* from cd.c: */ - { - setpwd(0, 0); - } - - /* from input.c: */ - { - basepf.nextc = basepf.buf = basebuf; - } - - /* from var.c: */ - { - char **envp; - char ppid[32]; - - initvar(); - for (envp = environ ; *envp ; envp++) { - if (strchr(*envp, '=')) { - setvareq(*envp, VEXPORT|VTEXTFIXED); - } - } - - snprintf(ppid, sizeof(ppid), "%d", (int) getppid()); - setvar("PPID", ppid, 0); - } -} - - - -/* - * This routine is called when an error or an interrupt occurs in an - * interactive shell and control is returned to the main command loop. - */ - -/* 1 == check for aliases, 2 == also check for assignments */ -static int checkalias; /* also used in no alias mode for check assignments */ - -static void -reset(void) { - - /* from eval.c: */ - { - evalskip = 0; - loopnest = 0; - funcnest = 0; - } - - /* from input.c: */ - { - if (exception != EXSHELLPROC) - parselleft = parsenleft = 0; /* clear input buffer */ - popallfiles(); - } - - /* from parser.c: */ - { - tokpushback = 0; - checkkwd = 0; - checkalias = 0; - } - - /* from redir.c: */ - { - while (redirlist) - popredir(); - } - -} - - - -/* - * This file implements the input routines used by the parser. - */ - -#ifdef BB_FEATURE_COMMAND_EDITING -static const char * cmdedit_prompt; -static inline void putprompt(const char *s) { - cmdedit_prompt = s; -} -#else -static inline void putprompt(const char *s) { - out2str(s); -} -#endif - -#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ - - - -/* - * Same as pgetc(), but ignores PEOA. - */ - -#ifdef ASH_ALIAS -static int -pgetc2() -{ - int c; - do { - c = pgetc_macro(); - } while (c == PEOA); - return c; -} -#else -static inline int pgetc2() { return pgetc_macro(); } -#endif - -/* - * Read a line from the script. - */ - -static inline char * -pfgets(char *line, int len) -{ - char *p = line; - int nleft = len; - int c; - - while (--nleft > 0) { - c = pgetc2(); - if (c == PEOF) { - if (p == line) - return NULL; - break; - } - *p++ = c; - if (c == '\n') - break; - } - *p = '\0'; - return line; -} - -static inline int -preadfd(void) -{ - int nr; - char *buf = parsefile->buf; - parsenextc = buf; - -retry: -#ifdef BB_FEATURE_COMMAND_EDITING - { - if (!iflag || parsefile->fd) - nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); - else { - nr = cmdedit_read_input((char*)cmdedit_prompt, buf); - } - } -#else - nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); -#endif - - if (nr < 0) { - if (parsefile->fd == 0 && errno == EWOULDBLOCK) { - int flags = fcntl(0, F_GETFL, 0); - if (flags >= 0 && flags & O_NONBLOCK) { - flags &=~ O_NONBLOCK; - if (fcntl(0, F_SETFL, flags) >= 0) { - out2str("sh: turning off NDELAY mode\n"); - goto retry; - } - } - } - } - return nr; -} - -static void -popstring(void) -{ - struct strpush *sp = parsefile->strpush; - - INTOFF; -#ifdef ASH_ALIAS - if (sp->ap) { - if (parsenextc[-1] == ' ' || parsenextc[-1] == '\t') { - if (!checkalias) { - checkalias = 1; - } - } - if (sp->string != sp->ap->val) { - ckfree(sp->string); - } - - sp->ap->flag &= ~ALIASINUSE; - if (sp->ap->flag & ALIASDEAD) { - unalias(sp->ap->name); - } - } -#endif - parsenextc = sp->prevstring; - parsenleft = sp->prevnleft; -/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ - parsefile->strpush = sp->prev; - if (sp != &(parsefile->basestrpush)) - ckfree(sp); - INTON; -} - - -/* - * Refill the input buffer and return the next input character: - * - * 1) If a string was pushed back on the input, pop it; - * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading - * from a string so we can't refill the buffer, return EOF. - * 3) If the is more stuff in this buffer, use it else call read to fill it. - * 4) Process input up to the next newline, deleting nul characters. - */ - -static int -preadbuffer(void) -{ - char *p, *q; - int more; - char savec; - - while (parsefile->strpush) { -#ifdef ASH_ALIAS - if (parsenleft == -1 && parsefile->strpush->ap && - parsenextc[-1] != ' ' && parsenextc[-1] != '\t') { - return PEOA; - } -#endif - popstring(); - if (--parsenleft >= 0) - return (*parsenextc++); - } - if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) - return PEOF; - flushall(); - -again: - if (parselleft <= 0) { - if ((parselleft = preadfd()) <= 0) { - parselleft = parsenleft = EOF_NLEFT; - return PEOF; - } - } - - q = p = parsenextc; - - /* delete nul characters */ - for (more = 1; more;) { - switch (*p) { - case '\0': - p++; /* Skip nul */ - goto check; - - - case '\n': - parsenleft = q - parsenextc; - more = 0; /* Stop processing here */ - break; - } - - *q++ = *p++; -check: - if (--parselleft <= 0 && more) { - parsenleft = q - parsenextc - 1; - if (parsenleft < 0) - goto again; - more = 0; - } - } - - savec = *q; - *q = '\0'; - - if (vflag) { - out2str(parsenextc); - } - - *q = savec; - - return *parsenextc++; -} - - -/* - * Push a string back onto the input at this current parsefile level. - * We handle aliases this way. - */ -static void -pushstring(char *s, int len, void *ap) -{ - struct strpush *sp; - - INTOFF; -/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ - if (parsefile->strpush) { - sp = ckmalloc(sizeof (struct strpush)); - sp->prev = parsefile->strpush; - parsefile->strpush = sp; - } else - sp = parsefile->strpush = &(parsefile->basestrpush); - sp->prevstring = parsenextc; - sp->prevnleft = parsenleft; -#ifdef ASH_ALIAS - sp->ap = (struct alias *)ap; - if (ap) { - ((struct alias *)ap)->flag |= ALIASINUSE; - sp->string = s; - } -#endif - parsenextc = s; - parsenleft = len; - INTON; -} - - -/* - * Like setinputfile, but takes input from a string. - */ - -static void -setinputstring(char *string) -{ - INTOFF; - pushfile(); - parsenextc = string; - parsenleft = strlen(string); - parsefile->buf = NULL; - plinno = 1; - INTON; -} - - - -/* - * To handle the "." command, a stack of input files is used. Pushfile - * adds a new entry to the stack and popfile restores the previous level. - */ - -static void -pushfile(void) { - struct parsefile *pf; - - parsefile->nleft = parsenleft; - parsefile->lleft = parselleft; - parsefile->nextc = parsenextc; - parsefile->linno = plinno; - pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); - pf->prev = parsefile; - pf->fd = -1; - pf->strpush = NULL; - pf->basestrpush.prev = NULL; - parsefile = pf; -} - -#ifdef JOBS -static void restartjob (struct job *); -#endif -static void freejob (struct job *); -static struct job *getjob (const char *); -static int dowait (int, struct job *); -static void waitonint(int); - - -/* - * We keep track of whether or not fd0 has been redirected. This is for - * background commands, where we want to redirect fd0 to /dev/null only - * if it hasn't already been redirected. -*/ -static int fd0_redirected = 0; - -/* Return true if fd 0 has already been redirected at least once. */ -static inline int -fd0_redirected_p () { - return fd0_redirected != 0; -} - -static void dupredirect (const union node *, int, int fd1dup); - -#ifdef JOBS -/* - * Turn job control on and off. - * - * Note: This code assumes that the third arg to ioctl is a character - * pointer, which is true on Berkeley systems but not System V. Since - * System V doesn't have job control yet, this isn't a problem now. - */ - - - -static void setjobctl(int enable) -{ -#ifdef OLD_TTY_DRIVER - int ldisc; -#endif - - if (enable == jobctl || rootshell == 0) - return; - if (enable) { - do { /* while we are in the background */ -#ifdef OLD_TTY_DRIVER - if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) { -#else - initialpgrp = tcgetpgrp(2); - if (initialpgrp < 0) { -#endif - out2str("sh: can't access tty; job control turned off\n"); - mflag = 0; - return; - } - if (initialpgrp == -1) - initialpgrp = getpgrp(); - else if (initialpgrp != getpgrp()) { - killpg(initialpgrp, SIGTTIN); - continue; - } - } while (0); -#ifdef OLD_TTY_DRIVER - if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) { - out2str("sh: need new tty driver to run job control; job control turned off\n"); - mflag = 0; - return; - } -#endif - setsignal(SIGTSTP); - setsignal(SIGTTOU); - setsignal(SIGTTIN); - setpgid(0, rootpid); -#ifdef OLD_TTY_DRIVER - ioctl(2, TIOCSPGRP, (char *)&rootpid); -#else - tcsetpgrp(2, rootpid); -#endif - } else { /* turning job control off */ - setpgid(0, initialpgrp); -#ifdef OLD_TTY_DRIVER - ioctl(2, TIOCSPGRP, (char *)&initialpgrp); -#else - tcsetpgrp(2, initialpgrp); -#endif - setsignal(SIGTSTP); - setsignal(SIGTTOU); - setsignal(SIGTTIN); - } - jobctl = enable; -} -#endif - - -#ifdef JOBS -static int -killcmd(argc, argv) - int argc; - char **argv; -{ - int signo = -1; - int list = 0; - int i; - pid_t pid; - struct job *jp; - - if (argc <= 1) { -usage: - error( -"Usage: kill [-s sigspec | -signum | -sigspec] [pid | job]... or\n" -"kill -l [exitstatus]" - ); - } - - if (*argv[1] == '-') { - signo = decode_signal(argv[1] + 1, 1); - if (signo < 0) { - int c; - - while ((c = nextopt("ls:")) != '\0') - switch (c) { - case 'l': - list = 1; - break; - case 's': - signo = decode_signal(optionarg, 1); - if (signo < 0) { - error( - "invalid signal number or name: %s", - optionarg - ); - } - break; -#ifdef DEBUG - default: - error( - "nextopt returned character code 0%o", c); -#endif - } - } else - argptr++; - } - - if (!list && signo < 0) - signo = SIGTERM; - - if ((signo < 0 || !*argptr) ^ list) { - goto usage; - } - - if (list) { - const char *name; - - if (!*argptr) { - out1str("0\n"); - for (i = 1; i < NSIG; i++) { - name = u_signal_names(0, &i, 1); - if(name) - printf(snlfmt, name); - } - return 0; - } - name = u_signal_names(*argptr, &signo, -1); - if (name) - printf(snlfmt, name); - else - error("invalid signal number or exit status: %s", - *argptr); - return 0; - } - - do { - if (**argptr == '%') { - jp = getjob(*argptr); - if (jp->jobctl == 0) - error("job %s not created under job control", - *argptr); - pid = -jp->ps[0].pid; - } else - pid = atoi(*argptr); - if (kill(pid, signo) != 0) - error("%s: %m", *argptr); - } while (*++argptr); - - return 0; -} - -static int -fgcmd(argc, argv) - int argc; - char **argv; -{ - struct job *jp; - int pgrp; - int status; - - jp = getjob(argv[1]); - if (jp->jobctl == 0) - error("job not created under job control"); - pgrp = jp->ps[0].pid; -#ifdef OLD_TTY_DRIVER - ioctl(2, TIOCSPGRP, (char *)&pgrp); -#else - tcsetpgrp(2, pgrp); -#endif - restartjob(jp); - INTOFF; - status = waitforjob(jp); - INTON; - return status; -} - - -static int -bgcmd(argc, argv) - int argc; - char **argv; -{ - struct job *jp; - - do { - jp = getjob(*++argv); - if (jp->jobctl == 0) - error("job not created under job control"); - restartjob(jp); - } while (--argc > 1); - return 0; -} - - -static void -restartjob(jp) - struct job *jp; -{ - struct procstat *ps; - int i; - - if (jp->state == JOBDONE) - return; - INTOFF; - killpg(jp->ps[0].pid, SIGCONT); - for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) { - if (WIFSTOPPED(ps->status)) { - ps->status = -1; - jp->state = 0; - } - } - INTON; -} -#endif - -static void showjobs(int change); - - -static int -jobscmd(argc, argv) - int argc; - char **argv; -{ - showjobs(0); - return 0; -} - - -/* - * Print a list of jobs. If "change" is nonzero, only print jobs whose - * statuses have changed since the last call to showjobs. - * - * If the shell is interrupted in the process of creating a job, the - * result may be a job structure containing zero processes. Such structures - * will be freed here. - */ - -static void -showjobs(change) - int change; -{ - int jobno; - int procno; - int i; - struct job *jp; - struct procstat *ps; - int col; - char s[64]; - - TRACE(("showjobs(%d) called\n", change)); - while (dowait(0, (struct job *)NULL) > 0); - for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) { - if (! jp->used) - continue; - if (jp->nprocs == 0) { - freejob(jp); - continue; - } - if (change && ! jp->changed) - continue; - procno = jp->nprocs; - for (ps = jp->ps ; ; ps++) { /* for each process */ - if (ps == jp->ps) - snprintf(s, 64, "[%d] %ld ", jobno, - (long)ps->pid); - else - snprintf(s, 64, " %ld ", - (long)ps->pid); - out1str(s); - col = strlen(s); - s[0] = '\0'; - if (ps->status == -1) { - /* don't print anything */ - } else if (WIFEXITED(ps->status)) { - snprintf(s, 64, "Exit %d", - WEXITSTATUS(ps->status)); - } else { -#ifdef JOBS - if (WIFSTOPPED(ps->status)) - i = WSTOPSIG(ps->status); - else /* WIFSIGNALED(ps->status) */ -#endif - i = WTERMSIG(ps->status); - if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F]) - strcpy(s, sys_siglist[i & 0x7F]); - else - snprintf(s, 64, "Signal %d", i & 0x7F); - if (WCOREDUMP(ps->status)) - strcat(s, " (core dumped)"); - } - out1str(s); - col += strlen(s); - printf( - "%*c%s\n", 30 - col >= 0 ? 30 - col : 0, ' ', - ps->cmd - ); - if (--procno <= 0) - break; - } - jp->changed = 0; - if (jp->state == JOBDONE) { - freejob(jp); - } - } -} - - -/* - * Mark a job structure as unused. - */ - -static void -freejob(struct job *jp) -{ - const struct procstat *ps; - int i; - - INTOFF; - for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) { - if (ps->cmd != nullstr) - ckfree(ps->cmd); - } - if (jp->ps != &jp->ps0) - ckfree(jp->ps); - jp->used = 0; -#ifdef JOBS - if (curjob == jp - jobtab + 1) - curjob = 0; -#endif - INTON; -} - - - -static int -waitcmd(argc, argv) - int argc; - char **argv; -{ - struct job *job; - int status, retval; - struct job *jp; - - if (--argc > 0) { -start: - job = getjob(*++argv); - } else { - job = NULL; - } - for (;;) { /* loop until process terminated or stopped */ - if (job != NULL) { - if (job->state) { - status = job->ps[job->nprocs - 1].status; - if (! iflag) - freejob(job); - if (--argc) { - goto start; - } - if (WIFEXITED(status)) - retval = WEXITSTATUS(status); -#ifdef JOBS - else if (WIFSTOPPED(status)) - retval = WSTOPSIG(status) + 128; -#endif - else { - /* XXX: limits number of signals */ - retval = WTERMSIG(status) + 128; - } - return retval; - } - } else { - for (jp = jobtab ; ; jp++) { - if (jp >= jobtab + njobs) { /* no running procs */ - return 0; - } - if (jp->used && jp->state == 0) - break; - } - } - if (dowait(2, 0) < 0 && errno == EINTR) { - return 129; - } - } -} - - - -/* - * Convert a job name to a job structure. - */ - -static struct job * -getjob(const char *name) -{ - int jobno; - struct job *jp; - int pid; - int i; - - if (name == NULL) { -#ifdef JOBS -currentjob: - if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0) - error("No current job"); - return &jobtab[jobno - 1]; -#else - error("No current job"); -#endif - } else if (name[0] == '%') { - if (is_digit(name[1])) { - jobno = number(name + 1); - if (jobno > 0 && jobno <= njobs - && jobtab[jobno - 1].used != 0) - return &jobtab[jobno - 1]; -#ifdef JOBS - } else if (name[1] == '%' && name[2] == '\0') { - goto currentjob; -#endif - } else { - struct job *found = NULL; - for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { - if (jp->used && jp->nprocs > 0 - && prefix(name + 1, jp->ps[0].cmd)) { - if (found) - error("%s: ambiguous", name); - found = jp; - } - } - if (found) - return found; - } - } else if (is_number(name, &pid)) { - for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { - if (jp->used && jp->nprocs > 0 - && jp->ps[jp->nprocs - 1].pid == pid) - return jp; - } - } - error("No such job: %s", name); - /* NOTREACHED */ -} - - - -/* - * Return a new job structure, - */ - -static struct job * -makejob(const union node *node, int nprocs) -{ - int i; - struct job *jp; - - for (i = njobs, jp = jobtab ; ; jp++) { - if (--i < 0) { - INTOFF; - if (njobs == 0) { - jobtab = ckmalloc(4 * sizeof jobtab[0]); - } else { - jp = ckmalloc((njobs + 4) * sizeof jobtab[0]); - memcpy(jp, jobtab, njobs * sizeof jp[0]); - /* Relocate `ps' pointers */ - for (i = 0; i < njobs; i++) - if (jp[i].ps == &jobtab[i].ps0) - jp[i].ps = &jp[i].ps0; - ckfree(jobtab); - jobtab = jp; - } - jp = jobtab + njobs; - for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0); - INTON; - break; - } - if (jp->used == 0) - break; - } - INTOFF; - jp->state = 0; - jp->used = 1; - jp->changed = 0; - jp->nprocs = 0; -#ifdef JOBS - jp->jobctl = jobctl; -#endif - if (nprocs > 1) { - jp->ps = ckmalloc(nprocs * sizeof (struct procstat)); - } else { - jp->ps = &jp->ps0; - } - INTON; - TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs, - jp - jobtab + 1)); - return jp; -} - - -/* - * Fork of a subshell. If we are doing job control, give the subshell its - * own process group. Jp is a job structure that the job is to be added to. - * N is the command that will be evaluated by the child. Both jp and n may - * be NULL. The mode parameter can be one of the following: - * FORK_FG - Fork off a foreground process. - * FORK_BG - Fork off a background process. - * FORK_NOJOB - Like FORK_FG, but don't give the process its own - * process group even if job control is on. - * - * When job control is turned off, background processes have their standard - * input redirected to /dev/null (except for the second and later processes - * in a pipeline). - */ - - - -static int -forkshell(struct job *jp, const union node *n, int mode) -{ - int pid; -#ifdef JOBS - int pgrp; -#endif - const char *devnull = _PATH_DEVNULL; - const char *nullerr = "Can't open %s"; - - TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n, - mode)); - INTOFF; - pid = fork(); - if (pid == -1) { - TRACE(("Fork failed, errno=%d\n", errno)); - INTON; - error("Cannot fork"); - } - if (pid == 0) { - struct job *p; - int wasroot; - int i; - - TRACE(("Child shell %d\n", getpid())); - wasroot = rootshell; - rootshell = 0; - closescript(); - INTON; - clear_traps(); -#ifdef JOBS - jobctl = 0; /* do job control only in root shell */ - if (wasroot && mode != FORK_NOJOB && mflag) { - if (jp == NULL || jp->nprocs == 0) - pgrp = getpid(); - else - pgrp = jp->ps[0].pid; - setpgid(0, pgrp); - if (mode == FORK_FG) { - /*** this causes superfluous TIOCSPGRPS ***/ -#ifdef OLD_TTY_DRIVER - if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0) - error("TIOCSPGRP failed, errno=%d", errno); -#else - if (tcsetpgrp(2, pgrp) < 0) - error("tcsetpgrp failed, errno=%d", errno); -#endif - } - setsignal(SIGTSTP); - setsignal(SIGTTOU); - } else if (mode == FORK_BG) { - ignoresig(SIGINT); - ignoresig(SIGQUIT); - if ((jp == NULL || jp->nprocs == 0) && - ! fd0_redirected_p ()) { - close(0); - if (open(devnull, O_RDONLY) != 0) - error(nullerr, devnull); - } - } -#else - if (mode == FORK_BG) { - ignoresig(SIGINT); - ignoresig(SIGQUIT); - if ((jp == NULL || jp->nprocs == 0) && - ! fd0_redirected_p ()) { - close(0); - if (open(devnull, O_RDONLY) != 0) - error(nullerr, devnull); - } - } -#endif - for (i = njobs, p = jobtab ; --i >= 0 ; p++) - if (p->used) - freejob(p); - if (wasroot && iflag) { - setsignal(SIGINT); - setsignal(SIGQUIT); - setsignal(SIGTERM); - } - return pid; - } -#ifdef JOBS - if (rootshell && mode != FORK_NOJOB && mflag) { - if (jp == NULL || jp->nprocs == 0) - pgrp = pid; - else - pgrp = jp->ps[0].pid; - setpgid(pid, pgrp); - } -#endif - if (mode == FORK_BG) - backgndpid = pid; /* set $! */ - if (jp) { - struct procstat *ps = &jp->ps[jp->nprocs++]; - ps->pid = pid; - ps->status = -1; - ps->cmd = nullstr; - if (iflag && rootshell && n) - ps->cmd = commandtext(n); - } - INTON; - TRACE(("In parent shell: child = %d\n", pid)); - return pid; -} - - - -/* - * Wait for job to finish. - * - * Under job control we have the problem that while a child process is - * running interrupts generated by the user are sent to the child but not - * to the shell. This means that an infinite loop started by an inter- - * active user may be hard to kill. With job control turned off, an - * interactive user may place an interactive program inside a loop. If - * the interactive program catches interrupts, the user doesn't want - * these interrupts to also abort the loop. The approach we take here - * is to have the shell ignore interrupt signals while waiting for a - * forground process to terminate, and then send itself an interrupt - * signal if the child process was terminated by an interrupt signal. - * Unfortunately, some programs want to do a bit of cleanup and then - * exit on interrupt; unless these processes terminate themselves by - * sending a signal to themselves (instead of calling exit) they will - * confuse this approach. - */ - -static int -waitforjob(struct job *jp) -{ -#ifdef JOBS - int mypgrp = getpgrp(); -#endif - int status; - int st; - struct sigaction act, oact; - - INTOFF; - intreceived = 0; -#ifdef JOBS - if (!jobctl) { -#else - if (!iflag) { -#endif - sigaction(SIGINT, 0, &act); - act.sa_handler = waitonint; - sigaction(SIGINT, &act, &oact); - } - TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1)); - while (jp->state == 0) { - dowait(1, jp); - } -#ifdef JOBS - if (!jobctl) { -#else - if (!iflag) { -#endif - sigaction(SIGINT, &oact, 0); - if (intreceived && trap[SIGINT]) kill(getpid(), SIGINT); - } -#ifdef JOBS - if (jp->jobctl) { -#ifdef OLD_TTY_DRIVER - if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0) - error("TIOCSPGRP failed, errno=%d\n", errno); -#else - if (tcsetpgrp(2, mypgrp) < 0) - error("tcsetpgrp failed, errno=%d\n", errno); -#endif - } - if (jp->state == JOBSTOPPED) - curjob = jp - jobtab + 1; -#endif - status = jp->ps[jp->nprocs - 1].status; - /* convert to 8 bits */ - if (WIFEXITED(status)) - st = WEXITSTATUS(status); -#ifdef JOBS - else if (WIFSTOPPED(status)) - st = WSTOPSIG(status) + 128; -#endif - else - st = WTERMSIG(status) + 128; -#ifdef JOBS - if (jp->jobctl) { - /* - * This is truly gross. - * If we're doing job control, then we did a TIOCSPGRP which - * caused us (the shell) to no longer be in the controlling - * session -- so we wouldn't have seen any ^C/SIGINT. So, we - * intuit from the subprocess exit status whether a SIGINT - * occured, and if so interrupt ourselves. Yuck. - mycroft - */ - if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) - raise(SIGINT); - } - if (jp->state == JOBDONE) - -#endif - freejob(jp); - INTON; - return st; -} - - - -/* - * Wait for a process to terminate. - */ - -/* - * Do a wait system call. If job control is compiled in, we accept - * stopped processes. If block is zero, we return a value of zero - * rather than blocking. - * - * System V doesn't have a non-blocking wait system call. It does - * have a SIGCLD signal that is sent to a process when one of it's - * children dies. The obvious way to use SIGCLD would be to install - * a handler for SIGCLD which simply bumped a counter when a SIGCLD - * was received, and have waitproc bump another counter when it got - * the status of a process. Waitproc would then know that a wait - * system call would not block if the two counters were different. - * This approach doesn't work because if a process has children that - * have not been waited for, System V will send it a SIGCLD when it - * installs a signal handler for SIGCLD. What this means is that when - * a child exits, the shell will be sent SIGCLD signals continuously - * until is runs out of stack space, unless it does a wait call before - * restoring the signal handler. The code below takes advantage of - * this (mis)feature by installing a signal handler for SIGCLD and - * then checking to see whether it was called. If there are any - * children to be waited for, it will be. - * - */ - -static inline int -waitproc(int block, int *status) -{ - int flags; - - flags = 0; -#ifdef JOBS - if (jobctl) - flags |= WUNTRACED; -#endif - if (block == 0) - flags |= WNOHANG; - return wait3(status, flags, (struct rusage *)NULL); -} - -static int -dowait(int block, struct job *job) -{ - int pid; - int status; - struct procstat *sp; - struct job *jp; - struct job *thisjob; - int done; - int stopped; - int core; - int sig; - - TRACE(("dowait(%d) called\n", block)); - do { - pid = waitproc(block, &status); - TRACE(("wait returns %d, status=%d\n", pid, status)); - } while (!(block & 2) && pid == -1 && errno == EINTR); - if (pid <= 0) - return pid; - INTOFF; - thisjob = NULL; - for (jp = jobtab ; jp < jobtab + njobs ; jp++) { - if (jp->used) { - done = 1; - stopped = 1; - for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) { - if (sp->pid == -1) - continue; - if (sp->pid == pid) { - TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status)); - sp->status = status; - thisjob = jp; - } - if (sp->status == -1) - stopped = 0; - else if (WIFSTOPPED(sp->status)) - done = 0; - } - if (stopped) { /* stopped or done */ - int state = done? JOBDONE : JOBSTOPPED; - if (jp->state != state) { - TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state)); - jp->state = state; -#ifdef JOBS - if (done && curjob == jp - jobtab + 1) - curjob = 0; /* no current job */ -#endif - } - } - } - } - INTON; - if (! rootshell || ! iflag || (job && thisjob == job)) { - core = WCOREDUMP(status); -#ifdef JOBS - if (WIFSTOPPED(status)) sig = WSTOPSIG(status); - else -#endif - if (WIFEXITED(status)) sig = 0; - else sig = WTERMSIG(status); - - if (sig != 0 && sig != SIGINT && sig != SIGPIPE) { - if (thisjob != job) - out2fmt("%d: ", pid); -#ifdef JOBS - if (sig == SIGTSTP && rootshell && iflag) - out2fmt("%%%ld ", - (long)(job - jobtab + 1)); -#endif - if (sig < NSIG && sys_siglist[sig]) - out2str(sys_siglist[sig]); - else - out2fmt("Signal %d", sig); - if (core) - out2str(" - core dumped"); - out2c('\n'); - } else { - TRACE(("Not printing status: status=%d, sig=%d\n", - status, sig)); - } - } else { - TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job)); - if (thisjob) - thisjob->changed = 1; - } - return pid; -} - - - - -/* - * return 1 if there are stopped jobs, otherwise 0 - */ -static int -stoppedjobs(void) -{ - int jobno; - struct job *jp; - - if (job_warning) - return (0); - for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) { - if (jp->used == 0) - continue; - if (jp->state == JOBSTOPPED) { - out2str("You have stopped jobs.\n"); - job_warning = 2; - return (1); - } - } - - return (0); -} - -/* - * Return a string identifying a command (to be printed by the - * jobs command. - */ - -static char *cmdnextc; -static int cmdnleft; -#define MAXCMDTEXT 200 - -static void -cmdputs(const char *s) -{ - const char *p; - char *q; - char c; - int subtype = 0; - - if (cmdnleft <= 0) - return; - p = s; - q = cmdnextc; - while ((c = *p++) != '\0') { - if (c == CTLESC) - *q++ = *p++; - else if (c == CTLVAR) { - *q++ = '$'; - if (--cmdnleft > 0) - *q++ = '{'; - subtype = *p++; - } else if (c == '=' && subtype != 0) { - *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL]; - subtype = 0; - } else if (c == CTLENDVAR) { - *q++ = '}'; - } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) - cmdnleft++; /* ignore it */ - else - *q++ = c; - if (--cmdnleft <= 0) { - *q++ = '.'; - *q++ = '.'; - *q++ = '.'; - break; - } - } - cmdnextc = q; -} - - -static void -cmdtxt(const union node *n) -{ - union node *np; - struct nodelist *lp; - const char *p; - int i; - char s[2]; - - if (n == NULL) - return; - switch (n->type) { - case NSEMI: - cmdtxt(n->nbinary.ch1); - cmdputs("; "); - cmdtxt(n->nbinary.ch2); - break; - case NAND: - cmdtxt(n->nbinary.ch1); - cmdputs(" && "); - cmdtxt(n->nbinary.ch2); - break; - case NOR: - cmdtxt(n->nbinary.ch1); - cmdputs(" || "); - cmdtxt(n->nbinary.ch2); - break; - case NPIPE: - for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { - cmdtxt(lp->n); - if (lp->next) - cmdputs(" | "); - } - break; - case NSUBSHELL: - cmdputs("("); - cmdtxt(n->nredir.n); - cmdputs(")"); - break; - case NREDIR: - case NBACKGND: - cmdtxt(n->nredir.n); - break; - case NIF: - cmdputs("if "); - cmdtxt(n->nif.test); - cmdputs("; then "); - cmdtxt(n->nif.ifpart); - cmdputs("..."); - break; - case NWHILE: - cmdputs("while "); - goto until; - case NUNTIL: - cmdputs("until "); -until: - cmdtxt(n->nbinary.ch1); - cmdputs("; do "); - cmdtxt(n->nbinary.ch2); - cmdputs("; done"); - break; - case NFOR: - cmdputs("for "); - cmdputs(n->nfor.var); - cmdputs(" in ..."); - break; - case NCASE: - cmdputs("case "); - cmdputs(n->ncase.expr->narg.text); - cmdputs(" in ..."); - break; - case NDEFUN: - cmdputs(n->narg.text); - cmdputs("() ..."); - break; - case NCMD: - for (np = n->ncmd.args ; np ; np = np->narg.next) { - cmdtxt(np); - if (np->narg.next) - cmdputs(spcstr); - } - for (np = n->ncmd.redirect ; np ; np = np->nfile.next) { - cmdputs(spcstr); - cmdtxt(np); - } - break; - case NARG: - cmdputs(n->narg.text); - break; - case NTO: - p = ">"; i = 1; goto redir; - case NAPPEND: - p = ">>"; i = 1; goto redir; - case NTOFD: - p = ">&"; i = 1; goto redir; - case NTOOV: - p = ">|"; i = 1; goto redir; - case NFROM: - p = "<"; i = 0; goto redir; - case NFROMFD: - p = "<&"; i = 0; goto redir; - case NFROMTO: - p = "<>"; i = 0; goto redir; -redir: - if (n->nfile.fd != i) { - s[0] = n->nfile.fd + '0'; - s[1] = '\0'; - cmdputs(s); - } - cmdputs(p); - if (n->type == NTOFD || n->type == NFROMFD) { - s[0] = n->ndup.dupfd + '0'; - s[1] = '\0'; - cmdputs(s); - } else { - cmdtxt(n->nfile.fname); - } - break; - case NHERE: - case NXHERE: - cmdputs("<<..."); - break; - default: - cmdputs("???"); - break; - } -} - - -static char * -commandtext(const union node *n) -{ - char *name; - - cmdnextc = name = ckmalloc(MAXCMDTEXT); - cmdnleft = MAXCMDTEXT - 4; - cmdtxt(n); - *cmdnextc = '\0'; - return name; -} - - -static void waitonint(int sig) { - intreceived = 1; - return; -} -/* - * Routines to check for mail. (Perhaps make part of main.c?) - */ - - -#define MAXMBOXES 10 - - -static int nmboxes; /* number of mailboxes */ -static time_t mailtime[MAXMBOXES]; /* times of mailboxes */ - - - -/* - * Print appropriate message(s) if mail has arrived. If the argument is - * nozero, then the value of MAIL has changed, so we just update the - * values. - */ - -static void -chkmail(int silent) -{ - int i; - const char *mpath; - char *p; - char *q; - struct stackmark smark; - struct stat statb; - - if (silent) - nmboxes = 10; - if (nmboxes == 0) - return; - setstackmark(&smark); - mpath = mpathset()? mpathval() : mailval(); - for (i = 0 ; i < nmboxes ; i++) { - p = padvance(&mpath, nullstr); - if (p == NULL) - break; - if (*p == '\0') - continue; - for (q = p ; *q ; q++); -#ifdef DEBUG - if (q[-1] != '/') - abort(); -#endif - q[-1] = '\0'; /* delete trailing '/' */ - if (stat(p, &statb) < 0) - statb.st_size = 0; - if (statb.st_size > mailtime[i] && ! silent) { - out2fmt(snlfmt, - pathopt? pathopt : "you have mail"); - } - mailtime[i] = statb.st_size; - } - nmboxes = i; - popstackmark(&smark); -} - -#define PROFILE 0 - -#if PROFILE -static short profile_buf[16384]; -extern int etext(); -#endif - -static void read_profile (const char *); -static void cmdloop (int); -static void options (int); -static void setoption (int, int); -static void procargs (int, char **); - - -/* - * Main routine. We initialize things, parse the arguments, execute - * profiles if we're a login shell, and then call cmdloop to execute - * commands. The setjmp call sets up the location to jump to when an - * exception occurs. When an exception occurs the variable "state" - * is used to figure out how far we had gotten. - */ - -int -ash_main(argc, argv) - int argc; - char **argv; -{ - struct jmploc jmploc; - struct stackmark smark; - volatile int state; - const char *shinit; - - BLTINCMD = find_builtin("builtin"); - EXECCMD = find_builtin("exec"); - EVALCMD = find_builtin("eval"); - -#ifndef BB_FEATURE_SH_FANCY_PROMPT - unsetenv("PS1"); - unsetenv("PS2"); -#endif - -#if PROFILE - monitor(4, etext, profile_buf, sizeof profile_buf, 50); -#endif -#if defined(linux) || defined(__GNU__) - signal(SIGCHLD, SIG_DFL); -#endif - state = 0; - if (setjmp(jmploc.loc)) { - INTOFF; - /* - * When a shell procedure is executed, we raise the - * exception EXSHELLPROC to clean up before executing - * the shell procedure. - */ - switch (exception) { - case EXSHELLPROC: - rootpid = getpid(); - rootshell = 1; - minusc = NULL; - state = 3; - break; - - case EXEXEC: - exitstatus = exerrno; - break; - - case EXERROR: - exitstatus = 2; - break; - - default: - break; - } - - if (exception != EXSHELLPROC) { - if (state == 0 || iflag == 0 || ! rootshell) - exitshell(exitstatus); - } - reset(); - if (exception == EXINT) { - out2c('\n'); - } - popstackmark(&smark); - FORCEINTON; /* enable interrupts */ - if (state == 1) - goto state1; - else if (state == 2) - goto state2; - else if (state == 3) - goto state3; - else - goto state4; - } - handler = &jmploc; -#ifdef DEBUG - opentrace(); - trputs("Shell args: "); trargs(argv); -#endif - rootpid = getpid(); - rootshell = 1; - init(); - setstackmark(&smark); - procargs(argc, argv); - if (argv[0] && argv[0][0] == '-') { - state = 1; - read_profile("/etc/profile"); -state1: - state = 2; - read_profile(".profile"); - } -state2: - state = 3; -#ifndef linux - if (getuid() == geteuid() && getgid() == getegid()) { -#endif - if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { - state = 3; - read_profile(shinit); - } -#ifndef linux - } -#endif -state3: - state = 4; - if (sflag == 0 || minusc) { - static int sigs[] = { - SIGINT, SIGQUIT, SIGHUP, -#ifdef SIGTSTP - SIGTSTP, -#endif - SIGPIPE - }; -#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0])) - int i; - - for (i = 0; i < SIGSSIZE; i++) - setsignal(sigs[i]); - } - - if (minusc) - evalstring(minusc, 0); - - if (sflag || minusc == NULL) { -state4: /* XXX ??? - why isn't this before the "if" statement */ - cmdloop(1); - } -#if PROFILE - monitor(0); -#endif - exitshell(exitstatus); - /* NOTREACHED */ -} - - -/* - * Read and execute commands. "Top" is nonzero for the top level command - * loop; it turns on prompting if the shell is interactive. - */ - -static void -cmdloop(int top) -{ - union node *n; - struct stackmark smark; - int inter; - int numeof = 0; - - TRACE(("cmdloop(%d) called\n", top)); - setstackmark(&smark); - for (;;) { - if (pendingsigs) - dotrap(); - inter = 0; - if (iflag && top) { - inter++; - showjobs(1); - chkmail(0); - flushall(); - } - n = parsecmd(inter); - /* showtree(n); DEBUG */ - if (n == NEOF) { - if (!top || numeof >= 50) - break; - if (!stoppedjobs()) { - if (!Iflag) - break; - out2str("\nUse \"exit\" to leave shell.\n"); - } - numeof++; - } else if (n != NULL && nflag == 0) { - job_warning = (job_warning == 2) ? 1 : 0; - numeof = 0; - evaltree(n, 0); - } - popstackmark(&smark); - setstackmark(&smark); - if (evalskip == SKIPFILE) { - evalskip = 0; - break; - } - } - popstackmark(&smark); -} - - - -/* - * Read /etc/profile or .profile. Return on error. - */ - -static void -read_profile(name) - const char *name; -{ - int fd; - int xflag_set = 0; - int vflag_set = 0; - - INTOFF; - if ((fd = open(name, O_RDONLY)) >= 0) - setinputfd(fd, 1); - INTON; - if (fd < 0) - return; - /* -q turns off -x and -v just when executing init files */ - if (qflag) { - if (xflag) - xflag = 0, xflag_set = 1; - if (vflag) - vflag = 0, vflag_set = 1; - } - cmdloop(0); - if (qflag) { - if (xflag_set) - xflag = 1; - if (vflag_set) - vflag = 1; - } - popfile(); -} - - - -/* - * Read a file containing shell functions. - */ - -static void -readcmdfile(const char *name) -{ - int fd; - - INTOFF; - if ((fd = open(name, O_RDONLY)) >= 0) - setinputfd(fd, 1); - else - error("Can't open %s", name); - INTON; - cmdloop(0); - popfile(); -} - - - -/* - * Take commands from a file. To be compatable we should do a path - * search for the file, which is necessary to find sub-commands. - */ - - -static inline char * -find_dot_file(mybasename) - char *mybasename; -{ - char *fullname; - const char *path = pathval(); - struct stat statb; - - /* don't try this for absolute or relative paths */ - if (strchr(mybasename, '/')) - return mybasename; - - while ((fullname = padvance(&path, mybasename)) != NULL) { - if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { - /* - * Don't bother freeing here, since it will - * be freed by the caller. - */ - return fullname; - } - stunalloc(fullname); - } - - /* not found in the PATH */ - error("%s: not found", mybasename); - /* NOTREACHED */ -} - -static int -dotcmd(argc, argv) - int argc; - char **argv; -{ - struct strlist *sp; - exitstatus = 0; - - for (sp = cmdenviron; sp ; sp = sp->next) - setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED); - - if (argc >= 2) { /* That's what SVR2 does */ - char *fullname; - struct stackmark smark; - - setstackmark(&smark); - fullname = find_dot_file(argv[1]); - setinputfile(fullname, 1); - commandname = fullname; - cmdloop(0); - popfile(); - popstackmark(&smark); - } - return exitstatus; -} - - -static int -exitcmd(argc, argv) - int argc; - char **argv; -{ - if (stoppedjobs()) - return 0; - if (argc > 1) - exitstatus = number(argv[1]); - else - exitstatus = oexitstatus; - exitshell(exitstatus); - /* NOTREACHED */ -} - -static pointer -stalloc(int nbytes) -{ - char *p; - - nbytes = ALIGN(nbytes); - if (nbytes > stacknleft) { - int blocksize; - struct stack_block *sp; - - blocksize = nbytes; - if (blocksize < MINSIZE) - blocksize = MINSIZE; - INTOFF; - sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize); - sp->prev = stackp; - stacknxt = sp->space; - stacknleft = blocksize; - stackp = sp; - INTON; - } - p = stacknxt; - stacknxt += nbytes; - stacknleft -= nbytes; - return p; -} - - -static void -stunalloc(pointer p) -{ -#ifdef DEBUG - if (p == NULL) { /*DEBUG */ - write(2, "stunalloc\n", 10); - abort(); - } -#endif - if (!(stacknxt >= (char *)p && (char *)p >= stackp->space)) { - p = stackp->space; - } - stacknleft += stacknxt - (char *)p; - stacknxt = p; -} - - -static void -setstackmark(struct stackmark *mark) -{ - mark->stackp = stackp; - mark->stacknxt = stacknxt; - mark->stacknleft = stacknleft; - mark->marknext = markp; - markp = mark; -} - - -static void -popstackmark(struct stackmark *mark) -{ - struct stack_block *sp; - - INTOFF; - markp = mark->marknext; - while (stackp != mark->stackp) { - sp = stackp; - stackp = sp->prev; - ckfree(sp); - } - stacknxt = mark->stacknxt; - stacknleft = mark->stacknleft; - INTON; -} - - -/* - * When the parser reads in a string, it wants to stick the string on the - * stack and only adjust the stack pointer when it knows how big the - * string is. Stackblock (defined in stack.h) returns a pointer to a block - * of space on top of the stack and stackblocklen returns the length of - * this block. Growstackblock will grow this space by at least one byte, - * possibly moving it (like realloc). Grabstackblock actually allocates the - * part of the block that has been used. - */ - -static void -growstackblock(void) { - char *p; - int newlen = ALIGN(stacknleft * 2 + 100); - char *oldspace = stacknxt; - int oldlen = stacknleft; - struct stack_block *sp; - struct stack_block *oldstackp; - - if (stacknxt == stackp->space && stackp != &stackbase) { - INTOFF; - oldstackp = stackp; - sp = stackp; - stackp = sp->prev; - sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen); - sp->prev = stackp; - stackp = sp; - stacknxt = sp->space; - stacknleft = newlen; - { - /* Stack marks pointing to the start of the old block - * must be relocated to point to the new block - */ - struct stackmark *xmark; - xmark = markp; - while (xmark != NULL && xmark->stackp == oldstackp) { - xmark->stackp = stackp; - xmark->stacknxt = stacknxt; - xmark->stacknleft = stacknleft; - xmark = xmark->marknext; - } - } - INTON; - } else { - p = stalloc(newlen); - memcpy(p, oldspace, oldlen); - stacknxt = p; /* free the space */ - stacknleft += newlen; /* we just allocated */ - } -} - - - -static inline void -grabstackblock(int len) -{ - len = ALIGN(len); - stacknxt += len; - stacknleft -= len; -} - - - -/* - * The following routines are somewhat easier to use that the above. - * The user declares a variable of type STACKSTR, which may be declared - * to be a register. The macro STARTSTACKSTR initializes things. Then - * the user uses the macro STPUTC to add characters to the string. In - * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is - * grown as necessary. When the user is done, she can just leave the - * string there and refer to it using stackblock(). Or she can allocate - * the space for it using grabstackstr(). If it is necessary to allow - * someone else to use the stack temporarily and then continue to grow - * the string, the user should use grabstack to allocate the space, and - * then call ungrabstr(p) to return to the previous mode of operation. - * - * USTPUTC is like STPUTC except that it doesn't check for overflow. - * CHECKSTACKSPACE can be called before USTPUTC to ensure that there - * is space for at least one character. - */ - - -static char * -growstackstr(void) { - int len = stackblocksize(); - if (herefd >= 0 && len >= 1024) { - xwrite(herefd, stackblock(), len); - sstrnleft = len - 1; - return stackblock(); - } - growstackblock(); - sstrnleft = stackblocksize() - len - 1; - return stackblock() + len; -} - - -/* - * Called from CHECKSTRSPACE. - */ - -static char * -makestrspace(size_t newlen) { - int len = stackblocksize() - sstrnleft; - do { - growstackblock(); - sstrnleft = stackblocksize() - len; - } while (sstrnleft < newlen); - return stackblock() + len; -} - - - -static void -ungrabstackstr(char *s, char *p) -{ - stacknleft += stacknxt - s; - stacknxt = s; - sstrnleft = stacknleft - (p - s); -} -/* - * Miscelaneous builtins. - */ - - -#undef rflag - -//#ifdef __GLIBC__ -static mode_t getmode(const void *, mode_t); -static void *setmode(const char *); -//#endif - -#if !defined(__GLIBC__) || __GLIBC__ == 2 && __GLIBC_MINOR__ < 1 -typedef long rlim_t; -#endif - - - -/* - * The read builtin. The -e option causes backslashes to escape the - * following character. - * - * This uses unbuffered input, which may be avoidable in some cases. - */ - -static int -readcmd(argc, argv) - int argc; - char **argv; -{ - char **ap; - int backslash; - char c; - int rflag; - char *prompt; - const char *ifs; - char *p; - int startword; - int status; - int i; - - rflag = 0; - prompt = NULL; - while ((i = nextopt("p:r")) != '\0') { - if (i == 'p') - prompt = optionarg; - else - rflag = 1; - } - if (prompt && isatty(0)) { - putprompt(prompt); - flushall(); - } - if (*(ap = argptr) == NULL) - error("arg count"); - if ((ifs = bltinlookup("IFS")) == NULL) - ifs = defifs; - status = 0; - startword = 1; - backslash = 0; - STARTSTACKSTR(p); - for (;;) { - if (read(0, &c, 1) != 1) { - status = 1; - break; - } - if (c == '\0') - continue; - if (backslash) { - backslash = 0; - if (c != '\n') - STPUTC(c, p); - continue; - } - if (!rflag && c == '\\') { - backslash++; - continue; - } - if (c == '\n') - break; - if (startword && *ifs == ' ' && strchr(ifs, c)) { - continue; - } - startword = 0; - if (backslash && c == '\\') { - if (read(0, &c, 1) != 1) { - status = 1; - break; - } - STPUTC(c, p); - } else if (ap[1] != NULL && strchr(ifs, c) != NULL) { - STACKSTRNUL(p); - setvar(*ap, stackblock(), 0); - ap++; - startword = 1; - STARTSTACKSTR(p); - } else { - STPUTC(c, p); - } - } - STACKSTRNUL(p); - /* Remove trailing blanks */ - while (stackblock() <= --p && strchr(ifs, *p) != NULL) - *p = '\0'; - setvar(*ap, stackblock(), 0); - while (*++ap != NULL) - setvar(*ap, nullstr, 0); - return status; -} - - - -static int -umaskcmd(argc, argv) - int argc; - char **argv; -{ - char *ap; - int mask; - int i; - int symbolic_mode = 0; - - while (nextopt("S") != '\0') { - symbolic_mode = 1; - } - - INTOFF; - mask = umask(0); - umask(mask); - INTON; - - if ((ap = *argptr) == NULL) { - if (symbolic_mode) { - char u[4], g[4], o[4]; - - i = 0; - if ((mask & S_IRUSR) == 0) - u[i++] = 'r'; - if ((mask & S_IWUSR) == 0) - u[i++] = 'w'; - if ((mask & S_IXUSR) == 0) - u[i++] = 'x'; - u[i] = '\0'; - - i = 0; - if ((mask & S_IRGRP) == 0) - g[i++] = 'r'; - if ((mask & S_IWGRP) == 0) - g[i++] = 'w'; - if ((mask & S_IXGRP) == 0) - g[i++] = 'x'; - g[i] = '\0'; - - i = 0; - if ((mask & S_IROTH) == 0) - o[i++] = 'r'; - if ((mask & S_IWOTH) == 0) - o[i++] = 'w'; - if ((mask & S_IXOTH) == 0) - o[i++] = 'x'; - o[i] = '\0'; - - printf("u=%s,g=%s,o=%s\n", u, g, o); - } else { - printf("%.4o\n", mask); - } - } else { - if (is_digit((unsigned char)*ap)) { - mask = 0; - do { - if (*ap >= '8' || *ap < '0') - error("Illegal number: %s", argv[1]); - mask = (mask << 3) + (*ap - '0'); - } while (*++ap != '\0'); - umask(mask); - } else { - void *set; - - INTOFF; - if ((set = setmode(ap)) != 0) { - mask = getmode(set, ~mask & 0777); - ckfree(set); - } - INTON; - if (!set) - error("Illegal mode: %s", ap); - - umask(~mask & 0777); - } - } - return 0; -} - -/* - * ulimit builtin - * - * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and - * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with - * ash by J.T. Conklin. - * - * Public domain. - */ - -struct limits { - const char *name; - int cmd; - int factor; /* multiply by to get rlim_{cur,max} values */ - char option; -}; - -static const struct limits limits[] = { -#ifdef RLIMIT_CPU - { "time(seconds)", RLIMIT_CPU, 1, 't' }, -#endif -#ifdef RLIMIT_FSIZE - { "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, -#endif -#ifdef RLIMIT_DATA - { "data(kbytes)", RLIMIT_DATA, 1024, 'd' }, -#endif -#ifdef RLIMIT_STACK - { "stack(kbytes)", RLIMIT_STACK, 1024, 's' }, -#endif -#ifdef RLIMIT_CORE - { "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, -#endif -#ifdef RLIMIT_RSS - { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' }, -#endif -#ifdef RLIMIT_MEMLOCK - { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, -#endif -#ifdef RLIMIT_NPROC - { "process(processes)", RLIMIT_NPROC, 1, 'p' }, -#endif -#ifdef RLIMIT_NOFILE - { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' }, -#endif -#ifdef RLIMIT_VMEM - { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' }, -#endif -#ifdef RLIMIT_SWAP - { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' }, -#endif - { (char *) 0, 0, 0, '\0' } -}; - -static int -ulimitcmd(argc, argv) - int argc; - char **argv; -{ - int c; - rlim_t val = 0; - enum { SOFT = 0x1, HARD = 0x2 } - how = SOFT | HARD; - const struct limits *l; - int set, all = 0; - int optc, what; - struct rlimit limit; - - what = 'f'; - while ((optc = nextopt("HSatfdsmcnpl")) != '\0') - switch (optc) { - case 'H': - how = HARD; - break; - case 'S': - how = SOFT; - break; - case 'a': - all = 1; - break; - default: - what = optc; - } - - for (l = limits; l->name && l->option != what; l++) - ; - if (!l->name) - error("internal error (%c)", what); - - set = *argptr ? 1 : 0; - if (set) { - char *p = *argptr; - - if (all || argptr[1]) - error("too many arguments"); - if (strcmp(p, "unlimited") == 0) - val = RLIM_INFINITY; - else { - val = (rlim_t) 0; - - while ((c = *p++) >= '0' && c <= '9') - { - val = (val * 10) + (long)(c - '0'); - if (val < (rlim_t) 0) - break; - } - if (c) - error("bad number"); - val *= l->factor; - } - } - if (all) { - for (l = limits; l->name; l++) { - getrlimit(l->cmd, &limit); - if (how & SOFT) - val = limit.rlim_cur; - else if (how & HARD) - val = limit.rlim_max; - - printf("%-20s ", l->name); - if (val == RLIM_INFINITY) - printf("unlimited\n"); - else - { - val /= l->factor; - printf("%lld\n", (long long) val); - } - } - return 0; - } - - getrlimit(l->cmd, &limit); - if (set) { - if (how & HARD) - limit.rlim_max = val; - if (how & SOFT) - limit.rlim_cur = val; - if (setrlimit(l->cmd, &limit) < 0) - error("error setting limit (%m)"); - } else { - if (how & SOFT) - val = limit.rlim_cur; - else if (how & HARD) - val = limit.rlim_max; - - if (val == RLIM_INFINITY) - printf("unlimited\n"); - else - { - val /= l->factor; - printf("%lld\n", (long long) val); - } - } - return 0; -} -/* - * prefix -- see if pfx is a prefix of string. - */ - -static int -prefix(char const *pfx, char const *string) -{ - while (*pfx) { - if (*pfx++ != *string++) - return 0; - } - return 1; -} - -/* - * Return true if s is a string of digits, and save munber in intptr - * nagative is bad - */ - -static int -is_number(const char *p, int *intptr) -{ - int ret = 0; - - do { - if (! is_digit(*p)) - return 0; - ret *= 10; - ret += digit_val(*p); - p++; - } while (*p != '\0'); - - *intptr = ret; - return 1; -} - -/* - * Convert a string of digits to an integer, printing an error message on - * failure. - */ - -static int -number(const char *s) -{ - int i; - if (! is_number(s, &i)) - error("Illegal number: %s", s); - return i; -} - -/* - * Produce a possibly single quoted string suitable as input to the shell. - * The return string is allocated on the stack. - */ - -static char * -single_quote(const char *s) { - char *p; - - STARTSTACKSTR(p); - - do { - char *q = p; - size_t len1, len1p, len2, len2p; - - len1 = strcspn(s, "'"); - len2 = strspn(s + len1, "'"); - - len1p = len1 ? len1 + 2 : len1; - switch (len2) { - case 0: - len2p = 0; - break; - case 1: - len2p = 2; - break; - default: - len2p = len2 + 2; - } - - CHECKSTRSPACE(len1p + len2p + 1, p); - - if (len1) { - *p = '\''; - q = p + 1 + len1; - memcpy(p + 1, s, len1); - *q++ = '\''; - s += len1; - } - - switch (len2) { - case 0: - break; - case 1: - *q++ = '\\'; - *q = '\''; - s++; - break; - default: - *q = '"'; - q += 1 + len2; - memcpy(q + 1, s, len2); - *q = '"'; - s += len2; - } - - STADJUST(len1p + len2p, p); - } while (*s); - - USTPUTC(0, p); - - return grabstackstr(p); -} - -/* - * Like strdup but works with the ash stack. - */ - -static char * -sstrdup(const char *p) -{ - size_t len = strlen(p) + 1; - return memcpy(stalloc(len), p, len); -} - - -/* - * Routine for dealing with parsed shell commands. - */ - - -static void sizenodelist (const struct nodelist *); -static struct nodelist *copynodelist (const struct nodelist *); -static char *nodesavestr (const char *); - -static void -calcsize(const union node *n) -{ - if (n == NULL) - return; - funcblocksize += nodesize[n->type]; - switch (n->type) { - case NSEMI: - case NAND: - case NOR: - case NWHILE: - case NUNTIL: - calcsize(n->nbinary.ch2); - calcsize(n->nbinary.ch1); - break; - case NCMD: - calcsize(n->ncmd.redirect); - calcsize(n->ncmd.args); - calcsize(n->ncmd.assign); - break; - case NPIPE: - sizenodelist(n->npipe.cmdlist); - break; - case NREDIR: - case NBACKGND: - case NSUBSHELL: - calcsize(n->nredir.redirect); - calcsize(n->nredir.n); - break; - case NIF: - calcsize(n->nif.elsepart); - calcsize(n->nif.ifpart); - calcsize(n->nif.test); - break; - case NFOR: - funcstringsize += strlen(n->nfor.var) + 1; - calcsize(n->nfor.body); - calcsize(n->nfor.args); - break; - case NCASE: - calcsize(n->ncase.cases); - calcsize(n->ncase.expr); - break; - case NCLIST: - calcsize(n->nclist.body); - calcsize(n->nclist.pattern); - calcsize(n->nclist.next); - break; - case NDEFUN: - case NARG: - sizenodelist(n->narg.backquote); - funcstringsize += strlen(n->narg.text) + 1; - calcsize(n->narg.next); - break; - case NTO: - case NFROM: - case NFROMTO: - case NAPPEND: - case NTOOV: - calcsize(n->nfile.fname); - calcsize(n->nfile.next); - break; - case NTOFD: - case NFROMFD: - calcsize(n->ndup.vname); - calcsize(n->ndup.next); - break; - case NHERE: - case NXHERE: - calcsize(n->nhere.doc); - calcsize(n->nhere.next); - break; - case NNOT: - calcsize(n->nnot.com); - break; - }; -} - -static void -sizenodelist(const struct nodelist *lp) -{ - while (lp) { - funcblocksize += ALIGN(sizeof(struct nodelist)); - calcsize(lp->n); - lp = lp->next; - } -} - - -static union node * -copynode(const union node *n) -{ - union node *new; - - if (n == NULL) - return NULL; - new = funcblock; - funcblock = (char *) funcblock + nodesize[n->type]; - switch (n->type) { - case NSEMI: - case NAND: - case NOR: - case NWHILE: - case NUNTIL: - new->nbinary.ch2 = copynode(n->nbinary.ch2); - new->nbinary.ch1 = copynode(n->nbinary.ch1); - break; - case NCMD: - new->ncmd.redirect = copynode(n->ncmd.redirect); - new->ncmd.args = copynode(n->ncmd.args); - new->ncmd.assign = copynode(n->ncmd.assign); - new->ncmd.backgnd = n->ncmd.backgnd; - break; - case NPIPE: - new->npipe.cmdlist = copynodelist(n->npipe.cmdlist); - new->npipe.backgnd = n->npipe.backgnd; - break; - case NREDIR: - case NBACKGND: - case NSUBSHELL: - new->nredir.redirect = copynode(n->nredir.redirect); - new->nredir.n = copynode(n->nredir.n); - break; - case NIF: - new->nif.elsepart = copynode(n->nif.elsepart); - new->nif.ifpart = copynode(n->nif.ifpart); - new->nif.test = copynode(n->nif.test); - break; - case NFOR: - new->nfor.var = nodesavestr(n->nfor.var); - new->nfor.body = copynode(n->nfor.body); - new->nfor.args = copynode(n->nfor.args); - break; - case NCASE: - new->ncase.cases = copynode(n->ncase.cases); - new->ncase.expr = copynode(n->ncase.expr); - break; - case NCLIST: - new->nclist.body = copynode(n->nclist.body); - new->nclist.pattern = copynode(n->nclist.pattern); - new->nclist.next = copynode(n->nclist.next); - break; - case NDEFUN: - case NARG: - new->narg.backquote = copynodelist(n->narg.backquote); - new->narg.text = nodesavestr(n->narg.text); - new->narg.next = copynode(n->narg.next); - break; - case NTO: - case NFROM: - case NFROMTO: - case NAPPEND: - case NTOOV: - new->nfile.fname = copynode(n->nfile.fname); - new->nfile.fd = n->nfile.fd; - new->nfile.next = copynode(n->nfile.next); - break; - case NTOFD: - case NFROMFD: - new->ndup.vname = copynode(n->ndup.vname); - new->ndup.dupfd = n->ndup.dupfd; - new->ndup.fd = n->ndup.fd; - new->ndup.next = copynode(n->ndup.next); - break; - case NHERE: - case NXHERE: - new->nhere.doc = copynode(n->nhere.doc); - new->nhere.fd = n->nhere.fd; - new->nhere.next = copynode(n->nhere.next); - break; - case NNOT: - new->nnot.com = copynode(n->nnot.com); - break; - }; - new->type = n->type; - return new; -} - - -static struct nodelist * -copynodelist(const struct nodelist *lp) -{ - struct nodelist *start; - struct nodelist **lpp; - - lpp = &start; - while (lp) { - *lpp = funcblock; - funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist)); - (*lpp)->n = copynode(lp->n); - lp = lp->next; - lpp = &(*lpp)->next; - } - *lpp = NULL; - return start; -} - - -static char * -nodesavestr(const char *s) -{ - const char *p = s; - char *q = funcstring; - char *rtn = funcstring; - - while ((*q++ = *p++) != '\0') - continue; - funcstring = q; - return rtn; -} - -#ifdef ASH_GETOPTS -static int getopts (char *, char *, char **, int *, int *); -#endif - - -/* - * Process the shell command line arguments. - */ - -static void -procargs(argc, argv) - int argc; - char **argv; -{ - int i; - - argptr = argv; - if (argc > 0) - argptr++; - for (i = 0; i < NOPTS; i++) - optent_val(i) = 2; - options(1); - if (*argptr == NULL && minusc == NULL) - sflag = 1; - if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) - iflag = 1; - if (mflag == 2) - mflag = iflag; - for (i = 0; i < NOPTS; i++) - if (optent_val(i) == 2) - optent_val(i) = 0; - arg0 = argv[0]; - if (sflag == 0 && minusc == NULL) { - commandname = argv[0]; - arg0 = *argptr++; - setinputfile(arg0, 0); - commandname = arg0; - } - /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ - if (argptr && minusc && *argptr) - arg0 = *argptr++; - - shellparam.p = argptr; - shellparam.optind = 1; - shellparam.optoff = -1; - /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ - while (*argptr) { - shellparam.nparam++; - argptr++; - } - optschanged(); -} - - - -/* - * Process shell options. The global variable argptr contains a pointer - * to the argument list; we advance it past the options. - */ - -static inline void -minus_o(const char *name, int val) -{ - int i; - - if (name == NULL) { - out1str("Current option settings\n"); - for (i = 0; i < NOPTS; i++) - printf("%-16s%s\n", optent_name(optlist[i]), - optent_val(i) ? "on" : "off"); - } else { - for (i = 0; i < NOPTS; i++) - if (equal(name, optent_name(optlist[i]))) { - setoption(optent_letter(optlist[i]), val); - return; - } - error("Illegal option -o %s", name); - } -} - - -static void -options(int cmdline) -{ - char *p; - int val; - int c; - - if (cmdline) - minusc = NULL; - while ((p = *argptr) != NULL) { - argptr++; - if ((c = *p++) == '-') { - val = 1; - if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { - if (!cmdline) { - /* "-" means turn off -x and -v */ - if (p[0] == '\0') - xflag = vflag = 0; - /* "--" means reset params */ - else if (*argptr == NULL) - setparam(argptr); - } - break; /* "-" or "--" terminates options */ - } - } else if (c == '+') { - val = 0; - } else { - argptr--; - break; - } - while ((c = *p++) != '\0') { - if (c == 'c' && cmdline) { - char *q; -#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */ - if (*p == '\0') -#endif - q = *argptr++; - if (q == NULL || minusc != NULL) - error("Bad -c option"); - minusc = q; -#ifdef NOHACK - break; -#endif - } else if (c == 'o') { - minus_o(*argptr, val); - if (*argptr) - argptr++; - } else { - setoption(c, val); - } - } - } -} - - -static void -setoption(int flag, int val) -{ - int i; - - for (i = 0; i < NOPTS; i++) - if (optent_letter(optlist[i]) == flag) { - optent_val(i) = val; - if (val) { - /* #%$ hack for ksh semantics */ - if (flag == 'V') - Eflag = 0; - else if (flag == 'E') - Vflag = 0; - } - return; - } - error("Illegal option -%c", flag); - /* NOTREACHED */ -} - - - -/* - * Set the shell parameters. - */ - -static void -setparam(char **argv) -{ - char **newparam; - char **ap; - int nparam; - - for (nparam = 0 ; argv[nparam] ; nparam++); - ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); - while (*argv) { - *ap++ = savestr(*argv++); - } - *ap = NULL; - freeparam(&shellparam); - shellparam.malloc = 1; - shellparam.nparam = nparam; - shellparam.p = newparam; - shellparam.optind = 1; - shellparam.optoff = -1; -} - - -/* - * Free the list of positional parameters. - */ - -static void -freeparam(volatile struct shparam *param) -{ - char **ap; - - if (param->malloc) { - for (ap = param->p ; *ap ; ap++) - ckfree(*ap); - ckfree(param->p); - } -} - - - -/* - * The shift builtin command. - */ - -static int -shiftcmd(argc, argv) - int argc; - char **argv; -{ - int n; - char **ap1, **ap2; - - n = 1; - if (argc > 1) - n = number(argv[1]); - if (n > shellparam.nparam) - error("can't shift that many"); - INTOFF; - shellparam.nparam -= n; - for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { - if (shellparam.malloc) - ckfree(*ap1); - } - ap2 = shellparam.p; - while ((*ap2++ = *ap1++) != NULL); - shellparam.optind = 1; - shellparam.optoff = -1; - INTON; - return 0; -} - - - -/* - * The set command builtin. - */ - -static int -setcmd(argc, argv) - int argc; - char **argv; -{ - if (argc == 1) - return showvarscmd(argc, argv); - INTOFF; - options(0); - optschanged(); - if (*argptr != NULL) { - setparam(argptr); - } - INTON; - return 0; -} - - -static void -getoptsreset(const char *value) -{ - shellparam.optind = number(value); - shellparam.optoff = -1; -} - -#ifdef BB_LOCALE_SUPPORT -static void change_lc_all(const char *value) -{ - if(value != 0 && *value != 0) - setlocale(LC_ALL, value); -} - -static void change_lc_ctype(const char *value) -{ - if(value != 0 && *value != 0) - setlocale(LC_CTYPE, value); -} - -#endif - -#ifdef ASH_GETOPTS -/* - * The getopts builtin. Shellparam.optnext points to the next argument - * to be processed. Shellparam.optptr points to the next character to - * be processed in the current argument. If shellparam.optnext is NULL, - * then it's the first time getopts has been called. - */ - -static int -getoptscmd(argc, argv) - int argc; - char **argv; -{ - char **optbase; - - if (argc < 3) - error("Usage: getopts optstring var [arg]"); - else if (argc == 3) { - optbase = shellparam.p; - if (shellparam.optind > shellparam.nparam + 1) { - shellparam.optind = 1; - shellparam.optoff = -1; - } - } - else { - optbase = &argv[3]; - if (shellparam.optind > argc - 2) { - shellparam.optind = 1; - shellparam.optoff = -1; - } - } - - return getopts(argv[1], argv[2], optbase, &shellparam.optind, - &shellparam.optoff); -} - -/* - * Safe version of setvar, returns 1 on success 0 on failure. - */ - -static int -setvarsafe(name, val, flags) - const char *name, *val; - int flags; -{ - struct jmploc jmploc; - struct jmploc *volatile savehandler = handler; - int err = 0; -#ifdef __GNUC__ - (void) &err; -#endif - - if (setjmp(jmploc.loc)) - err = 1; - else { - handler = &jmploc; - setvar(name, val, flags); - } - handler = savehandler; - return err; -} - -static int -getopts(optstr, optvar, optfirst, myoptind, optoff) - char *optstr; - char *optvar; - char **optfirst; - int *myoptind; - int *optoff; -{ - char *p, *q; - char c = '?'; - int done = 0; - int err = 0; - char s[10]; - char **optnext = optfirst + *myoptind - 1; - - if (*myoptind <= 1 || *optoff < 0 || !(*(optnext - 1)) || - strlen(*(optnext - 1)) < *optoff) - p = NULL; - else - p = *(optnext - 1) + *optoff; - if (p == NULL || *p == '\0') { - /* Current word is done, advance */ - if (optnext == NULL) - return 1; - p = *optnext; - if (p == NULL || *p != '-' || *++p == '\0') { -atend: - *myoptind = optnext - optfirst + 1; - p = NULL; - done = 1; - goto out; - } - optnext++; - if (p[0] == '-' && p[1] == '\0') /* check for "--" */ - goto atend; - } - - c = *p++; - for (q = optstr; *q != c; ) { - if (*q == '\0') { - if (optstr[0] == ':') { - s[0] = c; - s[1] = '\0'; - err |= setvarsafe("OPTARG", s, 0); - } - else { - out2fmt("Illegal option -%c\n", c); - (void) unsetvar("OPTARG"); - } - c = '?'; - goto bad; - } - if (*++q == ':') - q++; - } - - if (*++q == ':') { - if (*p == '\0' && (p = *optnext) == NULL) { - if (optstr[0] == ':') { - s[0] = c; - s[1] = '\0'; - err |= setvarsafe("OPTARG", s, 0); - c = ':'; - } - else { - out2fmt("No arg for -%c option\n", c); - (void) unsetvar("OPTARG"); - c = '?'; - } - goto bad; - } - - if (p == *optnext) - optnext++; - setvarsafe("OPTARG", p, 0); - p = NULL; - } - else - setvarsafe("OPTARG", "", 0); - *myoptind = optnext - optfirst + 1; - goto out; - -bad: - *myoptind = 1; - p = NULL; -out: - *optoff = p ? p - *(optnext - 1) : -1; - snprintf(s, sizeof(s), "%d", *myoptind); - err |= setvarsafe("OPTIND", s, VNOFUNC); - s[0] = c; - s[1] = '\0'; - err |= setvarsafe(optvar, s, 0); - if (err) { - *myoptind = 1; - *optoff = -1; - exraise(EXERROR); - } - return done; -} -#endif - -/* - * XXX - should get rid of. have all builtins use getopt(3). the - * library getopt must have the BSD extension static variable "optreset" - * otherwise it can't be used within the shell safely. - * - * Standard option processing (a la getopt) for builtin routines. The - * only argument that is passed to nextopt is the option string; the - * other arguments are unnecessary. It return the character, or '\0' on - * end of input. - */ - -static int -nextopt(const char *optstring) -{ - char *p; - const char *q; - char c; - - if ((p = optptr) == NULL || *p == '\0') { - p = *argptr; - if (p == NULL || *p != '-' || *++p == '\0') - return '\0'; - argptr++; - if (p[0] == '-' && p[1] == '\0') /* check for "--" */ - return '\0'; - } - c = *p++; - for (q = optstring ; *q != c ; ) { - if (*q == '\0') - error("Illegal option -%c", c); - if (*++q == ':') - q++; - } - if (*++q == ':') { - if (*p == '\0' && (p = *argptr++) == NULL) - error("No arg for -%c option", c); - optionarg = p; - p = NULL; - } - optptr = p; - return c; -} - -static void -flushall() { - INTOFF; - fflush(stdout); - INTON; -} - - -static void -out2fmt(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); -} - -/* - * Version of write which resumes after a signal is caught. - */ - -static int -xwrite(int fd, const char *buf, int nbytes) -{ - int ntry; - int i; - int n; - - n = nbytes; - ntry = 0; - for (;;) { - i = write(fd, buf, n); - if (i > 0) { - if ((n -= i) <= 0) - return nbytes; - buf += i; - ntry = 0; - } else if (i == 0) { - if (++ntry > 10) - return nbytes - n; - } else if (errno != EINTR) { - return -1; - } - } -} - - -/* - * Shell command parser. - */ - -#define EOFMARKLEN 79 - - - -struct heredoc { - struct heredoc *next; /* next here document in list */ - union node *here; /* redirection node */ - char *eofmark; /* string indicating end of input */ - int striptabs; /* if set, strip leading tabs */ -}; - -static struct heredoc *heredoclist; /* list of here documents to read */ -static int parsebackquote; /* nonzero if we are inside backquotes */ -static int doprompt; /* if set, prompt the user */ -static int needprompt; /* true if interactive and at start of line */ -static int lasttoken; /* last token read */ - -static char *wordtext; /* text of last word returned by readtoken */ - -static struct nodelist *backquotelist; -static union node *redirnode; -static struct heredoc *heredoc; -static int quoteflag; /* set if (part of) last token was quoted */ -static int startlinno; /* line # where last token started */ - - -static union node *list (int); -static union node *andor (void); -static union node *pipeline (void); -static union node *command (void); -static union node *simplecmd (void); -static void parsefname (void); -static void parseheredoc (void); -static int peektoken (void); -static int readtoken (void); -static int xxreadtoken (void); -static int readtoken1 (int, char const *, char *, int); -static int noexpand (char *); -static void synexpect (int) __attribute__((noreturn)); -static void synerror (const char *) __attribute__((noreturn)); -static void setprompt (int); - - -/* - * Read and parse a command. Returns NEOF on end of file. (NULL is a - * valid parse tree indicating a blank line.) - */ - -static union node * -parsecmd(int interact) -{ - int t; - - tokpushback = 0; - doprompt = interact; - if (doprompt) - setprompt(1); - else - setprompt(0); - needprompt = 0; - t = readtoken(); - if (t == TEOF) - return NEOF; - if (t == TNL) - return NULL; - tokpushback++; - return list(1); -} - - -static union node * -list(nlflag) - int nlflag; -{ - union node *n1, *n2, *n3; - int tok; - - checkkwd = 2; - if (nlflag == 0 && tokendlist[peektoken()]) - return NULL; - n1 = NULL; - for (;;) { - n2 = andor(); - tok = readtoken(); - if (tok == TBACKGND) { - if (n2->type == NCMD || n2->type == NPIPE) { - n2->ncmd.backgnd = 1; - } else if (n2->type == NREDIR) { - n2->type = NBACKGND; - } else { - n3 = (union node *)stalloc(sizeof (struct nredir)); - n3->type = NBACKGND; - n3->nredir.n = n2; - n3->nredir.redirect = NULL; - n2 = n3; - } - } - if (n1 == NULL) { - n1 = n2; - } - else { - n3 = (union node *)stalloc(sizeof (struct nbinary)); - n3->type = NSEMI; - n3->nbinary.ch1 = n1; - n3->nbinary.ch2 = n2; - n1 = n3; - } - switch (tok) { - case TBACKGND: - case TSEMI: - tok = readtoken(); - /* fall through */ - case TNL: - if (tok == TNL) { - parseheredoc(); - if (nlflag) - return n1; - } else { - tokpushback++; - } - checkkwd = 2; - if (tokendlist[peektoken()]) - return n1; - break; - case TEOF: - if (heredoclist) - parseheredoc(); - else - pungetc(); /* push back EOF on input */ - return n1; - default: - if (nlflag) - synexpect(-1); - tokpushback++; - return n1; - } - } -} - - - -static union node * -andor() { - union node *n1, *n2, *n3; - int t; - - checkkwd = 1; - n1 = pipeline(); - for (;;) { - if ((t = readtoken()) == TAND) { - t = NAND; - } else if (t == TOR) { - t = NOR; - } else { - tokpushback++; - return n1; - } - checkkwd = 2; - n2 = pipeline(); - n3 = (union node *)stalloc(sizeof (struct nbinary)); - n3->type = t; - n3->nbinary.ch1 = n1; - n3->nbinary.ch2 = n2; - n1 = n3; - } -} - - - -static union node * -pipeline() { - union node *n1, *n2, *pipenode; - struct nodelist *lp, *prev; - int negate; - - negate = 0; - TRACE(("pipeline: entered\n")); - if (readtoken() == TNOT) { - negate = !negate; - checkkwd = 1; - } else - tokpushback++; - n1 = command(); - if (readtoken() == TPIPE) { - pipenode = (union node *)stalloc(sizeof (struct npipe)); - pipenode->type = NPIPE; - pipenode->npipe.backgnd = 0; - lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); - pipenode->npipe.cmdlist = lp; - lp->n = n1; - do { - prev = lp; - lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); - checkkwd = 2; - lp->n = command(); - prev->next = lp; - } while (readtoken() == TPIPE); - lp->next = NULL; - n1 = pipenode; - } - tokpushback++; - if (negate) { - n2 = (union node *)stalloc(sizeof (struct nnot)); - n2->type = NNOT; - n2->nnot.com = n1; - return n2; - } else - return n1; -} - - - -static union node * -command() { - union node *n1, *n2; - union node *ap, **app; - union node *cp, **cpp; - union node *redir, **rpp; - int t; - - redir = NULL; - n1 = NULL; - rpp = &redir; - - /* Check for redirection which may precede command */ - while (readtoken() == TREDIR) { - *rpp = n2 = redirnode; - rpp = &n2->nfile.next; - parsefname(); - } - tokpushback++; - - switch (readtoken()) { - case TIF: - n1 = (union node *)stalloc(sizeof (struct nif)); - n1->type = NIF; - n1->nif.test = list(0); - if (readtoken() != TTHEN) - synexpect(TTHEN); - n1->nif.ifpart = list(0); - n2 = n1; - while (readtoken() == TELIF) { - n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); - n2 = n2->nif.elsepart; - n2->type = NIF; - n2->nif.test = list(0); - if (readtoken() != TTHEN) - synexpect(TTHEN); - n2->nif.ifpart = list(0); - } - if (lasttoken == TELSE) - n2->nif.elsepart = list(0); - else { - n2->nif.elsepart = NULL; - tokpushback++; - } - if (readtoken() != TFI) - synexpect(TFI); - checkkwd = 1; - break; - case TWHILE: - case TUNTIL: { - int got; - n1 = (union node *)stalloc(sizeof (struct nbinary)); - n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; - n1->nbinary.ch1 = list(0); - if ((got=readtoken()) != TDO) { -TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); - synexpect(TDO); - } - n1->nbinary.ch2 = list(0); - if (readtoken() != TDONE) - synexpect(TDONE); - checkkwd = 1; - break; - } - case TFOR: - if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) - synerror("Bad for loop variable"); - n1 = (union node *)stalloc(sizeof (struct nfor)); - n1->type = NFOR; - n1->nfor.var = wordtext; - checkkwd = 1; - if (readtoken() == TIN) { - app = ≈ - while (readtoken() == TWORD) { - n2 = (union node *)stalloc(sizeof (struct narg)); - n2->type = NARG; - n2->narg.text = wordtext; - n2->narg.backquote = backquotelist; - *app = n2; - app = &n2->narg.next; - } - *app = NULL; - n1->nfor.args = ap; - if (lasttoken != TNL && lasttoken != TSEMI) - synexpect(-1); - } else { - static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, - '@', '=', '\0'}; - n2 = (union node *)stalloc(sizeof (struct narg)); - n2->type = NARG; - n2->narg.text = argvars; - n2->narg.backquote = NULL; - n2->narg.next = NULL; - n1->nfor.args = n2; - /* - * Newline or semicolon here is optional (but note - * that the original Bourne shell only allowed NL). - */ - if (lasttoken != TNL && lasttoken != TSEMI) - tokpushback++; - } - checkkwd = 2; - if (readtoken() != TDO) - synexpect(TDO); - n1->nfor.body = list(0); - if (readtoken() != TDONE) - synexpect(TDONE); - checkkwd = 1; - break; - case TCASE: - n1 = (union node *)stalloc(sizeof (struct ncase)); - n1->type = NCASE; - if (readtoken() != TWORD) - synexpect(TWORD); - n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); - n2->type = NARG; - n2->narg.text = wordtext; - n2->narg.backquote = backquotelist; - n2->narg.next = NULL; - do { - checkkwd = 1; - } while (readtoken() == TNL); - if (lasttoken != TIN) - synerror("expecting \"in\""); - cpp = &n1->ncase.cases; - checkkwd = 2, readtoken(); - do { - if (lasttoken == TLP) - readtoken(); - *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); - cp->type = NCLIST; - app = &cp->nclist.pattern; - for (;;) { - *app = ap = (union node *)stalloc(sizeof (struct narg)); - ap->type = NARG; - ap->narg.text = wordtext; - ap->narg.backquote = backquotelist; - if (checkkwd = 2, readtoken() != TPIPE) - break; - app = &ap->narg.next; - readtoken(); - } - ap->narg.next = NULL; - if (lasttoken != TRP) - synexpect(TRP); - cp->nclist.body = list(0); - - checkkwd = 2; - if ((t = readtoken()) != TESAC) { - if (t != TENDCASE) - synexpect(TENDCASE); - else - checkkwd = 2, readtoken(); - } - cpp = &cp->nclist.next; - } while(lasttoken != TESAC); - *cpp = NULL; - checkkwd = 1; - break; - case TLP: - n1 = (union node *)stalloc(sizeof (struct nredir)); - n1->type = NSUBSHELL; - n1->nredir.n = list(0); - n1->nredir.redirect = NULL; - if (readtoken() != TRP) - synexpect(TRP); - checkkwd = 1; - break; - case TBEGIN: - n1 = list(0); - if (readtoken() != TEND) - synexpect(TEND); - checkkwd = 1; - break; - /* Handle an empty command like other simple commands. */ - case TSEMI: - case TAND: - case TOR: - case TNL: - case TEOF: - case TRP: - case TBACKGND: - /* - * An empty command before a ; doesn't make much sense, and - * should certainly be disallowed in the case of `if ;'. - */ - if (!redir) - synexpect(-1); - case TWORD: - tokpushback++; - n1 = simplecmd(); - return n1; - default: - synexpect(-1); - /* NOTREACHED */ - } - - /* Now check for redirection which may follow command */ - while (readtoken() == TREDIR) { - *rpp = n2 = redirnode; - rpp = &n2->nfile.next; - parsefname(); - } - tokpushback++; - *rpp = NULL; - if (redir) { - if (n1->type != NSUBSHELL) { - n2 = (union node *)stalloc(sizeof (struct nredir)); - n2->type = NREDIR; - n2->nredir.n = n1; - n1 = n2; - } - n1->nredir.redirect = redir; - } - - return n1; -} - - -static union node * -simplecmd() { - union node *args, **app; - union node *n = NULL; - union node *vars, **vpp; - union node **rpp, *redir; - - args = NULL; - app = &args; - vars = NULL; - vpp = &vars; - redir = NULL; - rpp = &redir; - - checkalias = 2; - for (;;) { - switch (readtoken()) { - case TWORD: - case TASSIGN: - n = (union node *)stalloc(sizeof (struct narg)); - n->type = NARG; - n->narg.text = wordtext; - n->narg.backquote = backquotelist; - if (lasttoken == TWORD) { - *app = n; - app = &n->narg.next; - } else { - *vpp = n; - vpp = &n->narg.next; - } - break; - case TREDIR: - *rpp = n = redirnode; - rpp = &n->nfile.next; - parsefname(); /* read name of redirection file */ - break; - case TLP: - if ( - args && app == &args->narg.next && - !vars && !redir - ) { - /* We have a function */ - if (readtoken() != TRP) - synexpect(TRP); - n->type = NDEFUN; - checkkwd = 2; - n->narg.next = command(); - return n; - } - /* fall through */ - default: - tokpushback++; - goto out; - } - } -out: - *app = NULL; - *vpp = NULL; - *rpp = NULL; - n = (union node *)stalloc(sizeof (struct ncmd)); - n->type = NCMD; - n->ncmd.backgnd = 0; - n->ncmd.args = args; - n->ncmd.assign = vars; - n->ncmd.redirect = redir; - return n; -} - -static union node * -makename(void) { - union node *n; - - n = (union node *)stalloc(sizeof (struct narg)); - n->type = NARG; - n->narg.next = NULL; - n->narg.text = wordtext; - n->narg.backquote = backquotelist; - return n; -} - -static void fixredir(union node *n, const char *text, int err) -{ - TRACE(("Fix redir %s %d\n", text, err)); - if (!err) - n->ndup.vname = NULL; - - if (is_digit(text[0]) && text[1] == '\0') - n->ndup.dupfd = digit_val(text[0]); - else if (text[0] == '-' && text[1] == '\0') - n->ndup.dupfd = -1; - else { - - if (err) - synerror("Bad fd number"); - else - n->ndup.vname = makename(); - } -} - - -static void -parsefname(void) { - union node *n = redirnode; - - if (readtoken() != TWORD) - synexpect(-1); - if (n->type == NHERE) { - struct heredoc *here = heredoc; - struct heredoc *p; - int i; - - if (quoteflag == 0) - n->type = NXHERE; - TRACE(("Here document %d\n", n->type)); - if (here->striptabs) { - while (*wordtext == '\t') - wordtext++; - } - if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) - synerror("Illegal eof marker for << redirection"); - rmescapes(wordtext); - here->eofmark = wordtext; - here->next = NULL; - if (heredoclist == NULL) - heredoclist = here; - else { - for (p = heredoclist ; p->next ; p = p->next); - p->next = here; - } - } else if (n->type == NTOFD || n->type == NFROMFD) { - fixredir(n, wordtext, 0); - } else { - n->nfile.fname = makename(); - } -} - - -/* - * Input any here documents. - */ - -static void -parseheredoc() { - struct heredoc *here; - union node *n; - - while (heredoclist) { - here = heredoclist; - heredoclist = here->next; - if (needprompt) { - setprompt(2); - needprompt = 0; - } - readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, - here->eofmark, here->striptabs); - n = (union node *)stalloc(sizeof (struct narg)); - n->narg.type = NARG; - n->narg.next = NULL; - n->narg.text = wordtext; - n->narg.backquote = backquotelist; - here->here->nhere.doc = n; - } -} - -static int -peektoken() { - int t; - - t = readtoken(); - tokpushback++; - return (t); -} - -static int -readtoken() { - int t; - -#ifdef ASH_ALIAS - int savecheckalias = checkalias; - int savecheckkwd = checkkwd; - struct alias *ap; -#endif - -#ifdef DEBUG - int alreadyseen = tokpushback; -#endif - -#ifdef ASH_ALIAS -top: -#endif - - t = xxreadtoken(); - -#ifdef ASH_ALIAS - checkalias = savecheckalias; -#endif - - if (checkkwd) { - /* - * eat newlines - */ - if (checkkwd == 2) { - checkkwd = 0; - while (t == TNL) { - parseheredoc(); - t = xxreadtoken(); - } - } - checkkwd = 0; - /* - * check for keywords - */ - if (t == TWORD && !quoteflag) - { - const char *const *pp; - - if ((pp = findkwd(wordtext))) { - lasttoken = t = pp - parsekwd + KWDOFFSET; - TRACE(("keyword %s recognized\n", tokname[t])); - goto out; - } - } - } - - - if (t != TWORD) { - if (t != TREDIR) { - checkalias = 0; - } - } else if (checkalias == 2 && isassignment(wordtext)) { - lasttoken = t = TASSIGN; -#ifdef ASH_ALIAS - } else if (checkalias) { - if (!quoteflag && (ap = lookupalias(wordtext, 1)) != NULL) { - if (*ap->val) { - pushstring(ap->val, strlen(ap->val), ap); - } - checkkwd = savecheckkwd; - goto top; - } - checkalias = 0; -#endif - } -out: -#ifdef DEBUG - if (!alreadyseen) - TRACE(("token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : "")); - else - TRACE(("reread token %s %s\n", tokname[t], t == TWORD || t == TASSIGN ? wordtext : "")); -#endif - return (t); -} - - -/* - * Read the next input token. - * If the token is a word, we set backquotelist to the list of cmds in - * backquotes. We set quoteflag to true if any part of the word was - * quoted. - * If the token is TREDIR, then we set redirnode to a structure containing - * the redirection. - * In all cases, the variable startlinno is set to the number of the line - * on which the token starts. - * - * [Change comment: here documents and internal procedures] - * [Readtoken shouldn't have any arguments. Perhaps we should make the - * word parsing code into a separate routine. In this case, readtoken - * doesn't need to have any internal procedures, but parseword does. - * We could also make parseoperator in essence the main routine, and - * have parseword (readtoken1?) handle both words and redirection.] - */ - -#define RETURN(token) return lasttoken = token - -static int -xxreadtoken() { - int c; - - if (tokpushback) { - tokpushback = 0; - return lasttoken; - } - if (needprompt) { - setprompt(2); - needprompt = 0; - } - startlinno = plinno; - for (;;) { /* until token or start of word found */ - c = pgetc_macro(); - switch (c) { - case ' ': case '\t': -#ifdef ASH_ALIAS - case PEOA: -#endif - continue; - case '#': - while ((c = pgetc()) != '\n' && c != PEOF); - pungetc(); - continue; - case '\\': - if (pgetc() == '\n') { - startlinno = ++plinno; - if (doprompt) - setprompt(2); - else - setprompt(0); - continue; - } - pungetc(); - goto breakloop; - case '\n': - plinno++; - needprompt = doprompt; - RETURN(TNL); - case PEOF: - RETURN(TEOF); - case '&': - if (pgetc() == '&') - RETURN(TAND); - pungetc(); - RETURN(TBACKGND); - case '|': - if (pgetc() == '|') - RETURN(TOR); - pungetc(); - RETURN(TPIPE); - case ';': - if (pgetc() == ';') - RETURN(TENDCASE); - pungetc(); - RETURN(TSEMI); - case '(': - RETURN(TLP); - case ')': - RETURN(TRP); - default: - goto breakloop; - } - } -breakloop: - return readtoken1(c, BASESYNTAX, (char *)NULL, 0); -#undef RETURN -} - - - -/* - * If eofmark is NULL, read a word or a redirection symbol. If eofmark - * is not NULL, read a here document. In the latter case, eofmark is the - * word which marks the end of the document and striptabs is true if - * leading tabs should be stripped from the document. The argument firstc - * is the first character of the input token or document. - * - * Because C does not have internal subroutines, I have simulated them - * using goto's to implement the subroutine linkage. The following macros - * will run code that appears at the end of readtoken1. - */ - -#define CHECKEND() {goto checkend; checkend_return:;} -#define PARSEREDIR() {goto parseredir; parseredir_return:;} -#define PARSESUB() {goto parsesub; parsesub_return:;} -#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} -#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} -#define PARSEARITH() {goto parsearith; parsearith_return:;} - -static int -readtoken1(firstc, syntax, eofmark, striptabs) - int firstc; - char const *syntax; - char *eofmark; - int striptabs; - { - int c = firstc; - char *out; - int len; - char line[EOFMARKLEN + 1]; - struct nodelist *bqlist; - int quotef; - int dblquote; - int varnest; /* levels of variables expansion */ - int arinest; /* levels of arithmetic expansion */ - int parenlevel; /* levels of parens in arithmetic */ - int dqvarnest; /* levels of variables expansion within double quotes */ - int oldstyle; - char const *prevsyntax; /* syntax before arithmetic */ -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &out; - (void) "ef; - (void) &dblquote; - (void) &varnest; - (void) &arinest; - (void) &parenlevel; - (void) &dqvarnest; - (void) &oldstyle; - (void) &prevsyntax; - (void) &syntax; -#endif - - startlinno = plinno; - dblquote = 0; - if (syntax == DQSYNTAX) - dblquote = 1; - quotef = 0; - bqlist = NULL; - varnest = 0; - arinest = 0; - parenlevel = 0; - dqvarnest = 0; - - STARTSTACKSTR(out); - loop: { /* for each line, until end of word */ - CHECKEND(); /* set c to PEOF if at end of here document */ - for (;;) { /* until end of line or end of word */ - CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ - switch(syntax[c]) { - case CNL: /* '\n' */ - if (syntax == BASESYNTAX) - goto endword; /* exit outer loop */ - USTPUTC(c, out); - plinno++; - if (doprompt) - setprompt(2); - else - setprompt(0); - c = pgetc(); - goto loop; /* continue outer loop */ - case CWORD: - USTPUTC(c, out); - break; - case CCTL: - if ((eofmark == NULL || dblquote) && - dqvarnest == 0) - USTPUTC(CTLESC, out); - USTPUTC(c, out); - break; - case CBACK: /* backslash */ - c = pgetc2(); - if (c == PEOF) { - USTPUTC('\\', out); - pungetc(); - } else if (c == '\n') { - if (doprompt) - setprompt(2); - else - setprompt(0); - } else { - if (dblquote && c != '\\' && c != '`' && c != '$' - && (c != '"' || eofmark != NULL)) - USTPUTC('\\', out); - if (SQSYNTAX[c] == CCTL) - USTPUTC(CTLESC, out); - else if (eofmark == NULL) - USTPUTC(CTLQUOTEMARK, out); - USTPUTC(c, out); - quotef++; - } - break; - case CSQUOTE: - if (eofmark == NULL) - USTPUTC(CTLQUOTEMARK, out); - syntax = SQSYNTAX; - break; - case CDQUOTE: - if (eofmark == NULL) - USTPUTC(CTLQUOTEMARK, out); - syntax = DQSYNTAX; - dblquote = 1; - break; - case CENDQUOTE: - if (eofmark != NULL && arinest == 0 && - varnest == 0) { - USTPUTC(c, out); - } else { - if (arinest) { - syntax = ARISYNTAX; - dblquote = 0; - } else if (eofmark == NULL && - dqvarnest == 0) { - syntax = BASESYNTAX; - dblquote = 0; - } - quotef++; - } - break; - case CVAR: /* '$' */ - PARSESUB(); /* parse substitution */ - break; - case CENDVAR: /* '}' */ - if (varnest > 0) { - varnest--; - if (dqvarnest > 0) { - dqvarnest--; - } - USTPUTC(CTLENDVAR, out); - } else { - USTPUTC(c, out); - } - break; -#ifdef ASH_MATH_SUPPORT - case CLP: /* '(' in arithmetic */ - parenlevel++; - USTPUTC(c, out); - break; - case CRP: /* ')' in arithmetic */ - if (parenlevel > 0) { - USTPUTC(c, out); - --parenlevel; - } else { - if (pgetc() == ')') { - if (--arinest == 0) { - USTPUTC(CTLENDARI, out); - syntax = prevsyntax; - if (syntax == DQSYNTAX) - dblquote = 1; - else - dblquote = 0; - } else - USTPUTC(')', out); - } else { - /* - * unbalanced parens - * (don't 2nd guess - no error) - */ - pungetc(); - USTPUTC(')', out); - } - } - break; -#endif - case CBQUOTE: /* '`' */ - PARSEBACKQOLD(); - break; - case CENDFILE: - goto endword; /* exit outer loop */ - case CIGN: - break; - default: - if (varnest == 0) - goto endword; /* exit outer loop */ -#ifdef ASH_ALIAS - if (c != PEOA) -#endif - USTPUTC(c, out); - - } - c = pgetc_macro(); - } - } -endword: - if (syntax == ARISYNTAX) - synerror("Missing '))'"); - if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) - synerror("Unterminated quoted string"); - if (varnest != 0) { - startlinno = plinno; - synerror("Missing '}'"); - } - USTPUTC('\0', out); - len = out - stackblock(); - out = stackblock(); - if (eofmark == NULL) { - if ((c == '>' || c == '<') - && quotef == 0 - && len <= 2 - && (*out == '\0' || is_digit(*out))) { - PARSEREDIR(); - return lasttoken = TREDIR; - } else { - pungetc(); - } - } - quoteflag = quotef; - backquotelist = bqlist; - grabstackblock(len); - wordtext = out; - return lasttoken = TWORD; -/* end of readtoken routine */ - - - -/* - * Check to see whether we are at the end of the here document. When this - * is called, c is set to the first character of the next input line. If - * we are at the end of the here document, this routine sets the c to PEOF. - */ - -checkend: { - if (eofmark) { -#ifdef ASH_ALIAS - if (c == PEOA) { - c = pgetc2(); - } -#endif - if (striptabs) { - while (c == '\t') { - c = pgetc2(); - } - } - if (c == *eofmark) { - if (pfgets(line, sizeof line) != NULL) { - char *p, *q; - - p = line; - for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); - if (*p == '\n' && *q == '\0') { - c = PEOF; - plinno++; - needprompt = doprompt; - } else { - pushstring(line, strlen(line), NULL); - } - } - } - } - goto checkend_return; -} - - -/* - * Parse a redirection operator. The variable "out" points to a string - * specifying the fd to be redirected. The variable "c" contains the - * first character of the redirection operator. - */ - -parseredir: { - char fd = *out; - union node *np; - - np = (union node *)stalloc(sizeof (struct nfile)); - if (c == '>') { - np->nfile.fd = 1; - c = pgetc(); - if (c == '>') - np->type = NAPPEND; - else if (c == '&') - np->type = NTOFD; - else if (c == '|') - np->type = NTOOV; - else { - np->type = NTO; - pungetc(); - } - } else { /* c == '<' */ - np->nfile.fd = 0; - switch (c = pgetc()) { - case '<': - if (sizeof (struct nfile) != sizeof (struct nhere)) { - np = (union node *)stalloc(sizeof (struct nhere)); - np->nfile.fd = 0; - } - np->type = NHERE; - heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); - heredoc->here = np; - if ((c = pgetc()) == '-') { - heredoc->striptabs = 1; - } else { - heredoc->striptabs = 0; - pungetc(); - } - break; - - case '&': - np->type = NFROMFD; - break; - - case '>': - np->type = NFROMTO; - break; - - default: - np->type = NFROM; - pungetc(); - break; - } - } - if (fd != '\0') - np->nfile.fd = digit_val(fd); - redirnode = np; - goto parseredir_return; -} - - -/* - * Parse a substitution. At this point, we have read the dollar sign - * and nothing else. - */ - -parsesub: { - int subtype; - int typeloc; - int flags; - char *p; - static const char types[] = "}-+?="; - - c = pgetc(); - if ( - c <= PEOA || - (c != '(' && c != '{' && !is_name(c) && !is_special(c)) - ) { - USTPUTC('$', out); - pungetc(); - } else if (c == '(') { /* $(command) or $((arith)) */ - if (pgetc() == '(') { - PARSEARITH(); - } else { - pungetc(); - PARSEBACKQNEW(); - } - } else { - USTPUTC(CTLVAR, out); - typeloc = out - stackblock(); - USTPUTC(VSNORMAL, out); - subtype = VSNORMAL; - if (c == '{') { - c = pgetc(); - if (c == '#') { - if ((c = pgetc()) == '}') - c = '#'; - else - subtype = VSLENGTH; - } - else - subtype = 0; - } - if (c > PEOA && is_name(c)) { - do { - STPUTC(c, out); - c = pgetc(); - } while (c > PEOA && is_in_name(c)); - } else if (is_digit(c)) { - do { - USTPUTC(c, out); - c = pgetc(); - } while (is_digit(c)); - } - else if (is_special(c)) { - USTPUTC(c, out); - c = pgetc(); - } - else -badsub: synerror("Bad substitution"); - - STPUTC('=', out); - flags = 0; - if (subtype == 0) { - switch (c) { - case ':': - flags = VSNUL; - c = pgetc(); - /*FALLTHROUGH*/ - default: - p = strchr(types, c); - if (p == NULL) - goto badsub; - subtype = p - types + VSNORMAL; - break; - case '%': - case '#': - { - int cc = c; - subtype = c == '#' ? VSTRIMLEFT : - VSTRIMRIGHT; - c = pgetc(); - if (c == cc) - subtype++; - else - pungetc(); - break; - } - } - } else { - pungetc(); - } - if (dblquote || arinest) - flags |= VSQUOTE; - *(stackblock() + typeloc) = subtype | flags; - if (subtype != VSNORMAL) { - varnest++; - if (dblquote) { - dqvarnest++; - } - } - } - goto parsesub_return; -} - - -/* - * Called to parse command substitutions. Newstyle is set if the command - * is enclosed inside $(...); nlpp is a pointer to the head of the linked - * list of commands (passed by reference), and savelen is the number of - * characters on the top of the stack which must be preserved. - */ - -parsebackq: { - struct nodelist **nlpp; - int savepbq; - union node *n; - char *volatile str; - struct jmploc jmploc; - struct jmploc *volatile savehandler; - int savelen; - int saveprompt; -#ifdef __GNUC__ - (void) &saveprompt; -#endif - - savepbq = parsebackquote; - if (setjmp(jmploc.loc)) { - if (str) - ckfree(str); - parsebackquote = 0; - handler = savehandler; - longjmp(handler->loc, 1); - } - INTOFF; - str = NULL; - savelen = out - stackblock(); - if (savelen > 0) { - str = ckmalloc(savelen); - memcpy(str, stackblock(), savelen); - } - savehandler = handler; - handler = &jmploc; - INTON; - if (oldstyle) { - /* We must read until the closing backquote, giving special - treatment to some slashes, and then push the string and - reread it as input, interpreting it normally. */ - char *pout; - int pc; - int psavelen; - char *pstr; - - - STARTSTACKSTR(pout); - for (;;) { - if (needprompt) { - setprompt(2); - needprompt = 0; - } - switch (pc = pgetc()) { - case '`': - goto done; - - case '\\': - if ((pc = pgetc()) == '\n') { - plinno++; - if (doprompt) - setprompt(2); - else - setprompt(0); - /* - * If eating a newline, avoid putting - * the newline into the new character - * stream (via the STPUTC after the - * switch). - */ - continue; - } - if (pc != '\\' && pc != '`' && pc != '$' - && (!dblquote || pc != '"')) - STPUTC('\\', pout); - if (pc > PEOA) { - break; - } - /* fall through */ - - case PEOF: -#ifdef ASH_ALIAS - case PEOA: -#endif - startlinno = plinno; - synerror("EOF in backquote substitution"); - - case '\n': - plinno++; - needprompt = doprompt; - break; - - default: - break; - } - STPUTC(pc, pout); - } -done: - STPUTC('\0', pout); - psavelen = pout - stackblock(); - if (psavelen > 0) { - pstr = grabstackstr(pout); - setinputstring(pstr); - } - } - nlpp = &bqlist; - while (*nlpp) - nlpp = &(*nlpp)->next; - *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); - (*nlpp)->next = NULL; - parsebackquote = oldstyle; - - if (oldstyle) { - saveprompt = doprompt; - doprompt = 0; - } - - n = list(0); - - if (oldstyle) - doprompt = saveprompt; - else { - if (readtoken() != TRP) - synexpect(TRP); - } - - (*nlpp)->n = n; - if (oldstyle) { - /* - * Start reading from old file again, ignoring any pushed back - * tokens left from the backquote parsing - */ - popfile(); - tokpushback = 0; - } - while (stackblocksize() <= savelen) - growstackblock(); - STARTSTACKSTR(out); - if (str) { - memcpy(out, str, savelen); - STADJUST(savelen, out); - INTOFF; - ckfree(str); - str = NULL; - INTON; - } - parsebackquote = savepbq; - handler = savehandler; - if (arinest || dblquote) - USTPUTC(CTLBACKQ | CTLQUOTE, out); - else - USTPUTC(CTLBACKQ, out); - if (oldstyle) - goto parsebackq_oldreturn; - else - goto parsebackq_newreturn; -} - -/* - * Parse an arithmetic expansion (indicate start of one and set state) - */ -parsearith: { - - if (++arinest == 1) { - prevsyntax = syntax; - syntax = ARISYNTAX; - USTPUTC(CTLARI, out); - if (dblquote) - USTPUTC('"',out); - else - USTPUTC(' ',out); - } else { - /* - * we collapse embedded arithmetic expansion to - * parenthesis, which should be equivalent - */ - USTPUTC('(', out); - } - goto parsearith_return; -} - -} /* end of readtoken */ - - -/* - * Returns true if the text contains nothing to expand (no dollar signs - * or backquotes). - */ - -static int -noexpand(text) - char *text; - { - char *p; - char c; - - p = text; - while ((c = *p++) != '\0') { - if (c == CTLQUOTEMARK) - continue; - if (c == CTLESC) - p++; - else if (BASESYNTAX[(int)c] == CCTL) - return 0; - } - return 1; -} - - -/* - * Return true if the argument is a legal variable name (a letter or - * underscore followed by zero or more letters, underscores, and digits). - */ - -static int -goodname(const char *name) -{ - const char *p; - - p = name; - if (! is_name(*p)) - return 0; - while (*++p) { - if (! is_in_name(*p)) - return 0; - } - return 1; -} - - -/* - * Called when an unexpected token is read during the parse. The argument - * is the token that is expected, or -1 if more than one type of token can - * occur at this point. - */ - -static void -synexpect(token) - int token; -{ - char msg[64]; - - if (token >= 0) { - snprintf(msg, 64, "%s unexpected (expecting %s)", - tokname[lasttoken], tokname[token]); - } else { - snprintf(msg, 64, "%s unexpected", tokname[lasttoken]); - } - synerror(msg); - /* NOTREACHED */ -} - - -static void -synerror(const char *msg) -{ - if (commandname) - out2fmt("%s: %d: ", commandname, startlinno); - out2fmt("Syntax error: %s\n", msg); - error((char *)NULL); - /* NOTREACHED */ -} - - -/* - * called by editline -- any expansions to the prompt - * should be added here. - */ -static void -setprompt(int whichprompt) -{ - char *prompt; - switch (whichprompt) { - case 1: - prompt = ps1val(); - break; - case 2: - prompt = ps2val(); - break; - default: /* 0 */ - prompt = ""; - } - putprompt(prompt); -} - - -/* - * Code for dealing with input/output redirection. - */ - -#define EMPTY -2 /* marks an unused slot in redirtab */ -#ifndef PIPE_BUF -# define PIPESIZE 4096 /* amount of buffering in a pipe */ -#else -# define PIPESIZE PIPE_BUF -#endif - - -/* - * Open a file in noclobber mode. - * The code was copied from bash. - */ -static inline int -noclobberopen(const char *fname) -{ - int r, fd; - struct stat finfo, finfo2; - - /* - * If the file exists and is a regular file, return an error - * immediately. - */ - r = stat(fname, &finfo); - if (r == 0 && S_ISREG(finfo.st_mode)) { - errno = EEXIST; - return -1; - } - - /* - * If the file was not present (r != 0), make sure we open it - * exclusively so that if it is created before we open it, our open - * will fail. Make sure that we do not truncate an existing file. - * Note that we don't turn on O_EXCL unless the stat failed -- if the - * file was not a regular file, we leave O_EXCL off. - */ - if (r != 0) - return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666); - fd = open(fname, O_WRONLY|O_CREAT, 0666); - - /* If the open failed, return the file descriptor right away. */ - if (fd < 0) - return fd; - - /* - * OK, the open succeeded, but the file may have been changed from a - * non-regular file to a regular file between the stat and the open. - * We are assuming that the O_EXCL open handles the case where FILENAME - * did not exist and is symlinked to an existing file between the stat - * and open. - */ - - /* - * If we can open it and fstat the file descriptor, and neither check - * revealed that it was a regular file, and the file has not been - * replaced, return the file descriptor. - */ - if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) && - finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) - return fd; - - /* The file has been replaced. badness. */ - close(fd); - errno = EEXIST; - return -1; -} - -/* - * Handle here documents. Normally we fork off a process to write the - * data to a pipe. If the document is short, we can stuff the data in - * the pipe without forking. - */ - -static inline int -openhere(const union node *redir) -{ - int pip[2]; - int len = 0; - - if (pipe(pip) < 0) - error("Pipe call failed"); - if (redir->type == NHERE) { - len = strlen(redir->nhere.doc->narg.text); - if (len <= PIPESIZE) { - xwrite(pip[1], redir->nhere.doc->narg.text, len); - goto out; - } - } - if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) { - close(pip[0]); - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - signal(SIGHUP, SIG_IGN); -#ifdef SIGTSTP - signal(SIGTSTP, SIG_IGN); -#endif - signal(SIGPIPE, SIG_DFL); - if (redir->type == NHERE) - xwrite(pip[1], redir->nhere.doc->narg.text, len); - else - expandhere(redir->nhere.doc, pip[1]); - _exit(0); - } -out: - close(pip[1]); - return pip[0]; -} - - -static inline int -openredirect(const union node *redir) -{ - char *fname; - int f; - - switch (redir->nfile.type) { - case NFROM: - fname = redir->nfile.expfname; - if ((f = open(fname, O_RDONLY)) < 0) - goto eopen; - break; - case NFROMTO: - fname = redir->nfile.expfname; - if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) - goto ecreate; - break; - case NTO: - /* Take care of noclobber mode. */ - if (Cflag) { - fname = redir->nfile.expfname; - if ((f = noclobberopen(fname)) < 0) - goto ecreate; - break; - } - case NTOOV: - fname = redir->nfile.expfname; -#ifdef O_CREAT - if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) - goto ecreate; -#else - if ((f = creat(fname, 0666)) < 0) - goto ecreate; -#endif - break; - case NAPPEND: - fname = redir->nfile.expfname; -#ifdef O_APPEND - if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) - goto ecreate; -#else - if ((f = open(fname, O_WRONLY)) < 0 - && (f = creat(fname, 0666)) < 0) - goto ecreate; - lseek(f, (off_t)0, 2); -#endif - break; - default: -#ifdef DEBUG - abort(); -#endif - /* Fall through to eliminate warning. */ - case NTOFD: - case NFROMFD: - f = -1; - break; - case NHERE: - case NXHERE: - f = openhere(redir); - break; - } - - return f; -ecreate: - error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); -eopen: - error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); -} - - -/* - * Process a list of redirection commands. If the REDIR_PUSH flag is set, - * old file descriptors are stashed away so that the redirection can be - * undone by calling popredir. If the REDIR_BACKQ flag is set, then the - * standard output, and the standard error if it becomes a duplicate of - * stdout. - */ - -static void -redirect(union node *redir, int flags) -{ - union node *n; - struct redirtab *sv = NULL; - int i; - int fd; - int newfd; - int try; - int fd1dup = flags & REDIR_BACKQ;; /* stdout `cmd` redir to pipe */ - - if (flags & REDIR_PUSH) { - sv = ckmalloc(sizeof (struct redirtab)); - for (i = 0 ; i < 10 ; i++) - sv->renamed[i] = EMPTY; - sv->next = redirlist; - redirlist = sv; - } - for (n = redir ; n ; n = n->nfile.next) { - fd = n->nfile.fd; - try = 0; - if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) && - n->ndup.dupfd == fd) - continue; /* redirect from/to same file descriptor */ - - INTOFF; - newfd = openredirect(n); - if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { - if (newfd == fd) { - try++; - } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) { - switch (errno) { - case EBADF: - if (!try) { - dupredirect(n, newfd, fd1dup); - try++; - break; - } - /* FALLTHROUGH*/ - default: - if (newfd >= 0) { - close(newfd); - } - INTON; - error("%d: %m", fd); - /* NOTREACHED */ - } - } - if (!try) { - close(fd); - if (flags & REDIR_PUSH) { - sv->renamed[fd] = i; - } - } - } else if (fd != newfd) { - close(fd); - } - if (fd == 0) - fd0_redirected++; - if (!try) - dupredirect(n, newfd, fd1dup); - INTON; - } -} - - -static void -dupredirect(const union node *redir, int f, int fd1dup) -{ - int fd = redir->nfile.fd; - - if(fd==1) - fd1dup = 0; - if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { - if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ - if (redir->ndup.dupfd!=1 || fd1dup!=1) - dup_as_newfd(redir->ndup.dupfd, fd); - } - return; - } - - if (f != fd) { - dup_as_newfd(f, fd); - close(f); - } - return; -} - - - -/* - * Undo the effects of the last redirection. - */ - -static void -popredir(void) -{ - struct redirtab *rp = redirlist; - int i; - - INTOFF; - for (i = 0 ; i < 10 ; i++) { - if (rp->renamed[i] != EMPTY) { - if (i == 0) - fd0_redirected--; - close(i); - if (rp->renamed[i] >= 0) { - dup_as_newfd(rp->renamed[i], i); - close(rp->renamed[i]); - } - } - } - redirlist = rp->next; - ckfree(rp); - INTON; -} - -/* - * Discard all saved file descriptors. - */ - -static void -clearredir(void) { - struct redirtab *rp; - int i; - - for (rp = redirlist ; rp ; rp = rp->next) { - for (i = 0 ; i < 10 ; i++) { - if (rp->renamed[i] >= 0) { - close(rp->renamed[i]); - } - rp->renamed[i] = EMPTY; - } - } -} - - -/* - * Copy a file descriptor to be >= to. Returns -1 - * if the source file descriptor is closed, EMPTY if there are no unused - * file descriptors left. - */ - -static int -dup_as_newfd(from, to) - int from; - int to; -{ - int newfd; - - newfd = fcntl(from, F_DUPFD, to); - if (newfd < 0) { - if (errno == EMFILE) - return EMPTY; - else - error("%d: %m", from); - } - return newfd; -} - -/*#ifdef __weak_alias -__weak_alias(getmode,_getmode) -__weak_alias(setmode,_setmode) -#endif*/ - -#ifndef S_ISTXT -#if defined(__GLIBC__) && __GLIBC__ >= 2 -#define S_ISTXT __S_ISVTX -#else -#define S_ISTXT S_ISVTX -#endif -#endif - -#define SET_LEN 6 /* initial # of bitcmd struct to malloc */ -#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */ - -typedef struct bitcmd { - char cmd; - char cmd2; - mode_t bits; -} BITCMD; - -#define CMD2_CLR 0x01 -#define CMD2_SET 0x02 -#define CMD2_GBITS 0x04 -#define CMD2_OBITS 0x08 -#define CMD2_UBITS 0x10 - -static BITCMD *addcmd (BITCMD *, int, int, int, u_int); -static void compress_mode (BITCMD *); -#ifdef SETMODE_DEBUG -static void dumpmode (BITCMD *); -#endif - -/* - * Given the old mode and an array of bitcmd structures, apply the operations - * described in the bitcmd structures to the old mode, and return the new mode. - * Note that there is no '=' command; a strict assignment is just a '-' (clear - * bits) followed by a '+' (set bits). - */ -static mode_t -getmode(bbox, omode) - const void *bbox; - mode_t omode; -{ - const BITCMD *set; - mode_t clrval, newmode, value; - - _DIAGASSERT(bbox != NULL); - - set = (const BITCMD *)bbox; - newmode = omode; - for (value = 0;; set++) - switch(set->cmd) { - /* - * When copying the user, group or other bits around, we "know" - * where the bits are in the mode so that we can do shifts to - * copy them around. If we don't use shifts, it gets real - * grundgy with lots of single bit checks and bit sets. - */ - case 'u': - value = (newmode & S_IRWXU) >> 6; - goto common; - - case 'g': - value = (newmode & S_IRWXG) >> 3; - goto common; - - case 'o': - value = newmode & S_IRWXO; -common: if (set->cmd2 & CMD2_CLR) { - clrval = - (set->cmd2 & CMD2_SET) ? S_IRWXO : value; - if (set->cmd2 & CMD2_UBITS) - newmode &= ~((clrval<<6) & set->bits); - if (set->cmd2 & CMD2_GBITS) - newmode &= ~((clrval<<3) & set->bits); - if (set->cmd2 & CMD2_OBITS) - newmode &= ~(clrval & set->bits); - } - if (set->cmd2 & CMD2_SET) { - if (set->cmd2 & CMD2_UBITS) - newmode |= (value<<6) & set->bits; - if (set->cmd2 & CMD2_GBITS) - newmode |= (value<<3) & set->bits; - if (set->cmd2 & CMD2_OBITS) - newmode |= value & set->bits; - } - break; - - case '+': - newmode |= set->bits; - break; - - case '-': - newmode &= ~set->bits; - break; - - case 'X': - if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH)) - newmode |= set->bits; - break; - - case '\0': - default: -#ifdef SETMODE_DEBUG - (void)printf("getmode:%04o -> %04o\n", omode, newmode); -#endif - return (newmode); - } -} - -#define ADDCMD(a, b, c, d) do { \ - if (set >= endset) { \ - BITCMD *newset; \ - setlen += SET_LEN_INCR; \ - newset = realloc(saveset, sizeof(BITCMD) * setlen); \ - if (newset == NULL) { \ - free(saveset); \ - return (NULL); \ - } \ - set = newset + (set - saveset); \ - saveset = newset; \ - endset = newset + (setlen - 2); \ - } \ - set = addcmd(set, (a), (b), (c), (d)); \ -} while (/*CONSTCOND*/0) - -#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) - -static void * -setmode(p) - const char *p; -{ - int perm, who; - char op, *ep; - BITCMD *set, *saveset, *endset; - sigset_t mysigset, sigoset; - mode_t mask; - int equalopdone = 0; /* pacify gcc */ - int permXbits, setlen; - - if (!*p) - return (NULL); - - /* - * Get a copy of the mask for the permissions that are mask relative. - * Flip the bits, we want what's not set. Since it's possible that - * the caller is opening files inside a signal handler, protect them - * as best we can. - */ - sigfillset(&mysigset); - (void)sigprocmask(SIG_BLOCK, &mysigset, &sigoset); - (void)umask(mask = umask(0)); - mask = ~mask; - (void)sigprocmask(SIG_SETMASK, &sigoset, NULL); - - setlen = SET_LEN + 2; - - if ((set = malloc((u_int)(sizeof(BITCMD) * setlen))) == NULL) - return (NULL); - saveset = set; - endset = set + (setlen - 2); - - /* - * If an absolute number, get it and return; disallow non-octal digits - * or illegal bits. - */ - if (is_digit((unsigned char)*p)) { - perm = (mode_t)strtol(p, &ep, 8); - if (*ep || perm & ~(STANDARD_BITS|S_ISTXT)) { - free(saveset); - return (NULL); - } - ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask); - set->cmd = 0; - return (saveset); - } - - /* - * Build list of structures to set/clear/copy bits as described by - * each clause of the symbolic mode. - */ - for (;;) { - /* First, find out which bits might be modified. */ - for (who = 0;; ++p) { - switch (*p) { - case 'a': - who |= STANDARD_BITS; - break; - case 'u': - who |= S_ISUID|S_IRWXU; - break; - case 'g': - who |= S_ISGID|S_IRWXG; - break; - case 'o': - who |= S_IRWXO; - break; - default: - goto getop; - } - } - -getop: if ((op = *p++) != '+' && op != '-' && op != '=') { - free(saveset); - return (NULL); - } - if (op == '=') - equalopdone = 0; - - who &= ~S_ISTXT; - for (perm = 0, permXbits = 0;; ++p) { - switch (*p) { - case 'r': - perm |= S_IRUSR|S_IRGRP|S_IROTH; - break; - case 's': - /* - * If specific bits where requested and - * only "other" bits ignore set-id. - */ - if (who == 0 || (who & ~S_IRWXO)) - perm |= S_ISUID|S_ISGID; - break; - case 't': - /* - * If specific bits where requested and - * only "other" bits ignore set-id. - */ - if (who == 0 || (who & ~S_IRWXO)) { - who |= S_ISTXT; - perm |= S_ISTXT; - } - break; - case 'w': - perm |= S_IWUSR|S_IWGRP|S_IWOTH; - break; - case 'X': - permXbits = S_IXUSR|S_IXGRP|S_IXOTH; - break; - case 'x': - perm |= S_IXUSR|S_IXGRP|S_IXOTH; - break; - case 'u': - case 'g': - case 'o': - /* - * When ever we hit 'u', 'g', or 'o', we have - * to flush out any partial mode that we have, - * and then do the copying of the mode bits. - */ - if (perm) { - ADDCMD(op, who, perm, mask); - perm = 0; - } - if (op == '=') - equalopdone = 1; - if (op == '+' && permXbits) { - ADDCMD('X', who, permXbits, mask); - permXbits = 0; - } - ADDCMD(*p, who, op, mask); - break; - - default: - /* - * Add any permissions that we haven't already - * done. - */ - if (perm || (op == '=' && !equalopdone)) { - if (op == '=') - equalopdone = 1; - ADDCMD(op, who, perm, mask); - perm = 0; - } - if (permXbits) { - ADDCMD('X', who, permXbits, mask); - permXbits = 0; - } - goto apply; - } - } - -apply: if (!*p) - break; - if (*p != ',') - goto getop; - ++p; - } - set->cmd = 0; -#ifdef SETMODE_DEBUG - (void)printf("Before compress_mode()\n"); - dumpmode(saveset); -#endif - compress_mode(saveset); -#ifdef SETMODE_DEBUG - (void)printf("After compress_mode()\n"); - dumpmode(saveset); -#endif - return (saveset); -} - -static BITCMD * -addcmd(set, op, who, oparg, mask) - BITCMD *set; - int oparg, who; - int op; - u_int mask; -{ - - _DIAGASSERT(set != NULL); - - switch (op) { - case '=': - set->cmd = '-'; - set->bits = who ? who : STANDARD_BITS; - set++; - - op = '+'; - /* FALLTHROUGH */ - case '+': - case '-': - case 'X': - set->cmd = op; - set->bits = (who ? who : mask) & oparg; - break; - - case 'u': - case 'g': - case 'o': - set->cmd = op; - if (who) { - set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) | - ((who & S_IRGRP) ? CMD2_GBITS : 0) | - ((who & S_IROTH) ? CMD2_OBITS : 0); - set->bits = (mode_t)~0; - } else { - set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS; - set->bits = mask; - } - - if (oparg == '+') - set->cmd2 |= CMD2_SET; - else if (oparg == '-') - set->cmd2 |= CMD2_CLR; - else if (oparg == '=') - set->cmd2 |= CMD2_SET|CMD2_CLR; - break; - } - return (set + 1); -} - -#ifdef SETMODE_DEBUG -static void -dumpmode(set) - BITCMD *set; -{ - - _DIAGASSERT(set != NULL); - - for (; set->cmd; ++set) - (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n", - set->cmd, set->bits, set->cmd2 ? " cmd2:" : "", - set->cmd2 & CMD2_CLR ? " CLR" : "", - set->cmd2 & CMD2_SET ? " SET" : "", - set->cmd2 & CMD2_UBITS ? " UBITS" : "", - set->cmd2 & CMD2_GBITS ? " GBITS" : "", - set->cmd2 & CMD2_OBITS ? " OBITS" : ""); -} -#endif - -/* - * Given an array of bitcmd structures, compress by compacting consecutive - * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u', - * 'g' and 'o' commands continue to be separate. They could probably be - * compacted, but it's not worth the effort. - */ -static void -compress_mode(set) - BITCMD *set; -{ - BITCMD *nset; - int setbits, clrbits, Xbits, op; - - _DIAGASSERT(set != NULL); - - for (nset = set;;) { - /* Copy over any 'u', 'g' and 'o' commands. */ - while ((op = nset->cmd) != '+' && op != '-' && op != 'X') { - *set++ = *nset++; - if (!op) - return; - } - - for (setbits = clrbits = Xbits = 0;; nset++) { - if ((op = nset->cmd) == '-') { - clrbits |= nset->bits; - setbits &= ~nset->bits; - Xbits &= ~nset->bits; - } else if (op == '+') { - setbits |= nset->bits; - clrbits &= ~nset->bits; - Xbits &= ~nset->bits; - } else if (op == 'X') - Xbits |= nset->bits & ~setbits; - else - break; - } - if (clrbits) { - set->cmd = '-'; - set->cmd2 = 0; - set->bits = clrbits; - set++; - } - if (setbits) { - set->cmd = '+'; - set->cmd2 = 0; - set->bits = setbits; - set++; - } - if (Xbits) { - set->cmd = 'X'; - set->cmd2 = 0; - set->bits = Xbits; - set++; - } - } -} -#ifdef DEBUG -static void shtree (union node *, int, char *, FILE*); -static void shcmd (union node *, FILE *); -static void sharg (union node *, FILE *); -static void indent (int, char *, FILE *); -static void trstring (char *); - - -static void -showtree(n) - union node *n; -{ - trputs("showtree called\n"); - shtree(n, 1, NULL, stdout); -} - - -static void -shtree(n, ind, pfx, fp) - union node *n; - int ind; - char *pfx; - FILE *fp; -{ - struct nodelist *lp; - const char *s; - - if (n == NULL) - return; - - indent(ind, pfx, fp); - switch(n->type) { - case NSEMI: - s = "; "; - goto binop; - case NAND: - s = " && "; - goto binop; - case NOR: - s = " || "; -binop: - shtree(n->nbinary.ch1, ind, NULL, fp); - /* if (ind < 0) */ - fputs(s, fp); - shtree(n->nbinary.ch2, ind, NULL, fp); - break; - case NCMD: - shcmd(n, fp); - if (ind >= 0) - putc('\n', fp); - break; - case NPIPE: - for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { - shcmd(lp->n, fp); - if (lp->next) - fputs(" | ", fp); - } - if (n->npipe.backgnd) - fputs(" &", fp); - if (ind >= 0) - putc('\n', fp); - break; - default: - fprintf(fp, "", n->type); - if (ind >= 0) - putc('\n', fp); - break; - } -} - - - -static void -shcmd(cmd, fp) - union node *cmd; - FILE *fp; -{ - union node *np; - int first; - const char *s; - int dftfd; - - first = 1; - for (np = cmd->ncmd.args ; np ; np = np->narg.next) { - if (! first) - putchar(' '); - sharg(np, fp); - first = 0; - } - for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) { - if (! first) - putchar(' '); - switch (np->nfile.type) { - case NTO: s = ">"; dftfd = 1; break; - case NAPPEND: s = ">>"; dftfd = 1; break; - case NTOFD: s = ">&"; dftfd = 1; break; - case NTOOV: s = ">|"; dftfd = 1; break; - case NFROM: s = "<"; dftfd = 0; break; - case NFROMFD: s = "<&"; dftfd = 0; break; - case NFROMTO: s = "<>"; dftfd = 0; break; - default: s = "*error*"; dftfd = 0; break; - } - if (np->nfile.fd != dftfd) - fprintf(fp, "%d", np->nfile.fd); - fputs(s, fp); - if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { - fprintf(fp, "%d", np->ndup.dupfd); - } else { - sharg(np->nfile.fname, fp); - } - first = 0; - } -} - - - -static void -sharg(arg, fp) - union node *arg; - FILE *fp; - { - char *p; - struct nodelist *bqlist; - int subtype; - - if (arg->type != NARG) { - printf("\n", arg->type); - fflush(stdout); - abort(); - } - bqlist = arg->narg.backquote; - for (p = arg->narg.text ; *p ; p++) { - switch (*p) { - case CTLESC: - putc(*++p, fp); - break; - case CTLVAR: - putc('$', fp); - putc('{', fp); - subtype = *++p; - if (subtype == VSLENGTH) - putc('#', fp); - - while (*p != '=') - putc(*p++, fp); - - if (subtype & VSNUL) - putc(':', fp); - - switch (subtype & VSTYPE) { - case VSNORMAL: - putc('}', fp); - break; - case VSMINUS: - putc('-', fp); - break; - case VSPLUS: - putc('+', fp); - break; - case VSQUESTION: - putc('?', fp); - break; - case VSASSIGN: - putc('=', fp); - break; - case VSTRIMLEFT: - putc('#', fp); - break; - case VSTRIMLEFTMAX: - putc('#', fp); - putc('#', fp); - break; - case VSTRIMRIGHT: - putc('%', fp); - break; - case VSTRIMRIGHTMAX: - putc('%', fp); - putc('%', fp); - break; - case VSLENGTH: - break; - default: - printf("", subtype); - } - break; - case CTLENDVAR: - putc('}', fp); - break; - case CTLBACKQ: - case CTLBACKQ|CTLQUOTE: - putc('$', fp); - putc('(', fp); - shtree(bqlist->n, -1, NULL, fp); - putc(')', fp); - break; - default: - putc(*p, fp); - break; - } - } -} - - -static void -indent(amount, pfx, fp) - int amount; - char *pfx; - FILE *fp; -{ - int i; - - for (i = 0 ; i < amount ; i++) { - if (pfx && i == amount - 1) - fputs(pfx, fp); - putc('\t', fp); - } -} -#endif - - - -/* - * Debugging stuff. - */ - - -#ifdef DEBUG -FILE *tracefile; - -#if DEBUG == 2 -static int debug = 1; -#else -static int debug = 0; -#endif - - -static void -trputc(c) - int c; -{ - if (tracefile == NULL) - return; - putc(c, tracefile); - if (c == '\n') - fflush(tracefile); -} - -static void -trace(const char *fmt, ...) -{ - va_list va; - va_start(va, fmt); - if (tracefile != NULL) { - (void) vfprintf(tracefile, fmt, va); - if (strchr(fmt, '\n')) - (void) fflush(tracefile); - } - va_end(va); -} - - -static void -trputs(s) - const char *s; -{ - if (tracefile == NULL) - return; - fputs(s, tracefile); - if (strchr(s, '\n')) - fflush(tracefile); -} - - -static void -trstring(s) - char *s; -{ - char *p; - char c; - - if (tracefile == NULL) - return; - putc('"', tracefile); - for (p = s ; *p ; p++) { - switch (*p) { - case '\n': c = 'n'; goto backslash; - case '\t': c = 't'; goto backslash; - case '\r': c = 'r'; goto backslash; - case '"': c = '"'; goto backslash; - case '\\': c = '\\'; goto backslash; - case CTLESC: c = 'e'; goto backslash; - case CTLVAR: c = 'v'; goto backslash; - case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; - case CTLBACKQ: c = 'q'; goto backslash; - case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; -backslash: putc('\\', tracefile); - putc(c, tracefile); - break; - default: - if (*p >= ' ' && *p <= '~') - putc(*p, tracefile); - else { - putc('\\', tracefile); - putc(*p >> 6 & 03, tracefile); - putc(*p >> 3 & 07, tracefile); - putc(*p & 07, tracefile); - } - break; - } - } - putc('"', tracefile); -} - - -static void -trargs(ap) - char **ap; -{ - if (tracefile == NULL) - return; - while (*ap) { - trstring(*ap++); - if (*ap) - putc(' ', tracefile); - else - putc('\n', tracefile); - } - fflush(tracefile); -} - - -static void -opentrace() { - char s[100]; -#ifdef O_APPEND - int flags; -#endif - - if (!debug) - return; -#ifdef not_this_way - { - char *p; - if ((p = getenv("HOME")) == NULL) { - if (geteuid() == 0) - p = "/"; - else - p = "/tmp"; - } - strcpy(s, p); - strcat(s, "/trace"); - } -#else - strcpy(s, "./trace"); -#endif /* not_this_way */ - if ((tracefile = fopen(s, "a")) == NULL) { - fprintf(stderr, "Can't open %s\n", s); - return; - } -#ifdef O_APPEND - if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) - fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); -#endif - fputs("\nTracing started.\n", tracefile); - fflush(tracefile); -} -#endif /* DEBUG */ - - -/* - * The trap builtin. - */ - -static int -trapcmd(argc, argv) - int argc; - char **argv; -{ - char *action; - char **ap; - int signo; - - if (argc <= 1) { - for (signo = 0 ; signo < NSIG ; signo++) { - if (trap[signo] != NULL) { - char *p; - const char *sn; - - p = single_quote(trap[signo]); - sn = sys_siglist[signo]; - if(sn==NULL) - sn = u_signal_names(0, &signo, 0); - if(sn==NULL) - sn = "???"; - printf("trap -- %s %s\n", p, sn); - stunalloc(p); - } - } - return 0; - } - ap = argv + 1; - if (argc == 2) - action = NULL; - else - action = *ap++; - while (*ap) { - if ((signo = decode_signal(*ap, 0)) < 0) - error("%s: bad trap", *ap); - INTOFF; - if (action) { - if (action[0] == '-' && action[1] == '\0') - action = NULL; - else - action = savestr(action); - } - if (trap[signo]) - ckfree(trap[signo]); - trap[signo] = action; - if (signo != 0) - setsignal(signo); - INTON; - ap++; - } - return 0; -} - - - - - - -/* - * Set the signal handler for the specified signal. The routine figures - * out what it should be set to. - */ - -static void -setsignal(int signo) -{ - int action; - char *t; - struct sigaction act; - - if ((t = trap[signo]) == NULL) - action = S_DFL; - else if (*t != '\0') - action = S_CATCH; - else - action = S_IGN; - if (rootshell && action == S_DFL) { - switch (signo) { - case SIGINT: - if (iflag || minusc || sflag == 0) - action = S_CATCH; - break; - case SIGQUIT: -#ifdef DEBUG - { - - if (debug) - break; - } -#endif - /* FALLTHROUGH */ - case SIGTERM: - if (iflag) - action = S_IGN; - break; -#ifdef JOBS - case SIGTSTP: - case SIGTTOU: - if (mflag) - action = S_IGN; - break; -#endif - } - } - - t = &sigmode[signo - 1]; - if (*t == 0) { - /* - * current setting unknown - */ - if (sigaction(signo, 0, &act) == -1) { - /* - * Pretend it worked; maybe we should give a warning - * here, but other shells don't. We don't alter - * sigmode, so that we retry every time. - */ - return; - } - if (act.sa_handler == SIG_IGN) { - if (mflag && (signo == SIGTSTP || - signo == SIGTTIN || signo == SIGTTOU)) { - *t = S_IGN; /* don't hard ignore these */ - } else - *t = S_HARD_IGN; - } else { - *t = S_RESET; /* force to be set */ - } - } - if (*t == S_HARD_IGN || *t == action) - return; - switch (action) { - case S_CATCH: - act.sa_handler = onsig; - break; - case S_IGN: - act.sa_handler = SIG_IGN; - break; - default: - act.sa_handler = SIG_DFL; - } - *t = action; - act.sa_flags = 0; - sigemptyset(&act.sa_mask); - sigaction(signo, &act, 0); -} - -/* - * Ignore a signal. - */ - -static void -ignoresig(signo) - int signo; -{ - if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { - signal(signo, SIG_IGN); - } - sigmode[signo - 1] = S_HARD_IGN; -} - - -/* - * Signal handler. - */ - -static void -onsig(int signo) -{ - if (signo == SIGINT && trap[SIGINT] == NULL) { - onint(); - return; - } - gotsig[signo - 1] = 1; - pendingsigs++; -} - - -/* - * Called to execute a trap. Perhaps we should avoid entering new trap - * handlers while we are executing a trap handler. - */ - -static void -dotrap(void) -{ - int i; - int savestatus; - - for (;;) { - for (i = 1 ; ; i++) { - if (gotsig[i - 1]) - break; - if (i >= NSIG - 1) - goto done; - } - gotsig[i - 1] = 0; - savestatus=exitstatus; - evalstring(trap[i], 0); - exitstatus=savestatus; - } -done: - pendingsigs = 0; -} - -/* - * Called to exit the shell. - */ - -static void -exitshell(int status) -{ - struct jmploc loc1, loc2; - char *p; - - TRACE(("exitshell(%d) pid=%d\n", status, getpid())); - if (setjmp(loc1.loc)) { - goto l1; - } - if (setjmp(loc2.loc)) { - goto l2; - } - handler = &loc1; - if ((p = trap[0]) != NULL && *p != '\0') { - trap[0] = NULL; - evalstring(p, 0); - } -l1: handler = &loc2; /* probably unnecessary */ - flushall(); -#ifdef JOBS - setjobctl(0); -#endif -l2: _exit(status); - /* NOTREACHED */ -} - -static int decode_signal(const char *string, int minsig) -{ - int signo; - const char *name = u_signal_names(string, &signo, minsig); - - return name ? signo : -1; -} - -static struct var **hashvar (const char *); -static void showvars (const char *, int, int); -static struct var **findvar (struct var **, const char *); - -/* - * Initialize the varable symbol tables and import the environment - */ - -/* - * This routine initializes the builtin variables. It is called when the - * shell is initialized and again when a shell procedure is spawned. - */ - -static void -initvar() { - const struct varinit *ip; - struct var *vp; - struct var **vpp; - - for (ip = varinit ; (vp = ip->var) != NULL ; ip++) { - if ((vp->flags & VEXPORT) == 0) { - vpp = hashvar(ip->text); - vp->next = *vpp; - *vpp = vp; - vp->text = strdup(ip->text); - vp->flags = ip->flags; - vp->func = ip->func; - } - } - /* - * PS1 depends on uid - */ - if ((vps1.flags & VEXPORT) == 0) { - vpp = hashvar("PS1="); - vps1.next = *vpp; - *vpp = &vps1; - vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# "); - vps1.flags = VSTRFIXED|VTEXTFIXED; - } -} - -/* - * Set the value of a variable. The flags argument is ored with the - * flags of the variable. If val is NULL, the variable is unset. - */ - -static void -setvar(name, val, flags) - const char *name, *val; - int flags; -{ - const char *p; - int len; - int namelen; - char *nameeq; - int isbad; - int vallen = 0; - - isbad = 0; - p = name; - if (! is_name(*p)) - isbad = 1; - p++; - for (;;) { - if (! is_in_name(*p)) { - if (*p == '\0' || *p == '=') - break; - isbad = 1; - } - p++; - } - namelen = p - name; - if (isbad) - error("%.*s: bad variable name", namelen, name); - len = namelen + 2; /* 2 is space for '=' and '\0' */ - if (val == NULL) { - flags |= VUNSET; - } else { - len += vallen = strlen(val); - } - INTOFF; - nameeq = ckmalloc(len); - memcpy(nameeq, name, namelen); - nameeq[namelen] = '='; - if (val) { - memcpy(nameeq + namelen + 1, val, vallen + 1); - } else { - nameeq[namelen + 1] = '\0'; - } - setvareq(nameeq, flags); - INTON; -} - - - -/* - * Same as setvar except that the variable and value are passed in - * the first argument as name=value. Since the first argument will - * be actually stored in the table, it should not be a string that - * will go away. - */ - -static void -setvareq(s, flags) - char *s; - int flags; -{ - struct var *vp, **vpp; - - vpp = hashvar(s); - flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1)); - if ((vp = *findvar(vpp, s))) { - if (vp->flags & VREADONLY) { - size_t len = strchr(s, '=') - s; - error("%.*s: is read only", len, s); - } - INTOFF; - - if (vp->func && (flags & VNOFUNC) == 0) - (*vp->func)(strchr(s, '=') + 1); - - if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) - ckfree(vp->text); - - vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET); - vp->flags |= flags; - vp->text = s; - - /* - * We could roll this to a function, to handle it as - * a regular variable function callback, but why bother? - */ - if (iflag && (vp == &vmpath || (vp == &vmail && !mpathset()))) - chkmail(1); - INTON; - return; - } - /* not found */ - vp = ckmalloc(sizeof (*vp)); - vp->flags = flags; - vp->text = s; - vp->next = *vpp; - vp->func = NULL; - *vpp = vp; -} - - - -/* - * Process a linked list of variable assignments. - */ - -static void -listsetvar(mylist) - struct strlist *mylist; - { - struct strlist *lp; - - INTOFF; - for (lp = mylist ; lp ; lp = lp->next) { - setvareq(savestr(lp->text), 0); - } - INTON; -} - - - -/* - * Find the value of a variable. Returns NULL if not set. - */ - -static const char * -lookupvar(name) - const char *name; - { - struct var *v; - - if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) { - return strchr(v->text, '=') + 1; - } - return NULL; -} - - - -/* - * Search the environment of a builtin command. - */ - -static const char * -bltinlookup(const char *name) -{ - const struct strlist *sp; - - for (sp = cmdenviron ; sp ; sp = sp->next) { - if (varequal(sp->text, name)) - return strchr(sp->text, '=') + 1; - } - return lookupvar(name); -} - - - -/* - * Generate a list of exported variables. This routine is used to construct - * the third argument to execve when executing a program. - */ - -static char ** -environment() { - int nenv; - struct var **vpp; - struct var *vp; - char **env; - char **ep; - - nenv = 0; - for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { - for (vp = *vpp ; vp ; vp = vp->next) - if (vp->flags & VEXPORT) - nenv++; - } - ep = env = stalloc((nenv + 1) * sizeof *env); - for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { - for (vp = *vpp ; vp ; vp = vp->next) - if (vp->flags & VEXPORT) - *ep++ = vp->text; - } - *ep = NULL; - return env; -} - - -/* - * Called when a shell procedure is invoked to clear out nonexported - * variables. It is also necessary to reallocate variables of with - * VSTACK set since these are currently allocated on the stack. - */ - -static void -shprocvar(void) { - struct var **vpp; - struct var *vp, **prev; - - for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { - for (prev = vpp ; (vp = *prev) != NULL ; ) { - if ((vp->flags & VEXPORT) == 0) { - *prev = vp->next; - if ((vp->flags & VTEXTFIXED) == 0) - ckfree(vp->text); - if ((vp->flags & VSTRFIXED) == 0) - ckfree(vp); - } else { - if (vp->flags & VSTACK) { - vp->text = savestr(vp->text); - vp->flags &=~ VSTACK; - } - prev = &vp->next; - } - } - } - initvar(); -} - - - -/* - * Command to list all variables which are set. Currently this command - * is invoked from the set command when the set command is called without - * any variables. - */ - -static int -showvarscmd(argc, argv) - int argc; - char **argv; -{ - showvars(nullstr, VUNSET, VUNSET); - return 0; -} - - - -/* - * The export and readonly commands. - */ - -static int -exportcmd(argc, argv) - int argc; - char **argv; -{ - struct var *vp; - char *name; - const char *p; - int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; - int pflag; - - listsetvar(cmdenviron); - pflag = (nextopt("p") == 'p'); - if (argc > 1 && !pflag) { - while ((name = *argptr++) != NULL) { - if ((p = strchr(name, '=')) != NULL) { - p++; - } else { - if ((vp = *findvar(hashvar(name), name))) { - vp->flags |= flag; - goto found; - } - } - setvar(name, p, flag); -found:; - } - } else { - showvars(argv[0], flag, 0); - } - return 0; -} - - -/* - * The "local" command. - */ - -/* funcnest nonzero if we are currently evaluating a function */ - -static int -localcmd(argc, argv) - int argc; - char **argv; -{ - char *name; - - if (! funcnest) - error("Not in a function"); - while ((name = *argptr++) != NULL) { - mklocal(name); - } - return 0; -} - - -/* - * Make a variable a local variable. When a variable is made local, it's - * value and flags are saved in a localvar structure. The saved values - * will be restored when the shell function returns. We handle the name - * "-" as a special case. - */ - -static void -mklocal(name) - char *name; - { - struct localvar *lvp; - struct var **vpp; - struct var *vp; - - INTOFF; - lvp = ckmalloc(sizeof (struct localvar)); - if (name[0] == '-' && name[1] == '\0') { - char *p; - p = ckmalloc(sizeof optet_vals); - lvp->text = memcpy(p, optet_vals, sizeof optet_vals); - vp = NULL; - } else { - vpp = hashvar(name); - vp = *findvar(vpp, name); - if (vp == NULL) { - if (strchr(name, '=')) - setvareq(savestr(name), VSTRFIXED); - else - setvar(name, NULL, VSTRFIXED); - vp = *vpp; /* the new variable */ - lvp->text = NULL; - lvp->flags = VUNSET; - } else { - lvp->text = vp->text; - lvp->flags = vp->flags; - vp->flags |= VSTRFIXED|VTEXTFIXED; - if (strchr(name, '=')) - setvareq(savestr(name), 0); - } - } - lvp->vp = vp; - lvp->next = localvars; - localvars = lvp; - INTON; -} - - -/* - * Called after a function returns. - */ - -static void -poplocalvars() { - struct localvar *lvp; - struct var *vp; - - while ((lvp = localvars) != NULL) { - localvars = lvp->next; - vp = lvp->vp; - if (vp == NULL) { /* $- saved */ - memcpy(optet_vals, lvp->text, sizeof optet_vals); - ckfree(lvp->text); - } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { - (void)unsetvar(vp->text); - } else { - if ((vp->flags & VTEXTFIXED) == 0) - ckfree(vp->text); - vp->flags = lvp->flags; - vp->text = lvp->text; - } - ckfree(lvp); - } -} - - -static int -setvarcmd(argc, argv) - int argc; - char **argv; -{ - if (argc <= 2) - return unsetcmd(argc, argv); - else if (argc == 3) - setvar(argv[1], argv[2], 0); - else - error("List assignment not implemented"); - return 0; -} - - -/* - * The unset builtin command. We unset the function before we unset the - * variable to allow a function to be unset when there is a readonly variable - * with the same name. - */ - -static int -unsetcmd(argc, argv) - int argc; - char **argv; -{ - char **ap; - int i; - int flg_func = 0; - int flg_var = 0; - int ret = 0; - - while ((i = nextopt("vf")) != '\0') { - if (i == 'f') - flg_func = 1; - else - flg_var = 1; - } - if (flg_func == 0 && flg_var == 0) - flg_var = 1; - - for (ap = argptr; *ap ; ap++) { - if (flg_func) - unsetfunc(*ap); - if (flg_var) - ret |= unsetvar(*ap); - } - return ret; -} - - -/* - * Unset the specified variable. - */ - -static int -unsetvar(const char *s) -{ - struct var **vpp; - struct var *vp; - - vpp = findvar(hashvar(s), s); - vp = *vpp; - if (vp) { - if (vp->flags & VREADONLY) - return (1); - INTOFF; - if (*(strchr(vp->text, '=') + 1) != '\0') - setvar(s, nullstr, 0); - vp->flags &= ~VEXPORT; - vp->flags |= VUNSET; - if ((vp->flags & VSTRFIXED) == 0) { - if ((vp->flags & VTEXTFIXED) == 0) - ckfree(vp->text); - *vpp = vp->next; - ckfree(vp); - } - INTON; - return (0); - } - - return (0); -} - - - -/* - * Find the appropriate entry in the hash table from the name. - */ - -static struct var ** -hashvar(const char *p) -{ - unsigned int hashval; - - hashval = ((unsigned char) *p) << 4; - while (*p && *p != '=') - hashval += (unsigned char) *p++; - return &vartab[hashval % VTABSIZE]; -} - - - -/* - * Returns true if the two strings specify the same varable. The first - * variable name is terminated by '='; the second may be terminated by - * either '=' or '\0'. - */ - -static int -varequal(const char *p, const char *q) -{ - while (*p == *q++) { - if (*p++ == '=') - return 1; - } - if (*p == '=' && *(q - 1) == '\0') - return 1; - return 0; -} - -static void -showvars(const char *myprefix, int mask, int xor) -{ - struct var **vpp; - struct var *vp; - const char *sep = myprefix == nullstr ? myprefix : spcstr; - - for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { - for (vp = *vpp ; vp ; vp = vp->next) { - if ((vp->flags & mask) ^ xor) { - char *p; - int len; - - p = strchr(vp->text, '=') + 1; - len = p - vp->text; - p = single_quote(p); - - printf("%s%s%.*s%s\n", myprefix, sep, len, - vp->text, p); - stunalloc(p); - } - } - } -} - -static struct var ** -findvar(struct var **vpp, const char *name) -{ - for (; *vpp; vpp = &(*vpp)->next) { - if (varequal((*vpp)->text, name)) { - break; - } - } - return vpp; -} - -/* - * Copyright (c) 1999 Herbert Xu - * This file contains code for the times builtin. - * $Id: ash.c,v 1.17.2.3 2001/09/06 17:59:36 andersen Exp $ - */ -static int timescmd (int argc, char **argv) -{ - struct tms buf; - long int clk_tck = sysconf(_SC_CLK_TCK); - - times(&buf); - printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", - (int) (buf.tms_utime / clk_tck / 60), - ((double) buf.tms_utime) / clk_tck, - (int) (buf.tms_stime / clk_tck / 60), - ((double) buf.tms_stime) / clk_tck, - (int) (buf.tms_cutime / clk_tck / 60), - ((double) buf.tms_cutime) / clk_tck, - (int) (buf.tms_cstime / clk_tck / 60), - ((double) buf.tms_cstime) / clk_tck); - return 0; -} - -#ifdef ASH_MATH_SUPPORT -/* The let builtin. */ -int letcmd(int argc, char **argv) -{ - int errcode; - long result=0; - if (argc == 2) { - char *tmp, *expression, p[13]; - expression = strchr(argv[1], '='); - if (!expression) { - /* Cannot use 'error()' here, or the return code - * will be incorrect */ - out2fmt("sh: let: syntax error: \"%s\"\n", argv[1]); - return 0; - } - *expression = '\0'; - tmp = ++expression; - result = arith(tmp, &errcode); - if (errcode < 0) { - /* Cannot use 'error()' here, or the return code - * will be incorrect */ - out2fmt("sh: let: "); - if(errcode == -2) - out2fmt("divide by zero"); - else - out2fmt("syntax error: \"%s=%s\"\n", argv[1], expression); - return 0; - } - snprintf(p, 12, "%ld", result); - setvar(argv[1], savestr(p), 0); - } else if (argc >= 3) - synerror("invalid operand"); - return !result; -} -#endif - - - -/*- - * Copyright (c) 1989, 1991, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Kenneth Almquist. - * - * 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. - */ diff --git a/busybox/shell/cmdedit.c b/busybox/shell/cmdedit.c deleted file mode 100644 index 16ec2f823..000000000 --- a/busybox/shell/cmdedit.c +++ /dev/null @@ -1,1521 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Termios command line History and Editting. - * - * Copyright (c) 1986-2001 may safely be consumed by a BSD or GPL license. - * Written by: Vladimir Oleynik - * - * Used ideas: - * Adam Rogoyski - * Dave Cinege - * Jakub Jelinek (c) 1995 - * Erik Andersen (Majorly adjusted for busybox) - * - * This code is 'as is' with no warranty. - * - * - */ - -/* - Usage and Known bugs: - Terminal key codes are not extensive, and more will probably - need to be added. This version was created on Debian GNU/Linux 2.x. - Delete, Backspace, Home, End, and the arrow keys were tested - to work in an Xterm and console. Ctrl-A also works as Home. - Ctrl-E also works as End. - - Small bugs (simple effect): - - not true viewing if terminal size (x*y symbols) less - size (prompt + editor`s line + 2 symbols) - - not true viewing if length prompt less terminal width - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "busybox.h" - -#ifdef BB_LOCALE_SUPPORT -#define Isprint(c) isprint((c)) -#else -#define Isprint(c) ( (c) >= ' ' && (c) != ((unsigned char)'\233') ) -#endif - -#ifndef TEST - -#define D(x) - -#else - -#define BB_FEATURE_COMMAND_EDITING -#define BB_FEATURE_COMMAND_TAB_COMPLETION -#define BB_FEATURE_COMMAND_USERNAME_COMPLETION -#define BB_FEATURE_NONPRINTABLE_INVERSE_PUT -#define BB_FEATURE_CLEAN_UP - -#define D(x) x - -#endif /* TEST */ - -#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION -#include -#include -#endif - -#ifdef BB_FEATURE_COMMAND_EDITING - -#ifndef BB_FEATURE_COMMAND_TAB_COMPLETION -#undef BB_FEATURE_COMMAND_USERNAME_COMPLETION -#endif - -#if defined(BB_FEATURE_COMMAND_USERNAME_COMPLETION) || defined(BB_FEATURE_SH_FANCY_PROMPT) -#define BB_FEATURE_GETUSERNAME_AND_HOMEDIR -#endif - -#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR -# ifndef TEST -# include "pwd_grp/pwd.h" -# else -# include -# endif /* TEST */ -#endif /* advanced FEATURES */ - - - -struct history { - char *s; - struct history *p; - struct history *n; -}; - -/* Maximum length of the linked list for the command line history */ -static const int MAX_HISTORY = 15; - -/* First element in command line list */ -static struct history *his_front = NULL; - -/* Last element in command line list */ -static struct history *his_end = NULL; - - -#include -#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp) -#define getTermSettings(fd,argp) tcgetattr(fd, argp); - -/* Current termio and the previous termio before starting sh */ -static struct termios initial_settings, new_settings; - - -static -volatile int cmdedit_termw = 80; /* actual terminal width */ -static int history_counter = 0; /* Number of commands in history list */ -static -volatile int handlers_sets = 0; /* Set next bites: */ - -enum { - SET_ATEXIT = 1, /* when atexit() has been called - and get euid,uid,gid to fast compare */ - SET_WCHG_HANDLERS = 2, /* winchg signal handler */ - SET_RESET_TERM = 4, /* if the terminal needs to be reset upon exit */ -}; - - -static int cmdedit_x; /* real x terminal position */ -static int cmdedit_y; /* pseudoreal y terminal position */ -static int cmdedit_prmt_len; /* lenght prompt without colores string */ - -static int cursor; /* required global for signal handler */ -static int len; /* --- "" - - "" - -"- --""-- --""--- */ -static char *command_ps; /* --- "" - - "" - -"- --""-- --""--- */ -static -#ifndef BB_FEATURE_SH_FANCY_PROMPT - const -#endif -char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */ - -#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR -static char *user_buf = ""; -static char *home_pwd_buf = ""; -static int my_euid; -#endif - -#ifdef BB_FEATURE_SH_FANCY_PROMPT -static char *hostname_buf = ""; -static int num_ok_lines = 1; -#endif - - -#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION - -#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR -static int my_euid; -#endif - -static int my_uid; -static int my_gid; - -#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ - -/* It seems that libc5 doesn't know what a sighandler_t is... */ -#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1) -typedef void (*sighandler_t) (int); -#endif - -static void cmdedit_setwidth(int w, int redraw_flg); - -static void win_changed(int nsig) -{ - struct winsize win = { 0, 0, 0, 0 }; - static sighandler_t previous_SIGWINCH_handler; /* for reset */ - - /* emulate || signal call */ - if (nsig == -SIGWINCH || nsig == SIGWINCH) { - ioctl(0, TIOCGWINSZ, &win); - if (win.ws_col > 0) { - cmdedit_setwidth(win.ws_col, nsig == SIGWINCH); - } - } - /* Unix not all standart in recall signal */ - - if (nsig == -SIGWINCH) /* save previous handler */ - previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); - else if (nsig == SIGWINCH) /* signaled called handler */ - signal(SIGWINCH, win_changed); /* set for next call */ - else /* nsig == 0 */ - /* set previous handler */ - signal(SIGWINCH, previous_SIGWINCH_handler); /* reset */ -} - -static void cmdedit_reset_term(void) -{ - if ((handlers_sets & SET_RESET_TERM) != 0) { -/* sparc and other have broken termios support: use old termio handling. */ - setTermSettings(fileno(stdin), (void *) &initial_settings); - handlers_sets &= ~SET_RESET_TERM; - } - if ((handlers_sets & SET_WCHG_HANDLERS) != 0) { - /* reset SIGWINCH handler to previous (default) */ - win_changed(0); - handlers_sets &= ~SET_WCHG_HANDLERS; - } - fflush(stdout); -#ifdef BB_FEATURE_CLEAN_UP - if (his_front) { - struct history *n; - - while (his_front != his_end) { - n = his_front->n; - free(his_front->s); - free(his_front); - his_front = n; - } - } -#endif -} - - -/* special for recount position for scroll and remove terminal margin effect */ -static void cmdedit_set_out_char(int next_char) -{ - - int c = (int)((unsigned char) command_ps[cursor]); - - if (c == 0) - c = ' '; /* destroy end char? */ -#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT - if (!Isprint(c)) { /* Inverse put non-printable characters */ - if (c >= 128) - c -= 128; - if (c < ' ') - c += '@'; - if (c == 127) - c = '?'; - printf("\033[7m%c\033[0m", c); - } else -#endif - putchar(c); - if (++cmdedit_x >= cmdedit_termw) { - /* terminal is scrolled down */ - cmdedit_y++; - cmdedit_x = 0; - - if (!next_char) - next_char = ' '; - /* destroy "(auto)margin" */ - putchar(next_char); - putchar('\b'); - } - cursor++; -} - -/* Move to end line. Bonus: rewrite line from cursor */ -static void input_end(void) -{ - while (cursor < len) - cmdedit_set_out_char(0); -} - -/* Go to the next line */ -static void goto_new_line(void) -{ - input_end(); - if (cmdedit_x) - putchar('\n'); -} - - -static inline void out1str(const char *s) -{ - fputs(s, stdout); -} -static inline void beep(void) -{ - putchar('\007'); -} - -/* Move back one charactor */ -/* special for slow terminal */ -static void input_backward(int num) -{ - if (num > cursor) - num = cursor; - cursor -= num; /* new cursor (in command, not terminal) */ - - if (cmdedit_x >= num) { /* no to up line */ - cmdedit_x -= num; - if (num < 4) - while (num-- > 0) - putchar('\b'); - - else - printf("\033[%dD", num); - } else { - int count_y; - - if (cmdedit_x) { - putchar('\r'); /* back to first terminal pos. */ - num -= cmdedit_x; /* set previous backward */ - } - count_y = 1 + num / cmdedit_termw; - printf("\033[%dA", count_y); - cmdedit_y -= count_y; - /* require forward after uping */ - cmdedit_x = cmdedit_termw * count_y - num; - printf("\033[%dC", cmdedit_x); /* set term cursor */ - } -} - -static void put_prompt(void) -{ - out1str(cmdedit_prompt); - cmdedit_x = cmdedit_prmt_len; /* count real x terminal position */ - cursor = 0; - cmdedit_y = 0; /* new quasireal y */ -} - -#ifndef BB_FEATURE_SH_FANCY_PROMPT -static void parse_prompt(const char *prmt_ptr) -{ - cmdedit_prompt = prmt_ptr; - cmdedit_prmt_len = strlen(prmt_ptr); - put_prompt(); -} -#else -static void parse_prompt(const char *prmt_ptr) -{ - int prmt_len = 0; - int sub_len = 0; - char flg_not_length = '['; - char *prmt_mem_ptr = xcalloc(1, 1); - char *pwd_buf = xgetcwd(0); - char buf2[PATH_MAX + 1]; - char buf[2]; - char c; - char *pbuf; - - if (!pwd_buf) { - pwd_buf=(char *)unknown; - } - - while (*prmt_ptr) { - pbuf = buf; - pbuf[1] = 0; - c = *prmt_ptr++; - if (c == '\\') { - const char *cp = prmt_ptr; - int l; - - c = process_escape_sequence(&prmt_ptr); - if(prmt_ptr==cp) { - if (*cp == 0) - break; - c = *prmt_ptr++; - switch (c) { -#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR - case 'u': - pbuf = user_buf; - break; -#endif - case 'h': - pbuf = hostname_buf; - if (*pbuf == 0) { - pbuf = xcalloc(256, 1); - if (gethostname(pbuf, 255) < 0) { - strcpy(pbuf, "?"); - } else { - char *s = strchr(pbuf, '.'); - - if (s) - *s = 0; - } - hostname_buf = pbuf; - } - break; - case '$': - c = my_euid == 0 ? '#' : '$'; - break; -#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR - case 'w': - pbuf = pwd_buf; - l = strlen(home_pwd_buf); - if (home_pwd_buf[0] != 0 && - strncmp(home_pwd_buf, pbuf, l) == 0 && - (pbuf[l]=='/' || pbuf[l]=='\0') && - strlen(pwd_buf+l) UCHAR_MAX || (pbuf - buf2) < l) { - l--; - break; - } - prmt_ptr++; - } - buf2[l] = 0; - c = (char)strtol(buf2, 0, 16); - if(c==0) - c = '?'; - pbuf = buf; - break; - case '[': case ']': - if (c == flg_not_length) { - flg_not_length = flg_not_length == '[' ? ']' : '['; - continue; - } - break; - } - } - } - if(pbuf == buf) - *pbuf = c; - prmt_len += strlen(pbuf); - prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf); - if (flg_not_length == ']') - sub_len++; - } - if(pwd_buf!=(char *)unknown) - free(pwd_buf); - cmdedit_prompt = prmt_mem_ptr; - cmdedit_prmt_len = prmt_len - sub_len; - put_prompt(); -} -#endif - - -/* draw promt, editor line, and clear tail */ -static void redraw(int y, int back_cursor) -{ - if (y > 0) /* up to start y */ - printf("\033[%dA", y); - putchar('\r'); - put_prompt(); - input_end(); /* rewrite */ - printf("\033[J"); /* destroy tail after cursor */ - input_backward(back_cursor); -} - -/* Delete the char in front of the cursor */ -static void input_delete(void) -{ - int j = cursor; - - if (j == len) - return; - - strcpy(command_ps + j, command_ps + j + 1); - len--; - input_end(); /* rewtite new line */ - cmdedit_set_out_char(0); /* destroy end char */ - input_backward(cursor - j); /* back to old pos cursor */ -} - -/* Delete the char in back of the cursor */ -static void input_backspace(void) -{ - if (cursor > 0) { - input_backward(1); - input_delete(); - } -} - - -/* Move forward one charactor */ -static void input_forward(void) -{ - if (cursor < len) - cmdedit_set_out_char(command_ps[cursor + 1]); -} - - -static void cmdedit_setwidth(int w, int redraw_flg) -{ - cmdedit_termw = cmdedit_prmt_len + 2; - if (w <= cmdedit_termw) { - cmdedit_termw = cmdedit_termw % w; - } - if (w > cmdedit_termw) { - cmdedit_termw = w; - - if (redraw_flg) { - /* new y for current cursor */ - int new_y = (cursor + cmdedit_prmt_len) / w; - - /* redraw */ - redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor); - fflush(stdout); - } - } -} - -static void cmdedit_init(void) -{ - cmdedit_prmt_len = 0; - if ((handlers_sets & SET_WCHG_HANDLERS) == 0) { - /* emulate usage handler to set handler and call yours work */ - win_changed(-SIGWINCH); - handlers_sets |= SET_WCHG_HANDLERS; - } - - if ((handlers_sets & SET_ATEXIT) == 0) { -#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR - struct passwd *entry; - - my_euid = geteuid(); - entry = getpwuid(my_euid); - if (entry) { - user_buf = xstrdup(entry->pw_name); - home_pwd_buf = xstrdup(entry->pw_dir); - } -#endif - -#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION - -#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR - my_euid = geteuid(); -#endif - my_uid = getuid(); - my_gid = getgid(); -#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ - handlers_sets |= SET_ATEXIT; - atexit(cmdedit_reset_term); /* be sure to do this only once */ - } -} - -#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION - -static int is_execute(const struct stat *st) -{ - if ((!my_euid && (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) || - (my_uid == st->st_uid && (st->st_mode & S_IXUSR)) || - (my_gid == st->st_gid && (st->st_mode & S_IXGRP)) || - (st->st_mode & S_IXOTH)) return TRUE; - return FALSE; -} - -#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION - -static char **username_tab_completion(char *ud, int *num_matches) -{ - struct passwd *entry; - int userlen; - char *temp; - - - ud++; /* ~user/... to user/... */ - userlen = strlen(ud); - - if (num_matches == 0) { /* "~/..." or "~user/..." */ - char *sav_ud = ud - 1; - char *home = 0; - - if (*ud == '/') { /* "~/..." */ - home = home_pwd_buf; - } else { - /* "~user/..." */ - temp = strchr(ud, '/'); - *temp = 0; /* ~user\0 */ - entry = getpwnam(ud); - *temp = '/'; /* restore ~user/... */ - ud = temp; - if (entry) - home = entry->pw_dir; - } - if (home) { - if ((userlen + strlen(home) + 1) < BUFSIZ) { - char temp2[BUFSIZ]; /* argument size */ - - /* /home/user/... */ - sprintf(temp2, "%s%s", home, ud); - strcpy(sav_ud, temp2); - } - } - return 0; /* void, result save to argument :-) */ - } else { - /* "~[^/]*" */ - char **matches = (char **) NULL; - int nm = 0; - - setpwent(); - - while ((entry = getpwent()) != NULL) { - /* Null usernames should result in all users as possible completions. */ - if ( /*!userlen || */ !strncmp(ud, entry->pw_name, userlen)) { - - temp = xmalloc(3 + strlen(entry->pw_name)); - sprintf(temp, "~%s/", entry->pw_name); - matches = xrealloc(matches, (nm + 1) * sizeof(char *)); - - matches[nm++] = temp; - } - } - - endpwent(); - (*num_matches) = nm; - return (matches); - } -} -#endif /* BB_FEATURE_COMMAND_USERNAME_COMPLETION */ - -enum { - FIND_EXE_ONLY = 0, - FIND_DIR_ONLY = 1, - FIND_FILE_ONLY = 2, -}; - -static int path_parse(char ***p, int flags) -{ - int npth; - char *tmp; - char *pth; - - /* if not setenv PATH variable, to search cur dir "." */ - if (flags != FIND_EXE_ONLY || (pth = getenv("PATH")) == 0 || - /* PATH= or PATH=: */ - *pth == 0 || (*pth == ':' && *(pth + 1) == 0)) { - return 1; - } - - tmp = pth; - npth = 0; - - for (;;) { - npth++; /* count words is + 1 count ':' */ - tmp = strchr(tmp, ':'); - if (tmp) { - if (*++tmp == 0) - break; /* : */ - } else - break; - } - - *p = xmalloc(npth * sizeof(char *)); - - tmp = pth; - (*p)[0] = xstrdup(tmp); - npth = 1; /* count words is + 1 count ':' */ - - for (;;) { - tmp = strchr(tmp, ':'); - if (tmp) { - (*p)[0][(tmp - pth)] = 0; /* ':' -> '\0' */ - if (*++tmp == 0) - break; /* : */ - } else - break; - (*p)[npth++] = &(*p)[0][(tmp - pth)]; /* p[next]=p[0][&'\0'+1] */ - } - - return npth; -} - -static char *add_quote_for_spec_chars(char *found) -{ - int l = 0; - char *s = xmalloc((strlen(found) + 1) * 2); - - while (*found) { - if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found)) - s[l++] = '\\'; - s[l++] = *found++; - } - s[l] = 0; - return s; -} - -static char **exe_n_cwd_tab_completion(char *command, int *num_matches, - int type) -{ - - char **matches = 0; - DIR *dir; - struct dirent *next; - char dirbuf[BUFSIZ]; - int nm = *num_matches; - struct stat st; - char *path1[1]; - char **paths = path1; - int npaths; - int i; - char *found; - char *pfind = strrchr(command, '/'); - - path1[0] = "."; - - if (pfind == NULL) { - /* no dir, if flags==EXE_ONLY - get paths, else "." */ - npaths = path_parse(&paths, type); - pfind = command; - } else { - /* with dir */ - /* save for change */ - strcpy(dirbuf, command); - /* set dir only */ - dirbuf[(pfind - command) + 1] = 0; -#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION - if (dirbuf[0] == '~') /* ~/... or ~user/... */ - username_tab_completion(dirbuf, 0); -#endif - /* "strip" dirname in command */ - pfind++; - - paths[0] = dirbuf; - npaths = 1; /* only 1 dir */ - } - - for (i = 0; i < npaths; i++) { - - dir = opendir(paths[i]); - if (!dir) /* Don't print an error */ - continue; - - while ((next = readdir(dir)) != NULL) { - char *str_found = next->d_name; - - /* matched ? */ - if (strncmp(str_found, pfind, strlen(pfind))) - continue; - /* not see .name without .match */ - if (*str_found == '.' && *pfind == 0) { - if (*paths[i] == '/' && paths[i][1] == 0 - && str_found[1] == 0) str_found = ""; /* only "/" */ - else - continue; - } - found = concat_path_file(paths[i], str_found); - /* hmm, remover in progress? */ - if (stat(found, &st) < 0) - goto cont; - /* find with dirs ? */ - if (paths[i] != dirbuf) - strcpy(found, next->d_name); /* only name */ - if (S_ISDIR(st.st_mode)) { - /* name is directory */ - str_found = found; - found = concat_path_file(found, ""); - free(str_found); - str_found = add_quote_for_spec_chars(found); - } else { - /* not put found file if search only dirs for cd */ - if (type == FIND_DIR_ONLY) - goto cont; - str_found = add_quote_for_spec_chars(found); - if (type == FIND_FILE_ONLY || - (type == FIND_EXE_ONLY && is_execute(&st) == TRUE)) - strcat(str_found, " "); - } - /* Add it to the list */ - matches = xrealloc(matches, (nm + 1) * sizeof(char *)); - - matches[nm++] = str_found; -cont: - free(found); - } - closedir(dir); - } - if (paths != path1) { - free(paths[0]); /* allocated memory only in first member */ - free(paths); - } - *num_matches = nm; - return (matches); -} - -static int match_compare(const void *a, const void *b) -{ - return strcmp(*(char **) a, *(char **) b); -} - - - -#define QUOT (UCHAR_MAX+1) - -#define collapse_pos(is, in) { \ - memcpy(int_buf+is, int_buf+in, (BUFSIZ+1-is-in)*sizeof(int)); \ - memcpy(pos_buf+is, pos_buf+in, (BUFSIZ+1-is-in)*sizeof(int)); } - -static int find_match(char *matchBuf, int *len_with_quotes) -{ - int i, j; - int command_mode; - int c, c2; - int int_buf[BUFSIZ + 1]; - int pos_buf[BUFSIZ + 1]; - - /* set to integer dimension characters and own positions */ - for (i = 0;; i++) { - int_buf[i] = (int) ((unsigned char) matchBuf[i]); - if (int_buf[i] == 0) { - pos_buf[i] = -1; /* indicator end line */ - break; - } else - pos_buf[i] = i; - } - - /* mask \+symbol and convert '\t' to ' ' */ - for (i = j = 0; matchBuf[i]; i++, j++) - if (matchBuf[i] == '\\') { - collapse_pos(j, j + 1); - int_buf[j] |= QUOT; - i++; -#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT - if (matchBuf[i] == '\t') /* algorithm equivalent */ - int_buf[j] = ' ' | QUOT; -#endif - } -#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT - else if (matchBuf[i] == '\t') - int_buf[j] = ' '; -#endif - - /* mask "symbols" or 'symbols' */ - c2 = 0; - for (i = 0; int_buf[i]; i++) { - c = int_buf[i]; - if (c == '\'' || c == '"') { - if (c2 == 0) - c2 = c; - else { - if (c == c2) - c2 = 0; - else - int_buf[i] |= QUOT; - } - } else if (c2 != 0 && c != '$') - int_buf[i] |= QUOT; - } - - /* skip commands with arguments if line have commands delimiters */ - /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */ - for (i = 0; int_buf[i]; i++) { - c = int_buf[i]; - c2 = int_buf[i + 1]; - j = i ? int_buf[i - 1] : -1; - command_mode = 0; - if (c == ';' || c == '&' || c == '|') { - command_mode = 1 + (c == c2); - if (c == '&') { - if (j == '>' || j == '<') - command_mode = 0; - } else if (c == '|' && j == '>') - command_mode = 0; - } - if (command_mode) { - collapse_pos(0, i + command_mode); - i = -1; /* hack incremet */ - } - } - /* collapse `command...` */ - for (i = 0; int_buf[i]; i++) - if (int_buf[i] == '`') { - for (j = i + 1; int_buf[j]; j++) - if (int_buf[j] == '`') { - collapse_pos(i, j + 1); - j = 0; - break; - } - if (j) { - /* not found close ` - command mode, collapse all previous */ - collapse_pos(0, i + 1); - break; - } else - i--; /* hack incremet */ - } - - /* collapse (command...(command...)...) or {command...{command...}...} */ - c = 0; /* "recursive" level */ - c2 = 0; - for (i = 0; int_buf[i]; i++) - if (int_buf[i] == '(' || int_buf[i] == '{') { - if (int_buf[i] == '(') - c++; - else - c2++; - collapse_pos(0, i + 1); - i = -1; /* hack incremet */ - } - for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++) - if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) { - if (int_buf[i] == ')') - c--; - else - c2--; - collapse_pos(0, i + 1); - i = -1; /* hack incremet */ - } - - /* skip first not quote space */ - for (i = 0; int_buf[i]; i++) - if (int_buf[i] != ' ') - break; - if (i) - collapse_pos(0, i); - - /* set find mode for completion */ - command_mode = FIND_EXE_ONLY; - for (i = 0; int_buf[i]; i++) - if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') { - if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY - && matchBuf[pos_buf[0]]=='c' - && matchBuf[pos_buf[1]]=='d' ) - command_mode = FIND_DIR_ONLY; - else { - command_mode = FIND_FILE_ONLY; - break; - } - } - /* "strlen" */ - for (i = 0; int_buf[i]; i++); - /* find last word */ - for (--i; i >= 0; i--) { - c = int_buf[i]; - if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') { - collapse_pos(0, i + 1); - break; - } - } - /* skip first not quoted '\'' or '"' */ - for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++); - /* collapse quote or unquote // or /~ */ - while ((int_buf[i] & ~QUOT) == '/' && - ((int_buf[i + 1] & ~QUOT) == '/' - || (int_buf[i + 1] & ~QUOT) == '~')) { - i++; - } - - /* set only match and destroy quotes */ - j = 0; - for (c = 0; pos_buf[i] >= 0; i++) { - matchBuf[c++] = matchBuf[pos_buf[i]]; - j = pos_buf[i] + 1; - } - matchBuf[c] = 0; - /* old lenght matchBuf with quotes symbols */ - *len_with_quotes = j ? j - pos_buf[0] : 0; - - return command_mode; -} - - -static void input_tab(int *lastWasTab) -{ - /* Do TAB completion */ - static int num_matches; - static char **matches; - - if (lastWasTab == 0) { /* free all memory */ - if (matches) { - while (num_matches > 0) - free(matches[--num_matches]); - free(matches); - matches = (char **) NULL; - } - return; - } - if (*lastWasTab == FALSE) { - - char *tmp; - int len_found; - char matchBuf[BUFSIZ]; - int find_type; - int recalc_pos; - - *lastWasTab = TRUE; /* flop trigger */ - - /* Make a local copy of the string -- up - * to the position of the cursor */ - tmp = strncpy(matchBuf, command_ps, cursor); - tmp[cursor] = 0; - - find_type = find_match(matchBuf, &recalc_pos); - - /* Free up any memory already allocated */ - input_tab(0); - -#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION - /* If the word starts with `~' and there is no slash in the word, - * then try completing this word as a username. */ - - if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0) - matches = username_tab_completion(matchBuf, &num_matches); -#endif - /* Try to match any executable in our path and everything - * in the current working directory that matches. */ - if (!matches) - matches = - exe_n_cwd_tab_completion(matchBuf, - &num_matches, find_type); - /* Remove duplicate found */ - if(matches) { - int i, j; - /* bubble */ - for(i=0; i<(num_matches-1); i++) - for(j=i+1; j 1) { - char *tmp1; - - beep(); - if (!matches) - return; /* not found */ - /* sort */ - qsort(matches, num_matches, sizeof(char *), match_compare); - - /* find minimal match */ - tmp = xstrdup(matches[0]); - for (tmp1 = tmp; *tmp1; tmp1++) - for (len_found = 1; len_found < num_matches; len_found++) - if (matches[len_found][(tmp1 - tmp)] != *tmp1) { - *tmp1 = 0; - break; - } - if (*tmp == 0) { /* have unique */ - free(tmp); - return; - } - } else { /* one match */ - tmp = matches[0]; - /* for next completion current found */ - *lastWasTab = FALSE; - } - - len_found = strlen(tmp); - /* have space to placed match? */ - if ((len_found - strlen(matchBuf) + len) < BUFSIZ) { - - /* before word for match */ - command_ps[cursor - recalc_pos] = 0; - /* save tail line */ - strcpy(matchBuf, command_ps + cursor); - /* add match */ - strcat(command_ps, tmp); - /* add tail */ - strcat(command_ps, matchBuf); - /* back to begin word for match */ - input_backward(recalc_pos); - /* new pos */ - recalc_pos = cursor + len_found; - /* new len */ - len = strlen(command_ps); - /* write out the matched command */ - redraw(cmdedit_y, len - recalc_pos); - } - if (tmp != matches[0]) - free(tmp); - } else { - /* Ok -- the last char was a TAB. Since they - * just hit TAB again, print a list of all the - * available choices... */ - if (matches && num_matches > 0) { - int i, col, l; - int sav_cursor = cursor; /* change goto_new_line() */ - - /* Go to the next line */ - goto_new_line(); - for (i = 0, col = 0; i < num_matches; i++) { - l = strlen(matches[i]); - if (l < 14) - l = 14; - printf("%-14s ", matches[i]); - if ((l += 2) > 16) - while (l % 16) { - putchar(' '); - l++; - } - col += l; - col -= (col / cmdedit_termw) * cmdedit_termw; - if (col > 60 && matches[i + 1] != NULL) { - putchar('\n'); - col = 0; - } - } - /* Go to the next line and rewrite */ - putchar('\n'); - redraw(0, len - sav_cursor); - } - } -} -#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ - -static void get_previous_history(struct history **hp, struct history *p) -{ - if ((*hp)->s) - free((*hp)->s); - (*hp)->s = xstrdup(command_ps); - *hp = p; -} - -static inline void get_next_history(struct history **hp) -{ - get_previous_history(hp, (*hp)->n); -} - -enum { - ESC = 27, - DEL = 127, -}; - - -/* - * This function is used to grab a character buffer - * from the input file descriptor and allows you to - * a string with full command editing (sortof like - * a mini readline). - * - * The following standard commands are not implemented: - * ESC-b -- Move back one word - * ESC-f -- Move forward one word - * ESC-d -- Delete back one word - * ESC-h -- Delete forward one word - * CTL-t -- Transpose two characters - * - * Furthermore, the "vi" command editing keys are not implemented. - * - */ - - -int cmdedit_read_input(char *prompt, char command[BUFSIZ]) -{ - - int break_out = 0; - int lastWasTab = FALSE; - unsigned char c = 0; - struct history *hp = his_end; - - /* prepare before init handlers */ - cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ - len = 0; - command_ps = command; - - getTermSettings(0, (void *) &initial_settings); - memcpy(&new_settings, &initial_settings, sizeof(struct termios)); - new_settings.c_lflag &= ~ICANON; /* unbuffered input */ - /* Turn off echoing and CTRL-C, so we can trap it */ - new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG); -#ifndef linux - /* Hmm, in linux c_cc[] not parsed if set ~ICANON */ - new_settings.c_cc[VMIN] = 1; - new_settings.c_cc[VTIME] = 0; - /* Turn off CTRL-C, so we can trap it */ -# ifndef _POSIX_VDISABLE -# define _POSIX_VDISABLE '\0' -# endif - new_settings.c_cc[VINTR] = _POSIX_VDISABLE; -#endif - command[0] = 0; - - setTermSettings(0, (void *) &new_settings); - handlers_sets |= SET_RESET_TERM; - - /* Now initialize things */ - cmdedit_init(); - /* Print out the command prompt */ - parse_prompt(prompt); - - while (1) { - - fflush(stdout); /* buffered out to fast */ - - if (safe_read(0, &c, 1) < 1) - /* if we can't read input then exit */ - goto prepare_to_die; - - switch (c) { - case '\n': - case '\r': - /* Enter */ - goto_new_line(); - break_out = 1; - break; - case 1: - /* Control-a -- Beginning of line */ - input_backward(cursor); - break; - case 2: - /* Control-b -- Move back one character */ - input_backward(1); - break; - case 3: - /* Control-c -- stop gathering input */ - goto_new_line(); - command[0] = 0; - len = 0; - lastWasTab = FALSE; - put_prompt(); - break; - case 4: - /* Control-d -- Delete one character, or exit - * if the len=0 and no chars to delete */ - if (len == 0) { -prepare_to_die: -#if !defined(BB_ASH) - printf("exit"); - goto_new_line(); - /* cmdedit_reset_term() called in atexit */ - exit(EXIT_SUCCESS); -#else - break_out = -1; /* for control stoped jobs */ - break; -#endif - } else { - input_delete(); - } - break; - case 5: - /* Control-e -- End of line */ - input_end(); - break; - case 6: - /* Control-f -- Move forward one character */ - input_forward(); - break; - case '\b': - case DEL: - /* Control-h and DEL */ - input_backspace(); - break; - case '\t': -#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION - input_tab(&lastWasTab); -#endif - break; - case 14: - /* Control-n -- Get next command in history */ - if (hp && hp->n && hp->n->s) { - get_next_history(&hp); - goto rewrite_line; - } else { - beep(); - } - break; - case 16: - /* Control-p -- Get previous command from history */ - if (hp && hp->p) { - get_previous_history(&hp, hp->p); - goto rewrite_line; - } else { - beep(); - } - break; - case 21: - /* Control-U -- Clear line before cursor */ - if (cursor) { - strcpy(command, command + cursor); - redraw(cmdedit_y, len -= cursor); - } - break; - - case ESC:{ - /* escape sequence follows */ - if (safe_read(0, &c, 1) < 1) - goto prepare_to_die; - /* different vt100 emulations */ - if (c == '[' || c == 'O') { - if (safe_read(0, &c, 1) < 1) - goto prepare_to_die; - } - switch (c) { -#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION - case '\t': /* Alt-Tab */ - - input_tab(&lastWasTab); - break; -#endif - case 'A': - /* Up Arrow -- Get previous command from history */ - if (hp && hp->p) { - get_previous_history(&hp, hp->p); - goto rewrite_line; - } else { - beep(); - } - break; - case 'B': - /* Down Arrow -- Get next command in history */ - if (hp && hp->n && hp->n->s) { - get_next_history(&hp); - goto rewrite_line; - } else { - beep(); - } - break; - - /* Rewrite the line with the selected history item */ - rewrite_line: - /* change command */ - len = strlen(strcpy(command, hp->s)); - /* redraw and go to end line */ - redraw(cmdedit_y, 0); - break; - case 'C': - /* Right Arrow -- Move forward one character */ - input_forward(); - break; - case 'D': - /* Left Arrow -- Move back one character */ - input_backward(1); - break; - case '3': - /* Delete */ - input_delete(); - break; - case '1': - case 'H': - /* Home (Ctrl-A) */ - input_backward(cursor); - break; - case '4': - case 'F': - /* End (Ctrl-E) */ - input_end(); - break; - default: - if (!(c >= '1' && c <= '9')) - c = 0; - beep(); - } - if (c >= '1' && c <= '9') - do - if (safe_read(0, &c, 1) < 1) - goto prepare_to_die; - while (c != '~'); - break; - } - - default: /* If it's regular input, do the normal thing */ -#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT - /* Control-V -- Add non-printable symbol */ - if (c == 22) { - if (safe_read(0, &c, 1) < 1) - goto prepare_to_die; - if (c == 0) { - beep(); - break; - } - } else -#endif - if (!Isprint(c)) /* Skip non-printable characters */ - break; - - if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ - break; - - len++; - - if (cursor == (len - 1)) { /* Append if at the end of the line */ - *(command + cursor) = c; - *(command + cursor + 1) = 0; - cmdedit_set_out_char(0); - } else { /* Insert otherwise */ - int sc = cursor; - - memmove(command + sc + 1, command + sc, len - sc); - *(command + sc) = c; - sc++; - /* rewrite from cursor */ - input_end(); - /* to prev x pos + 1 */ - input_backward(cursor - sc); - } - - break; - } - if (break_out) /* Enter is the command terminator, no more input. */ - break; - - if (c != '\t') - lastWasTab = FALSE; - } - - setTermSettings(0, (void *) &initial_settings); - handlers_sets &= ~SET_RESET_TERM; - - /* Handle command history log */ - if (len) { /* no put empty line */ - - struct history *h = his_end; - char *ss; - - ss = xstrdup(command); /* duplicate */ - - if (h == 0) { - /* No previous history -- this memory is never freed */ - h = his_front = xmalloc(sizeof(struct history)); - h->n = xmalloc(sizeof(struct history)); - - h->p = NULL; - h->s = ss; - h->n->p = h; - h->n->n = NULL; - h->n->s = NULL; - his_end = h->n; - history_counter++; - } else { - /* Add a new history command -- this memory is never freed */ - h->n = xmalloc(sizeof(struct history)); - - h->n->p = h; - h->n->n = NULL; - h->n->s = NULL; - h->s = ss; - his_end = h->n; - - /* After max history, remove the oldest command */ - if (history_counter >= MAX_HISTORY) { - - struct history *p = his_front->n; - - p->p = NULL; - free(his_front->s); - free(his_front); - his_front = p; - } else { - history_counter++; - } - } -#if defined(BB_FEATURE_SH_FANCY_PROMPT) - num_ok_lines++; -#endif - } - if(break_out>0) { - command[len++] = '\n'; /* set '\n' */ - command[len] = 0; - } -#if defined(BB_FEATURE_CLEAN_UP) && defined(BB_FEATURE_COMMAND_TAB_COMPLETION) - input_tab(0); /* strong free */ -#endif -#if defined(BB_FEATURE_SH_FANCY_PROMPT) - free(cmdedit_prompt); -#endif - cmdedit_reset_term(); - return len; -} - - - -#endif /* BB_FEATURE_COMMAND_EDITING */ - - -#ifdef TEST - -const char *applet_name = "debug stuff usage"; -const char *memory_exhausted = "Memory exhausted"; - -#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT -#include -#endif - -int main(int argc, char **argv) -{ - char buff[BUFSIZ]; - char *prompt = -#if defined(BB_FEATURE_SH_FANCY_PROMPT) - "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:\ -\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \ -\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]"; -#else - "% "; -#endif - -#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT - setlocale(LC_ALL, ""); -#endif - while(1) { - int l; - cmdedit_read_input(prompt, buff); - l = strlen(buff); - if(l==0) - break; - if(l > 0 && buff[l-1] == '\n') - buff[l-1] = 0; - printf("*** cmdedit_read_input() returned line =%s=\n", buff); - } - printf("*** cmdedit_read_input() detect ^C\n"); - return 0; -} - -#endif /* TEST */ diff --git a/busybox/shell/cmdedit.h b/busybox/shell/cmdedit.h deleted file mode 100644 index 83893572a..000000000 --- a/busybox/shell/cmdedit.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef CMDEDIT_H -#define CMDEDIT_H - -int cmdedit_read_input(char* promptStr, char* command); - -#endif /* CMDEDIT_H */ diff --git a/busybox/shell/hush.c b/busybox/shell/hush.c deleted file mode 100644 index 0e619f80e..000000000 --- a/busybox/shell/hush.c +++ /dev/null @@ -1,2692 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * sh.c -- a prototype Bourne shell grammar parser - * Intended to follow the original Thompson and Ritchie - * "small and simple is beautiful" philosophy, which - * incidentally is a good match to today's BusyBox. - * - * Copyright (C) 2000,2001 Larry Doolittle - * - * Credits: - * The parser routines proper are all original material, first - * written Dec 2000 and Jan 2001 by Larry Doolittle. - * The execution engine, the builtins, and much of the underlying - * support has been adapted from busybox-0.49pre's lash, - * which is Copyright (C) 2000 by Lineo, Inc., and - * written by Erik Andersen , . - * That, in turn, is based in part on ladsh.c, by Michael K. Johnson and - * Erik W. Troan, which they placed in the public domain. I don't know - * how much of the Johnson/Troan code has survived the repeated rewrites. - * Other credits: - * simple_itoa() was lifted from boa-0.93.15 - * b_addchr() derived from similar w_addchar function in glibc-2.2 - * setup_redirect(), redirect_opt_num(), and big chunks of main() - * and many builtins derived from contributions by Erik Andersen - * miscellaneous bugfixes from Matt Kraai - * - * There are two big (and related) architecture differences between - * this parser and the lash parser. One is that this version is - * actually designed from the ground up to understand nearly all - * of the Bourne grammar. The second, consequential change is that - * the parser and input reader have been turned inside out. Now, - * the parser is in control, and asks for input as needed. The old - * way had the input reader in control, and it asked for parsing to - * take place as needed. The new way makes it much easier to properly - * handle the recursion implicit in the various substitutions, especially - * across continuation lines. - * - * Bash grammar not implemented: (how many of these were in original sh?) - * $@ (those sure look like weird quoting rules) - * $_ - * ! negation operator for pipes - * &> and >& redirection of stdout+stderr - * Brace Expansion - * Tilde Expansion - * fancy forms of Parameter Expansion - * aliases - * Arithmetic Expansion - * <(list) and >(list) Process Substitution - * reserved words: case, esac, select, function - * Here Documents ( << word ) - * Functions - * Major bugs: - * job handling woefully incomplete and buggy - * reserved word execution woefully incomplete and buggy - * to-do: - * port selected bugfixes from post-0.49 busybox lash - done? - * finish implementing reserved words: for, while, until, do, done - * change { and } from special chars to reserved words - * builtins: break, continue, eval, return, set, trap, ulimit - * test magic exec - * handle children going into background - * clean up recognition of null pipes - * check setting of global_argc and global_argv - * control-C handling, probably with longjmp - * follow IFS rules more precisely, including update semantics - * figure out what to do with backslash-newline - * explain why we use signal instead of sigaction - * propagate syntax errors, die on resource errors? - * continuation lines, both explicit and implicit - done? - * memory leak finding and plugging - done? - * more testing, especially quoting rules and redirection - * document how quoting rules not precisely followed for variable assignments - * maybe change map[] to use 2-bit entries - * (eventually) remove all the printf's - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include /* isalpha, isdigit */ -#include /* getpid */ -#include /* getenv, atoi */ -#include /* strchr */ -#include /* popen etc. */ -#include /* glob, of course */ -#include /* va_list */ -#include -#include -#include /* should be pretty obvious */ - -#include /* ulimit */ -#include -#include -#include - -/* #include */ -/* #define DEBUG_SHELL */ - -#ifdef BB_VER -#include "busybox.h" -#include "cmdedit.h" -#else -#define applet_name "hush" -#include "standalone.h" -#define hush_main main -#undef BB_FEATURE_SH_FANCY_PROMPT -#endif - -typedef enum { - REDIRECT_INPUT = 1, - REDIRECT_OVERWRITE = 2, - REDIRECT_APPEND = 3, - REDIRECT_HEREIS = 4, - REDIRECT_IO = 5 -} redir_type; - -/* The descrip member of this structure is only used to make debugging - * output pretty */ -struct {int mode; int default_fd; char *descrip;} redir_table[] = { - { 0, 0, "()" }, - { O_RDONLY, 0, "<" }, - { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" }, - { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" }, - { O_RDONLY, -1, "<<" }, - { O_RDWR, 1, "<>" } -}; - -typedef enum { - PIPE_SEQ = 1, - PIPE_AND = 2, - PIPE_OR = 3, - PIPE_BG = 4, -} pipe_style; - -/* might eventually control execution */ -typedef enum { - RES_NONE = 0, - RES_IF = 1, - RES_THEN = 2, - RES_ELIF = 3, - RES_ELSE = 4, - RES_FI = 5, - RES_FOR = 6, - RES_WHILE = 7, - RES_UNTIL = 8, - RES_DO = 9, - RES_DONE = 10, - RES_XXXX = 11, - RES_SNTX = 12 -} reserved_style; -#define FLAG_END (1<, but protected with __USE_GNU */ - -/* "globals" within this file */ -static char *ifs; -static char map[256]; -static int fake_mode; -static int interactive; -static struct close_me *close_me_head; -static const char *cwd; -static struct pipe *job_list; -static unsigned int last_bg_pid; -static unsigned int last_jobid; -static unsigned int shell_terminal; -static char *PS1; -static char *PS2; -struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 }; -struct variables *top_vars = &shell_ver; - - -#define B_CHUNK (100) -#define B_NOSPAC 1 - -typedef struct { - char *data; - int length; - int maxlen; - int quote; - int nonnull; -} o_string; -#define NULL_O_STRING {NULL,0,0,0,0} -/* used for initialization: - o_string foo = NULL_O_STRING; */ - -/* I can almost use ordinary FILE *. Is open_memstream() universally - * available? Where is it documented? */ -struct in_str { - const char *p; - char peek_buf[2]; - int __promptme; - int promptmode; - FILE *file; - int (*get) (struct in_str *); - int (*peek) (struct in_str *); -}; -#define b_getch(input) ((input)->get(input)) -#define b_peek(input) ((input)->peek(input)) - -#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" - -struct built_in_command { - char *cmd; /* name */ - char *descr; /* description */ - int (*function) (struct child_prog *); /* function ptr */ -}; - -/* belongs in busybox.h */ -static inline int max(int a, int b) { - return (a>b)?a:b; -} - -/* This should be in utility.c */ -#ifdef DEBUG_SHELL -static void debug_printf(const char *format, ...) -{ - va_list args; - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); -} -#else -static inline void debug_printf(const char *format, ...) { } -#endif -#define final_printf debug_printf - -static void __syntax(char *file, int line) { - error_msg("syntax error %s:%d", file, line); -} -#define syntax() __syntax(__FILE__, __LINE__) - -/* Index of subroutines: */ -/* function prototypes for builtins */ -static int builtin_cd(struct child_prog *child); -static int builtin_env(struct child_prog *child); -static int builtin_exec(struct child_prog *child); -static int builtin_exit(struct child_prog *child); -static int builtin_export(struct child_prog *child); -static int builtin_fg_bg(struct child_prog *child); -static int builtin_help(struct child_prog *child); -static int builtin_jobs(struct child_prog *child); -static int builtin_pwd(struct child_prog *child); -static int builtin_read(struct child_prog *child); -static int builtin_set(struct child_prog *child); -static int builtin_shift(struct child_prog *child); -static int builtin_source(struct child_prog *child); -static int builtin_umask(struct child_prog *child); -static int builtin_unset(struct child_prog *child); -static int builtin_not_written(struct child_prog *child); -/* o_string manipulation: */ -static int b_check_space(o_string *o, int len); -static int b_addchr(o_string *o, int ch); -static void b_reset(o_string *o); -static int b_addqchr(o_string *o, int ch, int quote); -static int b_adduint(o_string *o, unsigned int i); -/* in_str manipulations: */ -static int static_get(struct in_str *i); -static int static_peek(struct in_str *i); -static int file_get(struct in_str *i); -static int file_peek(struct in_str *i); -static void setup_file_in_str(struct in_str *i, FILE *f); -static void setup_string_in_str(struct in_str *i, const char *s); -/* close_me manipulations: */ -static void mark_open(int fd); -static void mark_closed(int fd); -static void close_all(); -/* "run" the final data structures: */ -static char *indenter(int i); -static int free_pipe_list(struct pipe *head, int indent); -static int free_pipe(struct pipe *pi, int indent); -/* really run the final data structures: */ -static int setup_redirects(struct child_prog *prog, int squirrel[]); -static int run_list_real(struct pipe *pi); -static void pseudo_exec(struct child_prog *child) __attribute__ ((noreturn)); -static int run_pipe_real(struct pipe *pi); -/* extended glob support: */ -static int globhack(const char *src, int flags, glob_t *pglob); -static int glob_needed(const char *s); -static int xglob(o_string *dest, int flags, glob_t *pglob); -/* variable assignment: */ -static int is_assignment(const char *s); -/* data structure manipulation: */ -static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input); -static void initialize_context(struct p_context *ctx); -static int done_word(o_string *dest, struct p_context *ctx); -static int done_command(struct p_context *ctx); -static int done_pipe(struct p_context *ctx, pipe_style type); -/* primary string parsing: */ -static int redirect_dup_num(struct in_str *input); -static int redirect_opt_num(o_string *o); -static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end); -static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); -static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src); -static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); -static int parse_string(o_string *dest, struct p_context *ctx, const char *src); -static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger); -/* setup: */ -static int parse_stream_outer(struct in_str *inp); -static int parse_string_outer(const char *s); -static int parse_file_outer(FILE *f); -/* job management: */ -static int checkjobs(struct pipe* fg_pipe); -static void insert_bg_job(struct pipe *pi); -static void remove_bg_job(struct pipe *pi); -/* local variable support */ -static char *get_local_var(const char *var); -static void unset_local_var(const char *name); -static int set_local_var(const char *s, int flg_export); - -/* Table of built-in functions. They can be forked or not, depending on - * context: within pipes, they fork. As simple commands, they do not. - * When used in non-forking context, they can change global variables - * in the parent shell process. If forked, of course they can not. - * For example, 'unset foo | whatever' will parse and run, but foo will - * still be set at the end. */ -static struct built_in_command bltins[] = { - {"bg", "Resume a job in the background", builtin_fg_bg}, - {"break", "Exit for, while or until loop", builtin_not_written}, - {"cd", "Change working directory", builtin_cd}, - {"continue", "Continue for, while or until loop", builtin_not_written}, - {"env", "Print all environment variables", builtin_env}, - {"eval", "Construct and run shell command", builtin_not_written}, - {"exec", "Exec command, replacing this shell with the exec'd process", - builtin_exec}, - {"exit", "Exit from shell()", builtin_exit}, - {"export", "Set environment variable", builtin_export}, - {"fg", "Bring job into the foreground", builtin_fg_bg}, - {"jobs", "Lists the active jobs", builtin_jobs}, - {"pwd", "Print current directory", builtin_pwd}, - {"read", "Input environment variable", builtin_read}, - {"return", "Return from a function", builtin_not_written}, - {"set", "Set/unset shell local variables", builtin_set}, - {"shift", "Shift positional parameters", builtin_shift}, - {"trap", "Trap signals", builtin_not_written}, - {"ulimit","Controls resource limits", builtin_not_written}, - {"umask","Sets file creation mask", builtin_umask}, - {"unset", "Unset environment variable", builtin_unset}, - {".", "Source-in and run commands in a file", builtin_source}, - {"help", "List shell built-in commands", builtin_help}, - {NULL, NULL, NULL} -}; - -static const char *set_cwd(void) -{ - if(cwd==unknown) - cwd = NULL; /* xgetcwd(arg) called free(arg) */ - cwd = xgetcwd((char *)cwd); - if (!cwd) - cwd = unknown; - return cwd; -} - - -/* built-in 'cd ' handler */ -static int builtin_cd(struct child_prog *child) -{ - char *newdir; - if (child->argv[1] == NULL) - newdir = getenv("HOME"); - else - newdir = child->argv[1]; - if (chdir(newdir)) { - printf("cd: %s: %s\n", newdir, strerror(errno)); - return EXIT_FAILURE; - } - set_cwd(); - return EXIT_SUCCESS; -} - -/* built-in 'env' handler */ -static int builtin_env(struct child_prog *dummy) -{ - char **e = environ; - if (e == NULL) return EXIT_FAILURE; - for (; *e; e++) { - puts(*e); - } - return EXIT_SUCCESS; -} - -/* built-in 'exec' handler */ -static int builtin_exec(struct child_prog *child) -{ - if (child->argv[1] == NULL) - return EXIT_SUCCESS; /* Really? */ - child->argv++; - pseudo_exec(child); - /* never returns */ -} - -/* built-in 'exit' handler */ -static int builtin_exit(struct child_prog *child) -{ - if (child->argv[1] == NULL) - exit(last_return_code); - exit (atoi(child->argv[1])); -} - -/* built-in 'export VAR=value' handler */ -static int builtin_export(struct child_prog *child) -{ - int res = 0; - char *name = child->argv[1]; - - if (name == NULL) { - return (builtin_env(child)); - } - - name = strdup(name); - - if(name) { - char *value = strchr(name, '='); - - if (!value) { - char *tmp; - /* They are exporting something without an =VALUE */ - - value = get_local_var(name); - if (value) { - size_t ln = strlen(name); - - tmp = realloc(name, ln+strlen(value)+2); - if(tmp==NULL) - res = -1; - else { - sprintf(tmp+ln, "=%s", value); - name = tmp; - } - } else { - /* bash does not return an error when trying to export - * an undefined variable. Do likewise. */ - res = 1; - } - } - } - if (res<0) - perror_msg("export"); - else if(res==0) - res = set_local_var(name, 1); - else - res = 0; - free(name); - return res; -} - -/* built-in 'fg' and 'bg' handler */ -static int builtin_fg_bg(struct child_prog *child) -{ - int i, jobnum; - struct pipe *pi=NULL; - - if (!interactive) - return EXIT_FAILURE; - /* If they gave us no args, assume they want the last backgrounded task */ - if (!child->argv[1]) { - for (pi = job_list; pi; pi = pi->next) { - if (pi->jobid == last_jobid) { - break; - } - } - if (!pi) { - error_msg("%s: no current job", child->argv[0]); - return EXIT_FAILURE; - } - } else { - if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { - error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]); - return EXIT_FAILURE; - } - for (pi = job_list; pi; pi = pi->next) { - if (pi->jobid == jobnum) { - break; - } - } - if (!pi) { - error_msg("%s: %d: no such job", child->argv[0], jobnum); - return EXIT_FAILURE; - } - } - - if (*child->argv[0] == 'f') { - /* Put the job into the foreground. */ - tcsetpgrp(shell_terminal, pi->pgrp); - } - - /* Restart the processes in the job */ - for (i = 0; i < pi->num_progs; i++) - pi->progs[i].is_stopped = 0; - - if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) { - if (i == ESRCH) { - remove_bg_job(pi); - } else { - perror_msg("kill (SIGCONT)"); - } - } - - pi->stopped_progs = 0; - return EXIT_SUCCESS; -} - -/* built-in 'help' handler */ -static int builtin_help(struct child_prog *dummy) -{ - struct built_in_command *x; - - printf("\nBuilt-in commands:\n"); - printf("-------------------\n"); - for (x = bltins; x->cmd; x++) { - if (x->descr==NULL) - continue; - printf("%s\t%s\n", x->cmd, x->descr); - } - printf("\n\n"); - return EXIT_SUCCESS; -} - -/* built-in 'jobs' handler */ -static int builtin_jobs(struct child_prog *child) -{ - struct pipe *job; - char *status_string; - - for (job = job_list; job; job = job->next) { - if (job->running_progs == job->stopped_progs) - status_string = "Stopped"; - else - status_string = "Running"; - - printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text); - } - return EXIT_SUCCESS; -} - - -/* built-in 'pwd' handler */ -static int builtin_pwd(struct child_prog *dummy) -{ - puts(set_cwd()); - return EXIT_SUCCESS; -} - -/* built-in 'read VAR' handler */ -static int builtin_read(struct child_prog *child) -{ - int res; - - if (child->argv[1]) { - char string[BUFSIZ]; - char *var = 0; - - string[0] = 0; /* In case stdin has only EOF */ - /* read string */ - fgets(string, sizeof(string), stdin); - chomp(string); - var = malloc(strlen(child->argv[1])+strlen(string)+2); - if(var) { - sprintf(var, "%s=%s", child->argv[1], string); - res = set_local_var(var, 0); - } else - res = -1; - if (res) - fprintf(stderr, "read: %m\n"); - free(var); /* So not move up to avoid breaking errno */ - return res; - } else { - do res=getchar(); while(res!='\n' && res!=EOF); - return 0; - } -} - -/* built-in 'set VAR=value' handler */ -static int builtin_set(struct child_prog *child) -{ - char *temp = child->argv[1]; - struct variables *e; - - if (temp == NULL) - for(e = top_vars; e; e=e->next) - printf("%s=%s\n", e->name, e->value); - else - set_local_var(temp, 0); - - return EXIT_SUCCESS; -} - - -/* Built-in 'shift' handler */ -static int builtin_shift(struct child_prog *child) -{ - int n=1; - if (child->argv[1]) { - n=atoi(child->argv[1]); - } - if (n>=0 && nargv[1] == NULL) - return EXIT_FAILURE; - - /* XXX search through $PATH is missing */ - input = fopen(child->argv[1], "r"); - if (!input) { - error_msg("Couldn't open file '%s'", child->argv[1]); - return EXIT_FAILURE; - } - - /* Now run the file */ - /* XXX argv and argc are broken; need to save old global_argv - * (pointer only is OK!) on this stack frame, - * set global_argv=child->argv+1, recurse, and restore. */ - mark_open(fileno(input)); - status = parse_file_outer(input); - mark_closed(fileno(input)); - fclose(input); - return (status); -} - -static int builtin_umask(struct child_prog *child) -{ - mode_t new_umask; - const char *arg = child->argv[1]; - char *end; - if (arg) { - new_umask=strtoul(arg, &end, 8); - if (*end!='\0' || end == arg) { - return EXIT_FAILURE; - } - } else { - printf("%.3o\n", (unsigned int) (new_umask=umask(0))); - } - umask(new_umask); - return EXIT_SUCCESS; -} - -/* built-in 'unset VAR' handler */ -static int builtin_unset(struct child_prog *child) -{ - /* bash returned already true */ - unset_local_var(child->argv[1]); - return EXIT_SUCCESS; -} - -static int builtin_not_written(struct child_prog *child) -{ - printf("builtin_%s not written\n",child->argv[0]); - return EXIT_FAILURE; -} - -static int b_check_space(o_string *o, int len) -{ - /* It would be easy to drop a more restrictive policy - * in here, such as setting a maximum string length */ - if (o->length + len > o->maxlen) { - char *old_data = o->data; - /* assert (data == NULL || o->maxlen != 0); */ - o->maxlen += max(2*len, B_CHUNK); - o->data = realloc(o->data, 1 + o->maxlen); - if (o->data == NULL) { - free(old_data); - } - } - return o->data == NULL; -} - -static int b_addchr(o_string *o, int ch) -{ - debug_printf("b_addchr: %c %d %p\n", ch, o->length, o); - if (b_check_space(o, 1)) return B_NOSPAC; - o->data[o->length] = ch; - o->length++; - o->data[o->length] = '\0'; - return 0; -} - -static void b_reset(o_string *o) -{ - o->length = 0; - o->nonnull = 0; - if (o->data != NULL) *o->data = '\0'; -} - -static void b_free(o_string *o) -{ - b_reset(o); - if (o->data != NULL) free(o->data); - o->data = NULL; - o->maxlen = 0; -} - -/* My analysis of quoting semantics tells me that state information - * is associated with a destination, not a source. - */ -static int b_addqchr(o_string *o, int ch, int quote) -{ - if (quote && strchr("*?[\\",ch)) { - int rc; - rc = b_addchr(o, '\\'); - if (rc) return rc; - } - return b_addchr(o, ch); -} - -/* belongs in utility.c */ -char *simple_itoa(unsigned int i) -{ - /* 21 digits plus null terminator, good for 64-bit or smaller ints */ - static char local[22]; - char *p = &local[21]; - *p-- = '\0'; - do { - *p-- = '0' + i % 10; - i /= 10; - } while (i > 0); - return p + 1; -} - -static int b_adduint(o_string *o, unsigned int i) -{ - int r; - char *p = simple_itoa(i); - /* no escape checking necessary */ - do r=b_addchr(o, *p++); while (r==0 && *p); - return r; -} - -static int static_get(struct in_str *i) -{ - int ch=*i->p++; - if (ch=='\0') return EOF; - return ch; -} - -static int static_peek(struct in_str *i) -{ - return *i->p; -} - -static inline void cmdedit_set_initial_prompt(void) -{ -#ifndef BB_FEATURE_SH_FANCY_PROMPT - PS1 = NULL; -#else - PS1 = getenv("PS1"); - if(PS1==0) - PS1 = "\\w \\$ "; -#endif -} - -static inline void setup_prompt_string(int promptmode, char **prompt_str) -{ - debug_printf("setup_prompt_string %d ",promptmode); -#ifndef BB_FEATURE_SH_FANCY_PROMPT - /* Set up the prompt */ - if (promptmode == 1) { - if (PS1) - free(PS1); - PS1=xmalloc(strlen(cwd)+4); - sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); - *prompt_str = PS1; - } else { - *prompt_str = PS2; - } -#else - *prompt_str = (promptmode==1)? PS1 : PS2; -#endif - debug_printf("result %s\n",*prompt_str); -} - -static void get_user_input(struct in_str *i) -{ - char *prompt_str; - static char the_command[BUFSIZ]; - - setup_prompt_string(i->promptmode, &prompt_str); -#ifdef BB_FEATURE_COMMAND_EDITING - /* - ** enable command line editing only while a command line - ** is actually being read; otherwise, we'll end up bequeathing - ** atexit() handlers and other unwanted stuff to our - ** child processes (rob@sysgo.de) - */ - cmdedit_read_input(prompt_str, the_command); -#else - fputs(prompt_str, stdout); - fflush(stdout); - the_command[0]=fgetc(i->file); - the_command[1]='\0'; -#endif - fflush(stdout); - i->p = the_command; -} - -/* This is the magic location that prints prompts - * and gets data back from the user */ -static int file_get(struct in_str *i) -{ - int ch; - - ch = 0; - /* If there is data waiting, eat it up */ - if (i->p && *i->p) { - ch=*i->p++; - } else { - /* need to double check i->file because we might be doing something - * more complicated by now, like sourcing or substituting. */ - if (i->__promptme && interactive && i->file == stdin) { - while(! i->p || (interactive && strlen(i->p)==0) ) { - get_user_input(i); - } - i->promptmode=2; - i->__promptme = 0; - if (i->p && *i->p) { - ch=*i->p++; - } - } else { - ch = fgetc(i->file); - } - - debug_printf("b_getch: got a %d\n", ch); - } - if (ch == '\n') i->__promptme=1; - return ch; -} - -/* All the callers guarantee this routine will never be - * used right after a newline, so prompting is not needed. - */ -static int file_peek(struct in_str *i) -{ - if (i->p && *i->p) { - return *i->p; - } else { - i->peek_buf[0] = fgetc(i->file); - i->peek_buf[1] = '\0'; - i->p = i->peek_buf; - debug_printf("b_peek: got a %d\n", *i->p); - return *i->p; - } -} - -static void setup_file_in_str(struct in_str *i, FILE *f) -{ - i->peek = file_peek; - i->get = file_get; - i->__promptme=1; - i->promptmode=1; - i->file = f; - i->p = NULL; -} - -static void setup_string_in_str(struct in_str *i, const char *s) -{ - i->peek = static_peek; - i->get = static_get; - i->__promptme=1; - i->promptmode=1; - i->p = s; -} - -static void mark_open(int fd) -{ - struct close_me *new = xmalloc(sizeof(struct close_me)); - new->fd = fd; - new->next = close_me_head; - close_me_head = new; -} - -static void mark_closed(int fd) -{ - struct close_me *tmp; - if (close_me_head == NULL || close_me_head->fd != fd) - error_msg_and_die("corrupt close_me"); - tmp = close_me_head; - close_me_head = close_me_head->next; - free(tmp); -} - -static void close_all() -{ - struct close_me *c; - for (c=close_me_head; c; c=c->next) { - close(c->fd); - } - close_me_head = NULL; -} - -/* squirrel != NULL means we squirrel away copies of stdin, stdout, - * and stderr if they are redirected. */ -static int setup_redirects(struct child_prog *prog, int squirrel[]) -{ - int openfd, mode; - struct redir_struct *redir; - - for (redir=prog->redirects; redir; redir=redir->next) { - if (redir->dup == -1 && redir->word.gl_pathv == NULL) { - /* something went wrong in the parse. Pretend it didn't happen */ - continue; - } - if (redir->dup == -1) { - mode=redir_table[redir->type].mode; - openfd = open(redir->word.gl_pathv[0], mode, 0666); - if (openfd < 0) { - /* this could get lost if stderr has been redirected, but - bash and ash both lose it as well (though zsh doesn't!) */ - perror_msg("error opening %s", redir->word.gl_pathv[0]); - return 1; - } - } else { - openfd = redir->dup; - } - - if (openfd != redir->fd) { - if (squirrel && redir->fd < 3) { - squirrel[redir->fd] = dup(redir->fd); - } - if (openfd == -3) { - close(openfd); - } else { - dup2(openfd, redir->fd); - if (redir->dup == -1) - close (openfd); - } - } - } - return 0; -} - -static void restore_redirects(int squirrel[]) -{ - int i, fd; - for (i=0; i<3; i++) { - fd = squirrel[i]; - if (fd != -1) { - /* No error checking. I sure wouldn't know what - * to do with an error if I found one! */ - dup2(fd, i); - close(fd); - } - } -} - -/* never returns */ -/* XXX no exit() here. If you don't exec, use _exit instead. - * The at_exit handlers apparently confuse the calling process, - * in particular stdin handling. Not sure why? */ -static void pseudo_exec(struct child_prog *child) -{ - int i, rcode; - struct built_in_command *x; - if (child->argv) { - for (i=0; is_assignment(child->argv[i]); i++) { - debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]); - putenv(strdup(child->argv[i])); - } - child->argv+=i; /* XXX this hack isn't so horrible, since we are about - to exit, and therefore don't need to keep data - structures consistent for free() use. */ - /* If a variable is assigned in a forest, and nobody listens, - * was it ever really set? - */ - if (child->argv[0] == NULL) { - _exit(EXIT_SUCCESS); - } - - /* - * Check if the command matches any of the builtins. - * Depending on context, this might be redundant. But it's - * easier to waste a few CPU cycles than it is to figure out - * if this is one of those cases. - */ - for (x = bltins; x->cmd; x++) { - if (strcmp(child->argv[0], x->cmd) == 0 ) { - debug_printf("builtin exec %s\n", child->argv[0]); - rcode = x->function(child); - fflush(stdout); - _exit(rcode); - } - } - - /* Check if the command matches any busybox internal commands - * ("applets") here. - * FIXME: This feature is not 100% safe, since - * BusyBox is not fully reentrant, so we have no guarantee the things - * from the .bss are still zeroed, or that things from .data are still - * at their defaults. We could exec ourself from /proc/self/exe, but I - * really dislike relying on /proc for things. We could exec ourself - * from global_argv[0], but if we are in a chroot, we may not be able - * to find ourself... */ -#ifdef BB_FEATURE_SH_STANDALONE_SHELL - { - int argc_l; - char** argv_l=child->argv; - char *name = child->argv[0]; - -#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN - /* Following discussions from November 2000 on the busybox mailing - * list, the default configuration, (without - * get_last_path_component()) lets the user force use of an - * external command by specifying the full (with slashes) filename. - * If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then applets - * _aways_ override external commands, so if you want to run - * /bin/cat, it will use BusyBox cat even if /bin/cat exists on the - * filesystem and is _not_ busybox. Some systems may want this, - * most do not. */ - name = get_last_path_component(name); -#endif - /* Count argc for use in a second... */ - for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++); - optind = 1; - debug_printf("running applet %s\n", name); - run_applet_by_name(name, argc_l, child->argv); - } -#endif - debug_printf("exec of %s\n",child->argv[0]); - execvp(child->argv[0],child->argv); - perror_msg("couldn't exec: %s",child->argv[0]); - _exit(1); - } else if (child->group) { - debug_printf("runtime nesting to group\n"); - interactive=0; /* crucial!!!! */ - rcode = run_list_real(child->group); - /* OK to leak memory by not calling free_pipe_list, - * since this process is about to exit */ - _exit(rcode); - } else { - /* Can happen. See what bash does with ">foo" by itself. */ - debug_printf("trying to pseudo_exec null command\n"); - _exit(EXIT_SUCCESS); - } -} - -static void insert_bg_job(struct pipe *pi) -{ - struct pipe *thejob; - - /* Linear search for the ID of the job to use */ - pi->jobid = 1; - for (thejob = job_list; thejob; thejob = thejob->next) - if (thejob->jobid >= pi->jobid) - pi->jobid = thejob->jobid + 1; - - /* add thejob to the list of running jobs */ - if (!job_list) { - thejob = job_list = xmalloc(sizeof(*thejob)); - } else { - for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */; - thejob->next = xmalloc(sizeof(*thejob)); - thejob = thejob->next; - } - - /* physically copy the struct job */ - memcpy(thejob, pi, sizeof(struct pipe)); - thejob->next = NULL; - thejob->running_progs = thejob->num_progs; - thejob->stopped_progs = 0; - thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */ - - //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0]) - { - char *bar=thejob->text; - char **foo=pi->progs[0].argv; - while(foo && *foo) { - bar += sprintf(bar, "%s ", *foo++); - } - } - - /* we don't wait for background thejobs to return -- append it - to the list of backgrounded thejobs and leave it alone */ - printf("[%d] %d\n", thejob->jobid, thejob->progs[0].pid); - last_bg_pid = thejob->progs[0].pid; - last_jobid = thejob->jobid; -} - -/* remove a backgrounded job */ -static void remove_bg_job(struct pipe *pi) -{ - struct pipe *prev_pipe; - - if (pi == job_list) { - job_list = pi->next; - } else { - prev_pipe = job_list; - while (prev_pipe->next != pi) - prev_pipe = prev_pipe->next; - prev_pipe->next = pi->next; - } - if (job_list) - last_jobid = job_list->jobid; - else - last_jobid = 0; - - pi->stopped_progs = 0; - free_pipe(pi, 0); - free(pi); -} - -/* Checks to see if any processes have exited -- if they - have, figure out why and see if a job has completed */ -static int checkjobs(struct pipe* fg_pipe) -{ - int attributes; - int status; - int prognum = 0; - struct pipe *pi; - pid_t childpid; - - attributes = WUNTRACED; - if (fg_pipe==NULL) { - attributes |= WNOHANG; - } - - while ((childpid = waitpid(-1, &status, attributes)) > 0) { - if (fg_pipe) { - int i, rcode = 0; - for (i=0; i < fg_pipe->num_progs; i++) { - if (fg_pipe->progs[i].pid == childpid) { - if (i==fg_pipe->num_progs-1) - rcode=WEXITSTATUS(status); - (fg_pipe->num_progs)--; - return(rcode); - } - } - } - - for (pi = job_list; pi; pi = pi->next) { - prognum = 0; - while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) { - prognum++; - } - if (prognum < pi->num_progs) - break; - } - - if(pi==NULL) { - debug_printf("checkjobs: pid %d was not in our list!\n", childpid); - continue; - } - - if (WIFEXITED(status) || WIFSIGNALED(status)) { - /* child exited */ - pi->running_progs--; - pi->progs[prognum].pid = 0; - - if (!pi->running_progs) { - printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text); - remove_bg_job(pi); - } - } else { - /* child stopped */ - pi->stopped_progs++; - pi->progs[prognum].is_stopped = 1; - -#if 0 - /* Printing this stuff is a pain, since it tends to - * overwrite the prompt an inconveinient moments. So - * don't do that. */ - if (pi->stopped_progs == pi->num_progs) { - printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text); - } -#endif - } - } - - if (childpid == -1 && errno != ECHILD) - perror_msg("waitpid"); - - /* move the shell to the foreground */ - //if (interactive && tcsetpgrp(shell_terminal, getpgid(0))) - // perror_msg("tcsetpgrp-2"); - return -1; -} - -/* Figure out our controlling tty, checking in order stderr, - * stdin, and stdout. If check_pgrp is set, also check that - * we belong to the foreground process group associated with - * that tty. The value of shell_terminal is needed in order to call - * tcsetpgrp(shell_terminal, ...); */ -void controlling_tty(int check_pgrp) -{ - pid_t curpgrp; - - if ((curpgrp = tcgetpgrp(shell_terminal = 2)) < 0 - && (curpgrp = tcgetpgrp(shell_terminal = 0)) < 0 - && (curpgrp = tcgetpgrp(shell_terminal = 1)) < 0) - goto shell_terminal_error; - - if (check_pgrp && curpgrp != getpgid(0)) - goto shell_terminal_error; - - return; - -shell_terminal_error: - shell_terminal = -1; - return; -} - -/* run_pipe_real() starts all the jobs, but doesn't wait for anything - * to finish. See checkjobs(). - * - * return code is normally -1, when the caller has to wait for children - * to finish to determine the exit status of the pipe. If the pipe - * is a simple builtin command, however, the action is done by the - * time run_pipe_real returns, and the exit code is provided as the - * return value. - * - * The input of the pipe is always stdin, the output is always - * stdout. The outpipe[] mechanism in BusyBox-0.48 lash is bogus, - * because it tries to avoid running the command substitution in - * subshell, when that is in fact necessary. The subshell process - * now has its stdout directed to the input of the appropriate pipe, - * so this routine is noticeably simpler. - */ -static int run_pipe_real(struct pipe *pi) -{ - int i; - int nextin, nextout; - int pipefds[2]; /* pipefds[0] is for reading */ - struct child_prog *child; - struct built_in_command *x; - - nextin = 0; - pi->pgrp = -1; - - /* Check if this is a simple builtin (not part of a pipe). - * Builtins within pipes have to fork anyway, and are handled in - * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. - */ - if (pi->num_progs == 1) child = & (pi->progs[0]); - if (pi->num_progs == 1 && child->group && child->subshell == 0) { - int squirrel[] = {-1, -1, -1}; - int rcode; - debug_printf("non-subshell grouping\n"); - setup_redirects(child, squirrel); - /* XXX could we merge code with following builtin case, - * by creating a pseudo builtin that calls run_list_real? */ - rcode = run_list_real(child->group); - restore_redirects(squirrel); - return rcode; - } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) { - for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ } - if (i!=0 && child->argv[i]==NULL) { - /* assignments, but no command: set the local environment */ - for (i=0; child->argv[i]!=NULL; i++) { - - /* Ok, this case is tricky. We have to decide if this is a - * local variable, or an already exported variable. If it is - * already exported, we have to export the new value. If it is - * not exported, we need only set this as a local variable. - * This junk is all to decide whether or not to export this - * variable. */ - int export_me=0; - char *name, *value; - name = xstrdup(child->argv[i]); - debug_printf("Local environment set: %s\n", name); - value = strchr(name, '='); - if (value) - *value=0; - if ( get_local_var(name)) { - export_me=1; - } - free(name); - set_local_var(child->argv[i], export_me); - } - return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ - } - for (x = bltins; x->cmd; x++) { - if (strcmp(child->argv[i], x->cmd) == 0 ) { - int squirrel[] = {-1, -1, -1}; - int rcode; - if (x->function == builtin_exec && child->argv[i+1]==NULL) { - debug_printf("magic exec\n"); - setup_redirects(child,NULL); - return EXIT_SUCCESS; - } - debug_printf("builtin inline %s\n", child->argv[0]); - /* XXX setup_redirects acts on file descriptors, not FILEs. - * This is perfect for work that comes after exec(). - * Is it really safe for inline use? Experimentally, - * things seem to work with glibc. */ - setup_redirects(child, squirrel); - for (i=0; is_assignment(child->argv[i]); i++) { - putenv(strdup(child->argv[i])); - } - child->argv+=i; /* XXX horrible hack */ - rcode = x->function(child); - child->argv-=i; /* XXX restore hack so free() can work right */ - restore_redirects(squirrel); - return rcode; - } - } - } - - for (i = 0; i < pi->num_progs; i++) { - child = & (pi->progs[i]); - - /* pipes are inserted between pairs of commands */ - if ((i + 1) < pi->num_progs) { - if (pipe(pipefds)<0) perror_msg_and_die("pipe"); - nextout = pipefds[1]; - } else { - nextout=1; - pipefds[0] = -1; - } - - /* XXX test for failed fork()? */ - if (!(child->pid = fork())) { - /* Set the handling for job control signals back to the default. */ - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGTSTP, SIG_DFL); - signal(SIGTTIN, SIG_DFL); - signal(SIGTTOU, SIG_DFL); - signal(SIGCHLD, SIG_DFL); - - close_all(); - - if (nextin != 0) { - dup2(nextin, 0); - close(nextin); - } - if (nextout != 1) { - dup2(nextout, 1); - close(nextout); - } - if (pipefds[0]!=-1) { - close(pipefds[0]); /* opposite end of our output pipe */ - } - - /* Like bash, explicit redirects override pipes, - * and the pipe fd is available for dup'ing. */ - setup_redirects(child,NULL); - - if (interactive && pi->followup!=PIPE_BG) { - /* If we (the child) win the race, put ourselves in the process - * group whose leader is the first process in this pipe. */ - if (pi->pgrp < 0) { - pi->pgrp = getpid(); - } - if (setpgid(0, pi->pgrp) == 0) { - tcsetpgrp(2, pi->pgrp); - } - } - - pseudo_exec(child); - } - - - /* put our child in the process group whose leader is the - first process in this pipe */ - if (pi->pgrp < 0) { - pi->pgrp = child->pid; - } - /* Don't check for errors. The child may be dead already, - * in which case setpgid returns error code EACCES. */ - setpgid(child->pid, pi->pgrp); - - if (nextin != 0) - close(nextin); - if (nextout != 1) - close(nextout); - - /* If there isn't another process, nextin is garbage - but it doesn't matter */ - nextin = pipefds[0]; - } - return -1; -} - -static int run_list_real(struct pipe *pi) -{ - int rcode=0; - int if_code=0, next_if_code=0; /* need double-buffer to handle elif */ - reserved_style rmode, skip_more_in_this_rmode=RES_XXXX; - for (;pi;pi=pi->next) { - rmode = pi->r_mode; - debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode); - if (rmode == skip_more_in_this_rmode) continue; - skip_more_in_this_rmode = RES_XXXX; - if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code; - if (rmode == RES_THEN && if_code) continue; - if (rmode == RES_ELSE && !if_code) continue; - if (rmode == RES_ELIF && !if_code) continue; - if (pi->num_progs == 0) continue; - rcode = run_pipe_real(pi); - debug_printf("run_pipe_real returned %d\n",rcode); - if (rcode!=-1) { - /* We only ran a builtin: rcode was set by the return value - * of run_pipe_real(), and we don't need to wait for anything. */ - } else if (pi->followup==PIPE_BG) { - /* XXX check bash's behavior with nontrivial pipes */ - /* XXX compute jobid */ - /* XXX what does bash do with attempts to background builtins? */ - insert_bg_job(pi); - rcode = EXIT_SUCCESS; - } else { - if (interactive) { - /* move the new process group into the foreground */ - if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY) - perror_msg("tcsetpgrp-3"); - rcode = checkjobs(pi); - /* move the shell to the foreground */ - if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY) - perror_msg("tcsetpgrp-4"); - } else { - rcode = checkjobs(pi); - } - debug_printf("checkjobs returned %d\n",rcode); - } - last_return_code=rcode; - if ( rmode == RES_IF || rmode == RES_ELIF ) - next_if_code=rcode; /* can be overwritten a number of times */ - if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) || - (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) ) - skip_more_in_this_rmode=rmode; - checkjobs(NULL); - } - return rcode; -} - -/* broken, of course, but OK for testing */ -static char *indenter(int i) -{ - static char blanks[]=" "; - return &blanks[sizeof(blanks)-i-1]; -} - -/* return code is the exit status of the pipe */ -static int free_pipe(struct pipe *pi, int indent) -{ - char **p; - struct child_prog *child; - struct redir_struct *r, *rnext; - int a, i, ret_code=0; - char *ind = indenter(indent); - - if (pi->stopped_progs > 0) - return ret_code; - final_printf("%s run pipe: (pid %d)\n",ind,getpid()); - for (i=0; inum_progs; i++) { - child = &pi->progs[i]; - final_printf("%s command %d:\n",ind,i); - if (child->argv) { - for (a=0,p=child->argv; *p; a++,p++) { - final_printf("%s argv[%d] = %s\n",ind,a,*p); - } - globfree(&child->glob_result); - child->argv=NULL; - } else if (child->group) { - final_printf("%s begin group (subshell:%d)\n",ind, child->subshell); - ret_code = free_pipe_list(child->group,indent+3); - final_printf("%s end group\n",ind); - } else { - final_printf("%s (nil)\n",ind); - } - for (r=child->redirects; r; r=rnext) { - final_printf("%s redirect %d%s", ind, r->fd, redir_table[r->type].descrip); - if (r->dup == -1) { - /* guard against the case >$FOO, where foo is unset or blank */ - if (r->word.gl_pathv) { - final_printf(" %s\n", *r->word.gl_pathv); - globfree(&r->word); - } - } else { - final_printf("&%d\n", r->dup); - } - rnext=r->next; - free(r); - } - child->redirects=NULL; - } - free(pi->progs); /* children are an array, they get freed all at once */ - pi->progs=NULL; - return ret_code; -} - -static int free_pipe_list(struct pipe *head, int indent) -{ - int rcode=0; /* if list has no members */ - struct pipe *pi, *next; - char *ind = indenter(indent); - for (pi=head; pi; pi=next) { - final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode); - rcode = free_pipe(pi, indent); - final_printf("%s pipe followup code %d\n", ind, pi->followup); - next=pi->next; - pi->next=NULL; - free(pi); - } - return rcode; -} - -/* Select which version we will use */ -static int run_list(struct pipe *pi) -{ - int rcode=0; - if (fake_mode==0) { - rcode = run_list_real(pi); - } - /* free_pipe_list has the side effect of clearing memory - * In the long run that function can be merged with run_list_real, - * but doing that now would hobble the debugging effort. */ - free_pipe_list(pi,0); - return rcode; -} - -/* The API for glob is arguably broken. This routine pushes a non-matching - * string into the output structure, removing non-backslashed backslashes. - * If someone can prove me wrong, by performing this function within the - * original glob(3) api, feel free to rewrite this routine into oblivion. - * Return code (0 vs. GLOB_NOSPACE) matches glob(3). - * XXX broken if the last character is '\\', check that before calling. - */ -static int globhack(const char *src, int flags, glob_t *pglob) -{ - int cnt=0, pathc; - const char *s; - char *dest; - for (cnt=1, s=src; s && *s; s++) { - if (*s == '\\') s++; - cnt++; - } - dest = malloc(cnt); - if (!dest) return GLOB_NOSPACE; - if (!(flags & GLOB_APPEND)) { - pglob->gl_pathv=NULL; - pglob->gl_pathc=0; - pglob->gl_offs=0; - pglob->gl_offs=0; - } - pathc = ++pglob->gl_pathc; - pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv)); - if (pglob->gl_pathv == NULL) return GLOB_NOSPACE; - pglob->gl_pathv[pathc-1]=dest; - pglob->gl_pathv[pathc]=NULL; - for (s=src; s && *s; s++, dest++) { - if (*s == '\\') s++; - *dest = *s; - } - *dest='\0'; - return 0; -} - -/* XXX broken if the last character is '\\', check that before calling */ -static int glob_needed(const char *s) -{ - for (; *s; s++) { - if (*s == '\\') s++; - if (strchr("*[?",*s)) return 1; - } - return 0; -} - -#if 0 -static void globprint(glob_t *pglob) -{ - int i; - debug_printf("glob_t at %p:\n", pglob); - debug_printf(" gl_pathc=%d gl_pathv=%p gl_offs=%d gl_flags=%d\n", - pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags); - for (i=0; igl_pathc; i++) - debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i, - pglob->gl_pathv[i], pglob->gl_pathv[i]); -} -#endif - -static int xglob(o_string *dest, int flags, glob_t *pglob) -{ - int gr; - - /* short-circuit for null word */ - /* we can code this better when the debug_printf's are gone */ - if (dest->length == 0) { - if (dest->nonnull) { - /* bash man page calls this an "explicit" null */ - gr = globhack(dest->data, flags, pglob); - debug_printf("globhack returned %d\n",gr); - } else { - return 0; - } - } else if (glob_needed(dest->data)) { - gr = glob(dest->data, flags, NULL, pglob); - debug_printf("glob returned %d\n",gr); - if (gr == GLOB_NOMATCH) { - /* quote removal, or more accurately, backslash removal */ - gr = globhack(dest->data, flags, pglob); - debug_printf("globhack returned %d\n",gr); - } - } else { - gr = globhack(dest->data, flags, pglob); - debug_printf("globhack returned %d\n",gr); - } - if (gr == GLOB_NOSPACE) - error_msg_and_die("out of memory during glob"); - if (gr != 0) { /* GLOB_ABORTED ? */ - error_msg("glob(3) error %d",gr); - } - /* globprint(glob_target); */ - return gr; -} - -/* This is used to get/check local shell variables */ -static char *get_local_var(const char *s) -{ - struct variables *cur; - - if (!s) - return NULL; - for (cur = top_vars; cur; cur=cur->next) - if(strcmp(cur->name, s)==0) - return cur->value; - return NULL; -} - -/* This is used to set local shell variables - flg_export==0 if only local (not exporting) variable - flg_export==1 if "new" exporting environ - flg_export>1 if current startup environ (not call putenv()) */ -static int set_local_var(const char *s, int flg_export) -{ - char *name, *value; - int result=0; - struct variables *cur; - - name=strdup(s); - - /* Assume when we enter this function that we are already in - * NAME=VALUE format. So the first order of business is to - * split 's' on the '=' into 'name' and 'value' */ - value = strchr(name, '='); - if (value==0 && ++value==0) { - free(name); - return -1; - } - *value++ = 0; - - for(cur = top_vars; cur; cur = cur->next) { - if(strcmp(cur->name, name)==0) - break; - } - - if(cur) { - if(strcmp(cur->value, value)==0) { - if(flg_export>0 && cur->flg_export==0) - cur->flg_export=flg_export; - else - result++; - } else { - if(cur->flg_read_only) { - error_msg("%s: readonly variable", name); - result = -1; - } else { - if(flg_export>0 || cur->flg_export>1) - cur->flg_export=1; - free(cur->value); - - cur->value = strdup(value); - } - } - } else { - cur = malloc(sizeof(struct variables)); - if(!cur) { - result = -1; - } else { - cur->name = strdup(name); - if(cur->name == 0) { - free(cur); - result = -1; - } else { - struct variables *bottom = top_vars; - cur->value = strdup(value); - cur->next = 0; - cur->flg_export = flg_export; - cur->flg_read_only = 0; - while(bottom->next) bottom=bottom->next; - bottom->next = cur; - } - } - } - - if(result==0 && cur->flg_export==1) { - *(value-1) = '='; - result = putenv(name); - } else { - free(name); - if(result>0) /* equivalent to previous set */ - result = 0; - } - return result; -} - -static void unset_local_var(const char *name) -{ - struct variables *cur; - - if (name) { - for (cur = top_vars; cur; cur=cur->next) { - if(strcmp(cur->name, name)==0) - break; - } - if(cur!=0) { - struct variables *next = top_vars; - if(cur->flg_read_only) { - error_msg("%s: readonly variable", name); - return; - } else { - if(cur->flg_export) - unsetenv(cur->name); - free(cur->name); - free(cur->value); - while (next->next != cur) - next = next->next; - next->next = cur->next; - } - free(cur); - } - } -} - -static int is_assignment(const char *s) -{ - if (s==NULL || !isalpha(*s)) return 0; - ++s; - while(isalnum(*s) || *s=='_') ++s; - return *s=='='; -} - -/* the src parameter allows us to peek forward to a possible &n syntax - * for file descriptor duplication, e.g., "2>&1". - * Return code is 0 normally, 1 if a syntax error is detected in src. - * Resource errors (in xmalloc) cause the process to exit */ -static int setup_redirect(struct p_context *ctx, int fd, redir_type style, - struct in_str *input) -{ - struct child_prog *child=ctx->child; - struct redir_struct *redir = child->redirects; - struct redir_struct *last_redir=NULL; - - /* Create a new redir_struct and drop it onto the end of the linked list */ - while(redir) { - last_redir=redir; - redir=redir->next; - } - redir = xmalloc(sizeof(struct redir_struct)); - redir->next=NULL; - redir->word.gl_pathv=NULL; - if (last_redir) { - last_redir->next=redir; - } else { - child->redirects=redir; - } - - redir->type=style; - redir->fd= (fd==-1) ? redir_table[style].default_fd : fd ; - - debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip); - - /* Check for a '2>&1' type redirect */ - redir->dup = redirect_dup_num(input); - if (redir->dup == -2) return 1; /* syntax error */ - if (redir->dup != -1) { - /* Erik had a check here that the file descriptor in question - * is legit; I postpone that to "run time" - * A "-" representation of "close me" shows up as a -3 here */ - debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup); - } else { - /* We do _not_ try to open the file that src points to, - * since we need to return and let src be expanded first. - * Set ctx->pending_redirect, so we know what to do at the - * end of the next parsed word. - */ - ctx->pending_redirect = redir; - } - return 0; -} - -struct pipe *new_pipe(void) { - struct pipe *pi; - pi = xmalloc(sizeof(struct pipe)); - pi->num_progs = 0; - pi->progs = NULL; - pi->next = NULL; - pi->followup = 0; /* invalid */ - return pi; -} - -static void initialize_context(struct p_context *ctx) -{ - ctx->pipe=NULL; - ctx->pending_redirect=NULL; - ctx->child=NULL; - ctx->list_head=new_pipe(); - ctx->pipe=ctx->list_head; - ctx->w=RES_NONE; - ctx->stack=NULL; - done_command(ctx); /* creates the memory for working child */ -} - -/* normal return is 0 - * if a reserved word is found, and processed, return 1 - * should handle if, then, elif, else, fi, for, while, until, do, done. - * case, function, and select are obnoxious, save those for later. - */ -int reserved_word(o_string *dest, struct p_context *ctx) -{ - struct reserved_combo { - char *literal; - int code; - long flag; - }; - /* Mostly a list of accepted follow-up reserved words. - * FLAG_END means we are done with the sequence, and are ready - * to turn the compound list into a command. - * FLAG_START means the word must start a new compound list. - */ - static struct reserved_combo reserved_list[] = { - { "if", RES_IF, FLAG_THEN | FLAG_START }, - { "then", RES_THEN, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, - { "elif", RES_ELIF, FLAG_THEN }, - { "else", RES_ELSE, FLAG_FI }, - { "fi", RES_FI, FLAG_END }, - { "for", RES_FOR, FLAG_DO | FLAG_START }, - { "while", RES_WHILE, FLAG_DO | FLAG_START }, - { "until", RES_UNTIL, FLAG_DO | FLAG_START }, - { "do", RES_DO, FLAG_DONE }, - { "done", RES_DONE, FLAG_END } - }; - struct reserved_combo *r; - for (r=reserved_list; -#define NRES sizeof(reserved_list)/sizeof(struct reserved_combo) - rdata, r->literal) == 0) { - debug_printf("found reserved word %s, code %d\n",r->literal,r->code); - if (r->flag & FLAG_START) { - struct p_context *new = xmalloc(sizeof(struct p_context)); - debug_printf("push stack\n"); - *new = *ctx; /* physical copy */ - initialize_context(ctx); - ctx->stack=new; - } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<code))) { - syntax(); - ctx->w = RES_SNTX; - b_reset (dest); - return 1; - } - ctx->w=r->code; - ctx->old_flag = r->flag; - if (ctx->old_flag & FLAG_END) { - struct p_context *old; - debug_printf("pop stack\n"); - old = ctx->stack; - old->child->group = ctx->list_head; - old->child->subshell = 0; - *ctx = *old; /* physical copy */ - free(old); - } - b_reset (dest); - return 1; - } - } - return 0; -} - -/* normal return is 0. - * Syntax or xglob errors return 1. */ -static int done_word(o_string *dest, struct p_context *ctx) -{ - struct child_prog *child=ctx->child; - glob_t *glob_target; - int gr, flags = 0; - - debug_printf("done_word: %s %p\n", dest->data, child); - if (dest->length == 0 && !dest->nonnull) { - debug_printf(" true null, ignored\n"); - return 0; - } - if (ctx->pending_redirect) { - glob_target = &ctx->pending_redirect->word; - } else { - if (child->group) { - syntax(); - return 1; /* syntax error, groups and arglists don't mix */ - } - if (!child->argv) { - debug_printf("checking %s for reserved-ness\n",dest->data); - if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX; - } - glob_target = &child->glob_result; - if (child->argv) flags |= GLOB_APPEND; - } - gr = xglob(dest, flags, glob_target); - if (gr != 0) return 1; - - b_reset(dest); - if (ctx->pending_redirect) { - ctx->pending_redirect=NULL; - if (glob_target->gl_pathc != 1) { - error_msg("ambiguous redirect"); - return 1; - } - } else { - child->argv = glob_target->gl_pathv; - } - return 0; -} - -/* The only possible error here is out of memory, in which case - * xmalloc exits. */ -static int done_command(struct p_context *ctx) -{ - /* The child is really already in the pipe structure, so - * advance the pipe counter and make a new, null child. - * Only real trickiness here is that the uncommitted - * child structure, to which ctx->child points, is not - * counted in pi->num_progs. */ - struct pipe *pi=ctx->pipe; - struct child_prog *prog=ctx->child; - - if (prog && prog->group == NULL - && prog->argv == NULL - && prog->redirects == NULL) { - debug_printf("done_command: skipping null command\n"); - return 0; - } else if (prog) { - pi->num_progs++; - debug_printf("done_command: num_progs incremented to %d\n",pi->num_progs); - } else { - debug_printf("done_command: initializing\n"); - } - pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1)); - - prog = pi->progs + pi->num_progs; - prog->redirects = NULL; - prog->argv = NULL; - prog->is_stopped = 0; - prog->group = NULL; - prog->glob_result.gl_pathv = NULL; - prog->family = pi; - - ctx->child=prog; - /* but ctx->pipe and ctx->list_head remain unchanged */ - return 0; -} - -static int done_pipe(struct p_context *ctx, pipe_style type) -{ - struct pipe *new_p; - done_command(ctx); /* implicit closure of previous command */ - debug_printf("done_pipe, type %d\n", type); - ctx->pipe->followup = type; - ctx->pipe->r_mode = ctx->w; - new_p=new_pipe(); - ctx->pipe->next = new_p; - ctx->pipe = new_p; - ctx->child = NULL; - done_command(ctx); /* set up new pipe to accept commands */ - return 0; -} - -/* peek ahead in the in_str to find out if we have a "&n" construct, - * as in "2>&1", that represents duplicating a file descriptor. - * returns either -2 (syntax error), -1 (no &), or the number found. - */ -static int redirect_dup_num(struct in_str *input) -{ - int ch, d=0, ok=0; - ch = b_peek(input); - if (ch != '&') return -1; - - b_getch(input); /* get the & */ - ch=b_peek(input); - if (ch == '-') { - b_getch(input); - return -3; /* "-" represents "close me" */ - } - while (isdigit(ch)) { - d = d*10+(ch-'0'); - ok=1; - b_getch(input); - ch = b_peek(input); - } - if (ok) return d; - - error_msg("ambiguous redirect"); - return -2; -} - -/* If a redirect is immediately preceded by a number, that number is - * supposed to tell which file descriptor to redirect. This routine - * looks for such preceding numbers. In an ideal world this routine - * needs to handle all the following classes of redirects... - * echo 2>foo # redirects fd 2 to file "foo", nothing passed to echo - * echo 49>foo # redirects fd 49 to file "foo", nothing passed to echo - * echo -2>foo # redirects fd 1 to file "foo", "-2" passed to echo - * echo 49x>foo # redirects fd 1 to file "foo", "49x" passed to echo - * A -1 output from this program means no valid number was found, so the - * caller should use the appropriate default for this redirection. - */ -static int redirect_opt_num(o_string *o) -{ - int num; - - if (o->length==0) return -1; - for(num=0; numlength; num++) { - if (!isdigit(*(o->data+num))) { - return -1; - } - } - /* reuse num (and save an int) */ - num=atoi(o->data); - b_reset(o); - return num; -} - -FILE *generate_stream_from_list(struct pipe *head) -{ - FILE *pf; -#if 1 - int pid, channel[2]; - if (pipe(channel)<0) perror_msg_and_die("pipe"); - pid=fork(); - if (pid<0) { - perror_msg_and_die("fork"); - } else if (pid==0) { - close(channel[0]); - if (channel[1] != 1) { - dup2(channel[1],1); - close(channel[1]); - } -#if 0 -#define SURROGATE "surrogate response" - write(1,SURROGATE,sizeof(SURROGATE)); - _exit(run_list(head)); -#else - _exit(run_list_real(head)); /* leaks memory */ -#endif - } - debug_printf("forked child %d\n",pid); - close(channel[1]); - pf = fdopen(channel[0],"r"); - debug_printf("pipe on FILE *%p\n",pf); -#else - free_pipe_list(head,0); - pf=popen("echo surrogate response","r"); - debug_printf("started fake pipe on FILE *%p\n",pf); -#endif - return pf; -} - -/* this version hacked for testing purposes */ -/* return code is exit status of the process that is run. */ -static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end) -{ - int retcode; - o_string result=NULL_O_STRING; - struct p_context inner; - FILE *p; - struct in_str pipe_str; - initialize_context(&inner); - - /* recursion to generate command */ - retcode = parse_stream(&result, &inner, input, subst_end); - if (retcode != 0) return retcode; /* syntax error or EOF */ - done_word(&result, &inner); - done_pipe(&inner, PIPE_SEQ); - b_free(&result); - - p=generate_stream_from_list(inner.list_head); - if (p==NULL) return 1; - mark_open(fileno(p)); - setup_file_in_str(&pipe_str, p); - - /* now send results of command back into original context */ - retcode = parse_stream(dest, ctx, &pipe_str, '\0'); - /* XXX In case of a syntax error, should we try to kill the child? - * That would be tough to do right, so just read until EOF. */ - if (retcode == 1) { - while (b_getch(&pipe_str)!=EOF) { /* discard */ }; - } - - debug_printf("done reading from pipe, pclose()ing\n"); - /* This is the step that wait()s for the child. Should be pretty - * safe, since we just read an EOF from its stdout. We could try - * to better, by using wait(), and keeping track of background jobs - * at the same time. That would be a lot of work, and contrary - * to the KISS philosophy of this program. */ - mark_closed(fileno(p)); - retcode=pclose(p); - free_pipe_list(inner.list_head,0); - debug_printf("pclosed, retcode=%d\n",retcode); - /* XXX this process fails to trim a single trailing newline */ - return retcode; -} - -static int parse_group(o_string *dest, struct p_context *ctx, - struct in_str *input, int ch) -{ - int rcode, endch=0; - struct p_context sub; - struct child_prog *child = ctx->child; - if (child->argv) { - syntax(); - return 1; /* syntax error, groups and arglists don't mix */ - } - initialize_context(&sub); - switch(ch) { - case '(': endch=')'; child->subshell=1; break; - case '{': endch='}'; break; - default: syntax(); /* really logic error */ - } - rcode=parse_stream(dest,&sub,input,endch); - done_word(dest,&sub); /* finish off the final word in the subcontext */ - done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */ - child->group = sub.list_head; - return rcode; - /* child remains "open", available for possible redirects */ -} - -/* basically useful version until someone wants to get fancier, - * see the bash man page under "Parameter Expansion" */ -static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src) -{ - const char *p=NULL; - if (src->data) { - p = getenv(src->data); - if (!p) - p = get_local_var(src->data); - } - if (p) parse_string(dest, ctx, p); /* recursion */ - b_free(src); -} - -/* return code: 0 for OK, 1 for syntax error */ -static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input) -{ - int i, advance=0; - o_string alt=NULL_O_STRING; - char sep[]=" "; - int ch = input->peek(input); /* first character after the $ */ - debug_printf("handle_dollar: ch=%c\n",ch); - if (isalpha(ch)) { - while(ch=b_peek(input),isalnum(ch) || ch=='_') { - b_getch(input); - b_addchr(&alt,ch); - } - lookup_param(dest, ctx, &alt); - } else if (isdigit(ch)) { - i = ch-'0'; /* XXX is $0 special? */ - if (i 0) b_adduint(dest, last_bg_pid); - advance = 1; - break; - case '?': - b_adduint(dest,last_return_code); - advance = 1; - break; - case '#': - b_adduint(dest,global_argc ? global_argc-1 : 0); - advance = 1; - break; - case '{': - b_getch(input); - /* XXX maybe someone will try to escape the '}' */ - while(ch=b_getch(input),ch!=EOF && ch!='}') { - b_addchr(&alt,ch); - } - if (ch != '}') { - syntax(); - return 1; - } - lookup_param(dest, ctx, &alt); - break; - case '(': - b_getch(input); - process_command_subs(dest, ctx, input, ')'); - break; - case '*': - sep[0]=ifs[0]; - for (i=1; iquote); - } - /* Eat the character if the flag was set. If the compiler - * is smart enough, we could substitute "b_getch(input);" - * for all the "advance = 1;" above, and also end up with - * a nice size-optimized program. Hah! That'll be the day. - */ - if (advance) b_getch(input); - return 0; -} - -int parse_string(o_string *dest, struct p_context *ctx, const char *src) -{ - struct in_str foo; - setup_string_in_str(&foo, src); - return parse_stream(dest, ctx, &foo, '\0'); -} - -/* return code is 0 for normal exit, 1 for syntax error */ -int parse_stream(o_string *dest, struct p_context *ctx, - struct in_str *input, int end_trigger) -{ - unsigned int ch, m; - int redir_fd; - redir_type redir_style; - int next; - - /* Only double-quote state is handled in the state variable dest->quote. - * A single-quote triggers a bypass of the main loop until its mate is - * found. When recursing, quote state is passed in via dest->quote. */ - - debug_printf("parse_stream, end_trigger=%d\n",end_trigger); - while ((ch=b_getch(input))!=EOF) { - m = map[ch]; - next = (ch == '\n') ? 0 : b_peek(input); - debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d\n", - ch,ch,m,dest->quote); - if (m==0 || ((m==1 || m==2) && dest->quote)) { - b_addqchr(dest, ch, dest->quote); - } else { - if (m==2) { /* unquoted IFS */ - done_word(dest, ctx); - /* If we aren't performing a substitution, treat a newline as a - * command separator. */ - if (end_trigger != '\0' && ch=='\n') - done_pipe(ctx,PIPE_SEQ); - } - if (ch == end_trigger && !dest->quote && ctx->w==RES_NONE) { - debug_printf("leaving parse_stream (triggered)\n"); - return 0; - } -#if 0 - if (ch=='\n') { - /* Yahoo! Time to run with it! */ - done_pipe(ctx,PIPE_SEQ); - run_list(ctx->list_head); - initialize_context(ctx); - } -#endif - if (m!=2) switch (ch) { - case '#': - if (dest->length == 0 && !dest->quote) { - while(ch=b_peek(input),ch!=EOF && ch!='\n') { b_getch(input); } - } else { - b_addqchr(dest, ch, dest->quote); - } - break; - case '\\': - if (next == EOF) { - syntax(); - return 1; - } - b_addqchr(dest, '\\', dest->quote); - b_addqchr(dest, b_getch(input), dest->quote); - break; - case '$': - if (handle_dollar(dest, ctx, input)!=0) return 1; - break; - case '\'': - dest->nonnull = 1; - while(ch=b_getch(input),ch!=EOF && ch!='\'') { - b_addchr(dest,ch); - } - if (ch==EOF) { - syntax(); - return 1; - } - break; - case '"': - dest->nonnull = 1; - dest->quote = !dest->quote; - break; - case '`': - process_command_subs(dest, ctx, input, '`'); - break; - case '>': - redir_fd = redirect_opt_num(dest); - done_word(dest, ctx); - redir_style=REDIRECT_OVERWRITE; - if (next == '>') { - redir_style=REDIRECT_APPEND; - b_getch(input); - } else if (next == '(') { - syntax(); /* until we support >(list) Process Substitution */ - return 1; - } - setup_redirect(ctx, redir_fd, redir_style, input); - break; - case '<': - redir_fd = redirect_opt_num(dest); - done_word(dest, ctx); - redir_style=REDIRECT_INPUT; - if (next == '<') { - redir_style=REDIRECT_HEREIS; - b_getch(input); - } else if (next == '>') { - redir_style=REDIRECT_IO; - b_getch(input); - } else if (next == '(') { - syntax(); /* until we support <(list) Process Substitution */ - return 1; - } - setup_redirect(ctx, redir_fd, redir_style, input); - break; - case ';': - done_word(dest, ctx); - done_pipe(ctx,PIPE_SEQ); - break; - case '&': - done_word(dest, ctx); - if (next=='&') { - b_getch(input); - done_pipe(ctx,PIPE_AND); - } else { - done_pipe(ctx,PIPE_BG); - } - break; - case '|': - done_word(dest, ctx); - if (next=='|') { - b_getch(input); - done_pipe(ctx,PIPE_OR); - } else { - /* we could pick up a file descriptor choice here - * with redirect_opt_num(), but bash doesn't do it. - * "echo foo 2| cat" yields "foo 2". */ - done_command(ctx); - } - break; - case '(': - case '{': - if (parse_group(dest, ctx, input, ch)!=0) return 1; - break; - case ')': - case '}': - syntax(); /* Proper use of this character caught by end_trigger */ - return 1; - break; - default: - syntax(); /* this is really an internal logic error */ - return 1; - } - } - } - /* complain if quote? No, maybe we just finished a command substitution - * that was quoted. Example: - * $ echo "`cat foo` plus more" - * and we just got the EOF generated by the subshell that ran "cat foo" - * The only real complaint is if we got an EOF when end_trigger != '\0', - * that is, we were really supposed to get end_trigger, and never got - * one before the EOF. Can't use the standard "syntax error" return code, - * so that parse_stream_outer can distinguish the EOF and exit smoothly. */ - debug_printf("leaving parse_stream (EOF)\n"); - if (end_trigger != '\0') return -1; - return 0; -} - -void mapset(const unsigned char *set, int code) -{ - const unsigned char *s; - for (s=set; *s; s++) map[*s] = code; -} - -void update_ifs_map(void) -{ - /* char *ifs and char map[256] are both globals. */ - ifs = getenv("IFS"); - if (ifs == NULL) ifs=" \t\n"; - /* Precompute a list of 'flow through' behavior so it can be treated - * quickly up front. Computation is necessary because of IFS. - * Special case handling of IFS == " \t\n" is not implemented. - * The map[] array only really needs two bits each, and on most machines - * that would be faster because of the reduced L1 cache footprint. - */ - memset(map,0,sizeof(map)); /* most characters flow through always */ - mapset("\\$'\"`", 3); /* never flow through */ - mapset("<>;&|(){}#", 1); /* flow through if quoted */ - mapset(ifs, 2); /* also flow through if quoted */ -} - -/* most recursion does not come through here, the exeception is - * from builtin_source() */ -int parse_stream_outer(struct in_str *inp) -{ - - struct p_context ctx; - o_string temp=NULL_O_STRING; - int rcode; - do { - initialize_context(&ctx); - update_ifs_map(); - inp->promptmode=1; - rcode = parse_stream(&temp, &ctx, inp, '\n'); - done_word(&temp, &ctx); - done_pipe(&ctx,PIPE_SEQ); - run_list(ctx.list_head); - b_free(&temp); - } while (rcode != -1); /* loop on syntax errors, return on EOF */ - return 0; -} - -static int parse_string_outer(const char *s) -{ - struct in_str input; - setup_string_in_str(&input, s); - return parse_stream_outer(&input); -} - -static int parse_file_outer(FILE *f) -{ - int rcode; - struct in_str input; - setup_file_in_str(&input, f); - rcode = parse_stream_outer(&input); - return rcode; -} - -/* Make sure we have a controlling tty. If we get started under a job - * aware app (like bash for example), make sure we are now in charge so - * we don't fight over who gets the foreground */ -static void setup_job_control() -{ - static pid_t shell_pgrp; - /* Loop until we are in the foreground. */ - while (tcgetpgrp (shell_terminal) != (shell_pgrp = getpgrp ())) - kill (- shell_pgrp, SIGTTIN); - - /* Ignore interactive and job-control signals. */ - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - signal(SIGTERM, SIG_IGN); - signal(SIGTSTP, SIG_IGN); - signal(SIGTTIN, SIG_IGN); - signal(SIGTTOU, SIG_IGN); - signal(SIGCHLD, SIG_IGN); - - /* Put ourselves in our own process group. */ - setsid(); - shell_pgrp = getpid (); - setpgid (shell_pgrp, shell_pgrp); - - /* Grab control of the terminal. */ - tcsetpgrp(shell_terminal, shell_pgrp); -} - -int hush_main(int argc, char **argv) -{ - int opt; - FILE *input; - char **e = environ; - - /* XXX what should these be while sourcing /etc/profile? */ - global_argc = argc; - global_argv = argv; - - /* (re?) initialize globals. Sometimes hush_main() ends up calling - * hush_main(), therefore we cannot rely on the BSS to zero out this - * stuff. Reset these to 0 every time. */ - ifs = NULL; - /* map[] is taken care of with call to update_ifs_map() */ - fake_mode = 0; - interactive = 0; - close_me_head = NULL; - last_bg_pid = 0; - job_list = NULL; - last_jobid = 0; - - /* Initialize some more globals to non-zero values */ - set_cwd(); -#ifdef BB_FEATURE_COMMAND_EDITING - cmdedit_set_initial_prompt(); -#else - PS1 = NULL; -#endif - PS2 = "> "; - - /* initialize our shell local variables with the values - * currently living in the environment */ - if (e) { - for (; *e; e++) - set_local_var(*e, 2); /* without call putenv() */ - } - - last_return_code=EXIT_SUCCESS; - - - if (argv[0] && argv[0][0] == '-') { - debug_printf("\nsourcing /etc/profile\n"); - if ((input = fopen("/etc/profile", "r")) != NULL) { - mark_open(fileno(input)); - parse_file_outer(input); - mark_closed(fileno(input)); - fclose(input); - } - } - input=stdin; - - while ((opt = getopt(argc, argv, "c:xif")) > 0) { - switch (opt) { - case 'c': - { - global_argv = argv+optind; - global_argc = argc-optind; - opt = parse_string_outer(optarg); - goto final_return; - } - break; - case 'i': - interactive++; - break; - case 'f': - fake_mode++; - break; - default: -#ifndef BB_VER - fprintf(stderr, "Usage: sh [FILE]...\n" - " or: sh -c command [args]...\n\n"); - exit(EXIT_FAILURE); -#else - show_usage(); -#endif - } - } - /* A shell is interactive if the `-i' flag was given, or if all of - * the following conditions are met: - * no -c command - * no arguments remaining or the -s flag given - * standard input is a terminal - * standard output is a terminal - * Refer to Posix.2, the description of the `sh' utility. */ - if (argv[optind]==NULL && input==stdin && - isatty(fileno(stdin)) && isatty(fileno(stdout))) { - interactive++; - } - - debug_printf("\ninteractive=%d\n", interactive); - if (interactive) { - /* Looks like they want an interactive shell */ - fprintf(stdout, "\nhush -- the humble shell v0.01 (testing)\n\n"); - setup_job_control(); - } - - if (argv[optind]==NULL) { - opt=parse_file_outer(stdin); - goto final_return; - } - - debug_printf("\nrunning script '%s'\n", argv[optind]); - global_argv = argv+optind; - global_argc = argc-optind; - input = xfopen(argv[optind], "r"); - opt = parse_file_outer(input); - -#ifdef BB_FEATURE_CLEAN_UP - fclose(input); - if (cwd && cwd != unknown) - free((char*)cwd); - { - struct variables *cur, *tmp; - for(cur = top_vars; cur; cur = tmp) { - tmp = cur->next; - if (!cur->flg_read_only) { - free(cur->name); - free(cur->value); - free(cur); - } - } - } -#endif - -final_return: - return(opt?opt:last_return_code); -} diff --git a/busybox/shell/lash.c b/busybox/shell/lash.c deleted file mode 100644 index b3f7cb6a8..000000000 --- a/busybox/shell/lash.c +++ /dev/null @@ -1,1638 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * lash -- the BusyBox Lame-Ass SHell - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * - * Based in part on ladsh.c by Michael K. Johnson and Erik W. Troan, which is - * under the following liberal license: "We have placed this source code in the - * public domain. Use it in any project, free or commercial." - * - * 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 - * - */ - -/* This shell's parsing engine is officially at a dead-end. - * Future work shell work should be done using hush.c - */ - -//For debugging/development on the shell only... -//#define DEBUG_SHELL - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" -#include "cmdedit.h" - -#ifdef BB_LOCALE_SUPPORT -#include -#endif - -#include -#define expand_t glob_t - - -static const int MAX_READ = 128; /* size of input buffer for `read' builtin */ -#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" - - -enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE, - REDIRECT_APPEND -}; - -static const unsigned int DEFAULT_CONTEXT=0x1; -static const unsigned int IF_TRUE_CONTEXT=0x2; -static const unsigned int IF_FALSE_CONTEXT=0x4; -static const unsigned int THEN_EXP_CONTEXT=0x8; -static const unsigned int ELSE_EXP_CONTEXT=0x10; - - -struct jobset { - struct job *head; /* head of list of running jobs */ - struct job *fg; /* current foreground job */ -}; - -struct redir_struct { - enum redir_type type; /* type of redirection */ - int fd; /* file descriptor being redirected */ - char *filename; /* file to redirect fd to */ -}; - -struct child_prog { - pid_t pid; /* 0 if exited */ - char **argv; /* program name and arguments */ - int num_redirects; /* elements in redirection array */ - struct redir_struct *redirects; /* I/O redirects */ - int is_stopped; /* is the program currently running? */ - struct job *family; /* pointer back to the child's parent job */ -}; - -struct job { - int jobid; /* job number */ - int num_progs; /* total number of programs in job */ - int running_progs; /* number of programs running */ - char *text; /* name of job */ - char *cmdbuf; /* buffer various argv's point into */ - pid_t pgrp; /* process group ID for the job */ - struct child_prog *progs; /* array of programs in job */ - struct job *next; /* to track background commands */ - int stopped_progs; /* number of programs alive, but stopped */ - unsigned int job_context; /* bitmask defining current context */ - struct jobset *job_list; -}; - -struct built_in_command { - char *cmd; /* name */ - char *descr; /* description */ - int (*function) (struct child_prog *); /* function ptr */ -}; - -struct close_me { - int fd; - struct close_me *next; -}; - -/* function prototypes for builtins */ -static int builtin_cd(struct child_prog *cmd); -static int builtin_exec(struct child_prog *cmd); -static int builtin_exit(struct child_prog *cmd); -static int builtin_fg_bg(struct child_prog *cmd); -static int builtin_help(struct child_prog *cmd); -static int builtin_jobs(struct child_prog *dummy); -static int builtin_pwd(struct child_prog *dummy); -static int builtin_export(struct child_prog *cmd); -static int builtin_source(struct child_prog *cmd); -static int builtin_unset(struct child_prog *cmd); -static int builtin_read(struct child_prog *cmd); - - -/* function prototypes for shell stuff */ -static void mark_open(int fd); -static void mark_closed(int fd); -static void close_all(void); -static void checkjobs(struct jobset *job_list); -static void remove_job(struct jobset *j_list, struct job *job); -static int get_command(FILE * source, char *command); -static int parse_command(char **command_ptr, struct job *job, int *inbg); -static int run_command(struct job *newjob, int inbg, int outpipe[2]); -static int pseudo_exec(struct child_prog *cmd) __attribute__ ((noreturn)); -static int busy_loop(FILE * input); - - -/* Table of built-in functions (these are non-forking builtins, meaning they - * can change global variables in the parent shell process but they will not - * work with pipes and redirects; 'unset foo | whatever' will not work) */ -static struct built_in_command bltins[] = { - {"bg", "Resume a job in the background", builtin_fg_bg}, - {"cd", "Change working directory", builtin_cd}, - {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec}, - {"exit", "Exit from shell()", builtin_exit}, - {"fg", "Bring job into the foreground", builtin_fg_bg}, - {"jobs", "Lists the active jobs", builtin_jobs}, - {"export", "Set environment variable", builtin_export}, - {"unset", "Unset environment variable", builtin_unset}, - {"read", "Input environment variable", builtin_read}, - {".", "Source-in and run commands in a file", builtin_source}, - /* to do: add ulimit */ - {NULL, NULL, NULL} -}; - -/* Table of forking built-in functions (things that fork cannot change global - * variables in the parent process, such as the current working directory) */ -static struct built_in_command bltins_forking[] = { - {"pwd", "Print current directory", builtin_pwd}, - {"help", "List shell built-in commands", builtin_help}, - {NULL, NULL, NULL} -}; - - -static int shell_context; /* Type prompt trigger (PS1 or PS2) */ - - -/* Globals that are static to this file */ -static const char *cwd; -static char *local_pending_command = NULL; -static struct jobset job_list = { NULL, NULL }; -static int argc; -static char **argv; -static struct close_me *close_me_head; -static int last_return_code; -static int last_bg_pid; -static unsigned int last_jobid; -static int shell_terminal; -static pid_t shell_pgrp; -static char *PS1; -static char *PS2 = "> "; - - -#ifdef DEBUG_SHELL -static inline void debug_printf(const char *format, ...) -{ - va_list args; - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); -} -#else -static inline void debug_printf(const char *format, ...) { } -#endif - -/* - Most builtins need access to the struct child_prog that has - their arguments, previously coded as cmd->progs[0]. That coding - can exhibit a bug, if the builtin is not the first command in - a pipeline: "echo foo | exec sort" will attempt to exec foo. - -builtin previous use notes ------- ----------------- --------- -cd cmd->progs[0] -exec cmd->progs[0] squashed bug: didn't look for applets or forking builtins -exit cmd->progs[0] -fg_bg cmd->progs[0], job_list->head, job_list->fg -help 0 -jobs job_list->head -pwd 0 -export cmd->progs[0] -source cmd->progs[0] -unset cmd->progs[0] -read cmd->progs[0] - -I added "struct job *family;" to struct child_prog, -and switched API to builtin_foo(struct child_prog *child); -So cmd->text becomes child->family->text - cmd->job_context becomes child->family->job_context - cmd->progs[0] becomes *child - job_list becomes child->family->job_list - */ - -/* built-in 'cd ' handler */ -static int builtin_cd(struct child_prog *child) -{ - char *newdir; - - if (child->argv[1] == NULL) - newdir = getenv("HOME"); - else - newdir = child->argv[1]; - if (chdir(newdir)) { - printf("cd: %s: %m\n", newdir); - return EXIT_FAILURE; - } - cwd = xgetcwd((char *)cwd); - if (!cwd) - cwd = unknown; - return EXIT_SUCCESS; -} - -/* built-in 'exec' handler */ -static int builtin_exec(struct child_prog *child) -{ - if (child->argv[1] == NULL) - return EXIT_SUCCESS; /* Really? */ - child->argv++; - close_all(); - pseudo_exec(child); - /* never returns */ -} - -/* built-in 'exit' handler */ -static int builtin_exit(struct child_prog *child) -{ - if (child->argv[1] == NULL) - exit(EXIT_SUCCESS); - - exit (atoi(child->argv[1])); -} - -/* built-in 'fg' and 'bg' handler */ -static int builtin_fg_bg(struct child_prog *child) -{ - int i, jobnum; - struct job *job=NULL; - - /* If they gave us no args, assume they want the last backgrounded task */ - if (!child->argv[1]) { - for (job = child->family->job_list->head; job; job = job->next) { - if (job->jobid == last_jobid) { - break; - } - } - if (!job) { - error_msg("%s: no current job", child->argv[0]); - return EXIT_FAILURE; - } - } else { - if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { - error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]); - return EXIT_FAILURE; - } - for (job = child->family->job_list->head; job; job = job->next) { - if (job->jobid == jobnum) { - break; - } - } - if (!job) { - error_msg("%s: %d: no such job", child->argv[0], jobnum); - return EXIT_FAILURE; - } - } - - if (*child->argv[0] == 'f') { - /* Put the job into the foreground. */ - tcsetpgrp(shell_terminal, job->pgrp); - - child->family->job_list->fg = job; - } - - /* Restart the processes in the job */ - for (i = 0; i < job->num_progs; i++) - job->progs[i].is_stopped = 0; - - job->stopped_progs = 0; - - if ( (i=kill(- job->pgrp, SIGCONT)) < 0) { - if (i == ESRCH) { - remove_job(&job_list, job); - } else { - perror_msg("kill (SIGCONT)"); - } - } - - return EXIT_SUCCESS; -} - -/* built-in 'help' handler */ -static int builtin_help(struct child_prog *dummy) -{ - struct built_in_command *x; - - printf("\nBuilt-in commands:\n"); - printf("-------------------\n"); - for (x = bltins; x->cmd; x++) { - if (x->descr==NULL) - continue; - printf("%s\t%s\n", x->cmd, x->descr); - } - for (x = bltins_forking; x->cmd; x++) { - if (x->descr==NULL) - continue; - printf("%s\t%s\n", x->cmd, x->descr); - } - printf("\n\n"); - return EXIT_SUCCESS; -} - -/* built-in 'jobs' handler */ -static int builtin_jobs(struct child_prog *child) -{ - struct job *job; - char *status_string; - - for (job = child->family->job_list->head; job; job = job->next) { - if (job->running_progs == job->stopped_progs) - status_string = "Stopped"; - else - status_string = "Running"; - - printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text); - } - return EXIT_SUCCESS; -} - - -/* built-in 'pwd' handler */ -static int builtin_pwd(struct child_prog *dummy) -{ - cwd = xgetcwd((char *)cwd); - if (!cwd) - cwd = unknown; - puts(cwd); - return EXIT_SUCCESS; -} - -/* built-in 'export VAR=value' handler */ -static int builtin_export(struct child_prog *child) -{ - int res; - char *v = child->argv[1]; - - if (v == NULL) { - char **e; - for (e = environ; *e; e++) { - puts(*e); - } - return 0; - } - res = putenv(v); - if (res) - fprintf(stderr, "export: %m\n"); -#ifdef BB_FEATURE_SH_FANCY_PROMPT - if (strncmp(v, "PS1=", 4)==0) - PS1 = getenv("PS1"); -#endif - -#ifdef BB_LOCALE_SUPPORT - if(strncmp(v, "LC_ALL=", 7)==0) - setlocale(LC_ALL, getenv("LC_ALL")); - if(strncmp(v, "LC_CTYPE=", 9)==0) - setlocale(LC_CTYPE, getenv("LC_CTYPE")); -#endif - - return (res); -} - -/* built-in 'read VAR' handler */ -static int builtin_read(struct child_prog *child) -{ - int res = 0, len, newlen; - char *s; - char string[MAX_READ]; - - if (child->argv[1]) { - /* argument (VAR) given: put "VAR=" into buffer */ - strcpy(string, child->argv[1]); - len = strlen(string); - string[len++] = '='; - string[len] = '\0'; - fgets(&string[len], sizeof(string) - len, stdin); /* read string */ - newlen = strlen(string); - if(newlen > len) - string[--newlen] = '\0'; /* chomp trailing newline */ - /* - ** string should now contain "VAR=" - ** copy it (putenv() won't do that, so we must make sure - ** the string resides in a static buffer!) - */ - res = -1; - if((s = strdup(string))) - res = putenv(s); - if (res) - fprintf(stderr, "read: %m\n"); - } - else - fgets(string, sizeof(string), stdin); - - return (res); -} - -/* Built-in '.' handler (read-in and execute commands from file) */ -static int builtin_source(struct child_prog *child) -{ - FILE *input; - int status; - int fd; - - if (child->argv[1] == NULL) - return EXIT_FAILURE; - - input = fopen(child->argv[1], "r"); - if (!input) { - printf( "Couldn't open file '%s'\n", child->argv[1]); - return EXIT_FAILURE; - } - - fd=fileno(input); - mark_open(fd); - /* Now run the file */ - status = busy_loop(input); - fclose(input); - mark_closed(fd); - return (status); -} - -/* built-in 'unset VAR' handler */ -static int builtin_unset(struct child_prog *child) -{ - if (child->argv[1] == NULL) { - printf( "unset: parameter required.\n"); - return EXIT_FAILURE; - } - unsetenv(child->argv[1]); - return EXIT_SUCCESS; -} - -static void mark_open(int fd) -{ - struct close_me *new = xmalloc(sizeof(struct close_me)); - new->fd = fd; - new->next = close_me_head; - close_me_head = new; -} - -static void mark_closed(int fd) -{ - struct close_me *tmp; - if (close_me_head == NULL || close_me_head->fd != fd) - error_msg_and_die("corrupt close_me"); - tmp = close_me_head; - close_me_head = close_me_head->next; - free(tmp); -} - -static void close_all() -{ - struct close_me *c, *tmp; - for (c=close_me_head; c; c=tmp) { - close(c->fd); - tmp=c->next; - free(c); - } - close_me_head = NULL; -} - - -/* free up all memory from a job */ -static void free_job(struct job *cmd) -{ - int i; - struct jobset *keep; - - for (i = 0; i < cmd->num_progs; i++) { - free(cmd->progs[i].argv); - if (cmd->progs[i].redirects) - free(cmd->progs[i].redirects); - } - if (cmd->progs) - free(cmd->progs); - if (cmd->text) - free(cmd->text); - if (cmd->cmdbuf) - free(cmd->cmdbuf); - keep = cmd->job_list; - memset(cmd, 0, sizeof(struct job)); - cmd->job_list = keep; -} - -/* remove a job from a jobset */ -static void remove_job(struct jobset *j_list, struct job *job) -{ - struct job *prevjob; - - free_job(job); - if (job == j_list->head) { - j_list->head = job->next; - } else { - prevjob = j_list->head; - while (prevjob->next != job) - prevjob = prevjob->next; - prevjob->next = job->next; - } - - if (j_list->head) - last_jobid = j_list->head->jobid; - else - last_jobid = 0; - - free(job); -} - -/* Checks to see if any background processes have exited -- if they - have, figure out why and see if a job has completed */ -static void checkjobs(struct jobset *j_list) -{ - struct job *job; - pid_t childpid; - int status; - int prognum = 0; - - while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { - for (job = j_list->head; job; job = job->next) { - prognum = 0; - while (prognum < job->num_progs && - job->progs[prognum].pid != childpid) prognum++; - if (prognum < job->num_progs) - break; - } - - /* This happens on backticked commands */ - if(job==NULL) - return; - - if (WIFEXITED(status) || WIFSIGNALED(status)) { - /* child exited */ - job->running_progs--; - job->progs[prognum].pid = 0; - - if (!job->running_progs) { - printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text); - last_jobid=0; - remove_job(j_list, job); - } - } else { - /* child stopped */ - job->stopped_progs++; - job->progs[prognum].is_stopped = 1; - -#if 0 - /* Printing this stuff is a pain, since it tends to - * overwrite the prompt an inconveinient moments. So - * don't do that. */ - if (job->stopped_progs == job->num_progs) { - printf(JOB_STATUS_FORMAT, job->jobid, "Stopped", - job->text); - } -#endif - } - } - - if (childpid == -1 && errno != ECHILD) - perror_msg("waitpid"); -} - -/* squirrel != NULL means we squirrel away copies of stdin, stdout, - * and stderr if they are redirected. */ -static int setup_redirects(struct child_prog *prog, int squirrel[]) -{ - int i; - int openfd; - int mode = O_RDONLY; - struct redir_struct *redir = prog->redirects; - - for (i = 0; i < prog->num_redirects; i++, redir++) { - switch (redir->type) { - case REDIRECT_INPUT: - mode = O_RDONLY; - break; - case REDIRECT_OVERWRITE: - mode = O_WRONLY | O_CREAT | O_TRUNC; - break; - case REDIRECT_APPEND: - mode = O_WRONLY | O_CREAT | O_APPEND; - break; - } - - openfd = open(redir->filename, mode, 0666); - if (openfd < 0) { - /* this could get lost if stderr has been redirected, but - bash and ash both lose it as well (though zsh doesn't!) */ - perror_msg("error opening %s", redir->filename); - return 1; - } - - if (openfd != redir->fd) { - if (squirrel && redir->fd < 3) { - squirrel[redir->fd] = dup(redir->fd); - } - dup2(openfd, redir->fd); - close(openfd); - } - } - - return 0; -} - -static void restore_redirects(int squirrel[]) -{ - int i, fd; - for (i=0; i<3; i++) { - fd = squirrel[i]; - if (fd != -1) { - /* No error checking. I sure wouldn't know what - * to do with an error if I found one! */ - dup2(fd, i); - close(fd); - } - } -} - -static inline void cmdedit_set_initial_prompt(void) -{ -#ifndef BB_FEATURE_SH_FANCY_PROMPT - PS1 = NULL; -#else - PS1 = getenv("PS1"); - if(PS1==0) - PS1 = "\\w \\$ "; -#endif -} - -static inline void setup_prompt_string(char **prompt_str) -{ -#ifndef BB_FEATURE_SH_FANCY_PROMPT - /* Set up the prompt */ - if (shell_context == 0) { - if (PS1) - free(PS1); - PS1=xmalloc(strlen(cwd)+4); - sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); - *prompt_str = PS1; - } else { - *prompt_str = PS2; - } -#else - *prompt_str = (shell_context==0)? PS1 : PS2; -#endif -} - -static int get_command(FILE * source, char *command) -{ - char *prompt_str; - - if (source == NULL) { - if (local_pending_command) { - /* a command specified (-c option): return it & mark it done */ - strcpy(command, local_pending_command); - free(local_pending_command); - local_pending_command = NULL; - return 0; - } - return 1; - } - - if (source == stdin) { - setup_prompt_string(&prompt_str); - -#ifdef BB_FEATURE_COMMAND_EDITING - /* - ** enable command line editing only while a command line - ** is actually being read; otherwise, we'll end up bequeathing - ** atexit() handlers and other unwanted stuff to our - ** child processes (rob@sysgo.de) - */ - cmdedit_read_input(prompt_str, command); - return 0; -#else - fputs(prompt_str, stdout); -#endif - } - - if (!fgets(command, BUFSIZ - 2, source)) { - if (source == stdin) - printf("\n"); - return 1; - } - - return 0; -} - -static char* itoa(register int i) -{ - static char a[7]; /* Max 7 ints */ - register char *b = a + sizeof(a) - 1; - int sign = (i < 0); - - if (sign) - i = -i; - *b = 0; - do - { - *--b = '0' + (i % 10); - i /= 10; - } - while (i); - if (sign) - *--b = '-'; - return b; -} - -char * strsep_space( char *string, int * ix) -{ - char *token, *begin; - - begin = string; - - /* Short circuit the trivial case */ - if ( !string || ! string[*ix]) - return NULL; - - /* Find the end of the token. */ - while( string && string[*ix] && !isspace(string[*ix]) ) { - (*ix)++; - } - - /* Find the end of any whitespace trailing behind - * the token and let that be part of the token */ - while( string && string[*ix] && isspace(string[*ix]) ) { - (*ix)++; - } - - if (! string && *ix==0) { - /* Nothing useful was found */ - return NULL; - } - - token = xmalloc(*ix+1); - token[*ix] = '\0'; - strncpy(token, string, *ix); - - return token; -} - -static int expand_arguments(char *command) -{ - int total_length=0, length, i, retval, ix = 0; - expand_t expand_result; - char *tmpcmd, *cmd, *cmd_copy; - char *src, *dst, *var; - const char *out_of_space = "out of space during expansion"; - int flags = GLOB_NOCHECK -#ifdef GLOB_BRACE - | GLOB_BRACE -#endif -#ifdef GLOB_TILDE - | GLOB_TILDE -#endif - ; - - /* get rid of the terminating \n */ - chomp(command); - - /* Fix up escape sequences to be the Real Thing(tm) */ - while( command && command[ix]) { - if (command[ix] == '\\') { - const char *tmp = command+ix+1; - command[ix] = process_escape_sequence( &tmp ); - memmove(command+ix + 1, tmp, strlen(tmp)+1); - } - ix++; - } - /* Use glob and then fixup environment variables and such */ - - /* It turns out that glob is very stupid. We have to feed it one word at a - * time since it can't cope with a full string. Here we convert command - * (char*) into cmd (char**, one word per string) */ - - /* We need a clean copy, so strsep can mess up the copy while - * we write stuff into the original (in a minute) */ - cmd = cmd_copy = strdup(command); - *command = '\0'; - for (ix = 0, tmpcmd = cmd; - (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) { - if (*tmpcmd == '\0') - break; - /* we need to trim() the result for glob! */ - trim(tmpcmd); - retval = glob(tmpcmd, flags, NULL, &expand_result); - free(tmpcmd); /* Free mem allocated by strsep_space */ - if (retval == GLOB_NOSPACE) { - /* Mem may have been allocated... */ - globfree (&expand_result); - error_msg(out_of_space); - return FALSE; - } else if (retval != 0) { - /* Some other error. GLOB_NOMATCH shouldn't - * happen because of the GLOB_NOCHECK flag in - * the glob call. */ - error_msg("syntax error"); - return FALSE; - } else { - /* Convert from char** (one word per string) to a simple char*, - * but don't overflow command which is BUFSIZ in length */ - for (i=0; i < expand_result.gl_pathc; i++) { - length=strlen(expand_result.gl_pathv[i]); - if (total_length+length+1 >= BUFSIZ) { - error_msg(out_of_space); - return FALSE; - } - strcat(command+total_length, " "); - total_length+=1; - strcat(command+total_length, expand_result.gl_pathv[i]); - total_length+=length; - } - globfree (&expand_result); - } - } - free(cmd_copy); - trim(command); - - /* Now do the shell variable substitutions which - * wordexp can't do for us, namely $? and $! */ - src = command; - while((dst = strchr(src,'$')) != NULL){ - var = NULL; - switch(*(dst+1)) { - case '?': - var = itoa(last_return_code); - break; - case '!': - if (last_bg_pid==-1) - *(var)='\0'; - else - var = itoa(last_bg_pid); - break; - /* Everything else like $$, $#, $[0-9], etc. should all be - * expanded by wordexp(), so we can in theory skip that stuff - * here, but just to be on the safe side (i.e., since uClibc - * wordexp doesn't do this stuff yet), lets leave it in for - * now. */ - case '$': - var = itoa(getpid()); - break; - case '#': - var = itoa(argc-1); - break; - case '0':case '1':case '2':case '3':case '4': - case '5':case '6':case '7':case '8':case '9': - { - int ixx=*(dst + 1)-48; - if (ixx >= argc) { - var='\0'; - } else { - var = argv[ixx]; - } - } - break; - - } - if (var) { - /* a single character construction was found, and - * already handled in the case statement */ - src=dst+2; - } else { - /* Looks like an environment variable */ - char delim_hold; - int num_skip_chars=0; - int dstlen = strlen(dst); - /* Is this a ${foo} type variable? */ - if (dstlen >=2 && *(dst+1) == '{') { - src=strchr(dst+1, '}'); - num_skip_chars=1; - } else { - src=dst+1; - while(isalnum(*src) || *src=='_') src++; - } - if (src == NULL) { - src = dst+dstlen; - } - delim_hold=*src; - *src='\0'; /* temporary */ - var = getenv(dst + 1 + num_skip_chars); - *src=delim_hold; - src += num_skip_chars; - } - if (var == NULL) { - /* Seems we got an un-expandable variable. So delete it. */ - var = ""; - } - { - int subst_len = strlen(var); - int trail_len = strlen(src); - if (dst+subst_len+trail_len >= command+BUFSIZ) { - error_msg(out_of_space); - return FALSE; - } - /* Move stuff to the end of the string to accommodate - * filling the created gap with the new stuff */ - memmove(dst+subst_len, src, trail_len+1); - /* Now copy in the new stuff */ - memcpy(dst, var, subst_len); - src = dst+subst_len; - } - } - - return TRUE; -} - -/* Return cmd->num_progs as 0 if no command is present (e.g. an empty - line). If a valid command is found, command_ptr is set to point to - the beginning of the next command (if the original command had more - then one job associated with it) or NULL if no more commands are - present. */ -static int parse_command(char **command_ptr, struct job *job, int *inbg) -{ - char *command; - char *return_command = NULL; - char *src, *buf, *chptr; - int argc_l = 0; - int done = 0; - int argv_alloced; - int i, saw_quote = 0; - char quote = '\0'; - int count; - struct child_prog *prog; - - /* skip leading white space */ - while (**command_ptr && isspace(**command_ptr)) - (*command_ptr)++; - - /* this handles empty lines or leading '#' characters */ - if (!**command_ptr || (**command_ptr == '#')) { - job->num_progs=0; - return 0; - } - - *inbg = 0; - job->num_progs = 1; - job->progs = xmalloc(sizeof(*job->progs)); - - /* We set the argv elements to point inside of this string. The - memory is freed by free_job(). Allocate twice the original - length in case we need to quote every single character. - - Getting clean memory relieves us of the task of NULL - terminating things and makes the rest of this look a bit - cleaner (though it is, admittedly, a tad less efficient) */ - job->cmdbuf = command = xcalloc(2*strlen(*command_ptr) + 1, sizeof(char)); - job->text = NULL; - - prog = job->progs; - prog->num_redirects = 0; - prog->redirects = NULL; - prog->is_stopped = 0; - prog->family = job; - - argv_alloced = 5; - prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced); - prog->argv[0] = job->cmdbuf; - - buf = command; - src = *command_ptr; - while (*src && !done) { - if (quote == *src) { - quote = '\0'; - } else if (quote) { - if (*src == '\\') { - src++; - if (!*src) { - error_msg("character expected after \\"); - free_job(job); - return 1; - } - - /* in shell, "\'" should yield \' */ - if (*src != quote) { - *buf++ = '\\'; - *buf++ = '\\'; - } - } else if (*src == '*' || *src == '?' || *src == '[' || - *src == ']') *buf++ = '\\'; - *buf++ = *src; - } else if (isspace(*src)) { - if (*prog->argv[argc_l] || saw_quote) { - buf++, argc_l++; - /* +1 here leaves room for the NULL which ends argv */ - if ((argc_l + 1) == argv_alloced) { - argv_alloced += 5; - prog->argv = xrealloc(prog->argv, - sizeof(*prog->argv) * - argv_alloced); - } - prog->argv[argc_l] = buf; - saw_quote = 0; - } - } else - switch (*src) { - case '"': - case '\'': - quote = *src; - saw_quote = 1; - break; - - case '#': /* comment */ - if (*(src-1)== '$') - *buf++ = *src; - else - done = 1; - break; - - case '>': /* redirects */ - case '<': - i = prog->num_redirects++; - prog->redirects = xrealloc(prog->redirects, - sizeof(*prog->redirects) * - (i + 1)); - - prog->redirects[i].fd = -1; - if (buf != prog->argv[argc_l]) { - /* the stuff before this character may be the file number - being redirected */ - prog->redirects[i].fd = - strtol(prog->argv[argc_l], &chptr, 10); - - if (*chptr && *prog->argv[argc_l]) { - buf++, argc_l++; - prog->argv[argc_l] = buf; - } - } - - if (prog->redirects[i].fd == -1) { - if (*src == '>') - prog->redirects[i].fd = 1; - else - prog->redirects[i].fd = 0; - } - - if (*src++ == '>') { - if (*src == '>') - prog->redirects[i].type = - REDIRECT_APPEND, src++; - else - prog->redirects[i].type = REDIRECT_OVERWRITE; - } else { - prog->redirects[i].type = REDIRECT_INPUT; - } - - /* This isn't POSIX sh compliant. Oh well. */ - chptr = src; - while (isspace(*chptr)) - chptr++; - - if (!*chptr) { - error_msg("file name expected after %c", *(src-1)); - free_job(job); - job->num_progs=0; - return 1; - } - - prog->redirects[i].filename = buf; - while (*chptr && !isspace(*chptr)) - *buf++ = *chptr++; - - src = chptr - 1; /* we src++ later */ - prog->argv[argc_l] = ++buf; - break; - - case '|': /* pipe */ - /* finish this command */ - if (*prog->argv[argc_l] || saw_quote) - argc_l++; - if (!argc_l) { - error_msg("empty command in pipe"); - free_job(job); - job->num_progs=0; - return 1; - } - prog->argv[argc_l] = NULL; - - /* and start the next */ - job->num_progs++; - job->progs = xrealloc(job->progs, - sizeof(*job->progs) * job->num_progs); - prog = job->progs + (job->num_progs - 1); - prog->num_redirects = 0; - prog->redirects = NULL; - prog->is_stopped = 0; - prog->family = job; - argc_l = 0; - - argv_alloced = 5; - prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced); - prog->argv[0] = ++buf; - - src++; - while (*src && isspace(*src)) - src++; - - if (!*src) { - error_msg("empty command in pipe"); - free_job(job); - job->num_progs=0; - return 1; - } - src--; /* we'll ++ it at the end of the loop */ - - break; - - case '&': /* background */ - *inbg = 1; - case ';': /* multiple commands */ - done = 1; - return_command = *command_ptr + (src - *command_ptr) + 1; - break; - - case '\\': - src++; - if (!*src) { - error_msg("character expected after \\"); - free_job(job); - return 1; - } - if (*src == '*' || *src == '[' || *src == ']' - || *src == '?') *buf++ = '\\'; - /* fallthrough */ - default: - *buf++ = *src; - } - - src++; - } - - if (*prog->argv[argc_l] || saw_quote) { - argc_l++; - } - if (!argc_l) { - free_job(job); - return 0; - } - prog->argv[argc_l] = NULL; - - if (!return_command) { - job->text = xmalloc(strlen(*command_ptr) + 1); - strcpy(job->text, *command_ptr); - } else { - /* This leaves any trailing spaces, which is a bit sloppy */ - count = return_command - *command_ptr; - job->text = xmalloc(count + 1); - strncpy(job->text, *command_ptr, count); - job->text[count] = '\0'; - } - - *command_ptr = return_command; - - return 0; -} - -/* Run the child_prog, no matter what kind of command it uses. - */ -static int pseudo_exec(struct child_prog *child) -{ - struct built_in_command *x; -#ifdef BB_FEATURE_SH_STANDALONE_SHELL - char *name; -#endif - - /* Check if the command matches any of the non-forking builtins. - * Depending on context, this might be redundant. But it's - * easier to waste a few CPU cycles than it is to figure out - * if this is one of those cases. - */ - for (x = bltins; x->cmd; x++) { - if (strcmp(child->argv[0], x->cmd) == 0 ) { - exit(x->function(child)); - } - } - - /* Check if the command matches any of the forking builtins. */ - for (x = bltins_forking; x->cmd; x++) { - if (strcmp(child->argv[0], x->cmd) == 0) { - applet_name=x->cmd; - exit (x->function(child)); - } - } -#ifdef BB_FEATURE_SH_STANDALONE_SHELL - /* Check if the command matches any busybox internal - * commands ("applets") here. Following discussions from - * November 2000 on busybox@opensource.lineo.com, don't use - * get_last_path_component(). This way explicit (with - * slashes) filenames will never be interpreted as an - * applet, just like with builtins. This way the user can - * override an applet with an explicit filename reference. - * The only downside to this change is that an explicit - * /bin/foo invocation will fork and exec /bin/foo, even if - * /bin/foo is a symlink to busybox. - */ - name = child->argv[0]; - -#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN - /* If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then - * if you run /bin/cat, it will use BusyBox cat even if - * /bin/cat exists on the filesystem and is _not_ busybox. - * Some systems want this, others do not. Choose wisely. :-) - */ - name = get_last_path_component(name); -#endif - - { - char** argv_l=child->argv; - int argc_l; - for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++); - optind = 1; - run_applet_by_name(name, argc_l, child->argv); - } -#endif - - execvp(child->argv[0], child->argv); - perror_msg_and_die("%s", child->argv[0]); -} - -static void insert_job(struct job *newjob, int inbg) -{ - struct job *thejob; - struct jobset *j_list=newjob->job_list; - - /* find the ID for thejob to use */ - newjob->jobid = 1; - for (thejob = j_list->head; thejob; thejob = thejob->next) - if (thejob->jobid >= newjob->jobid) - newjob->jobid = thejob->jobid + 1; - - /* add thejob to the list of running jobs */ - if (!j_list->head) { - thejob = j_list->head = xmalloc(sizeof(*thejob)); - } else { - for (thejob = j_list->head; thejob->next; thejob = thejob->next) /* nothing */; - thejob->next = xmalloc(sizeof(*thejob)); - thejob = thejob->next; - } - - *thejob = *newjob; /* physically copy the struct job */ - thejob->next = NULL; - thejob->running_progs = thejob->num_progs; - thejob->stopped_progs = 0; - - if (inbg) { - /* we don't wait for background thejobs to return -- append it - to the list of backgrounded thejobs and leave it alone */ - printf("[%d] %d\n", thejob->jobid, - newjob->progs[newjob->num_progs - 1].pid); - last_jobid = newjob->jobid; - last_bg_pid=newjob->progs[newjob->num_progs - 1].pid; - } else { - newjob->job_list->fg = thejob; - - /* move the new process group into the foreground */ - /* suppress messages when run from /linuxrc mag@sysgo.de */ - if (tcsetpgrp(shell_terminal, newjob->pgrp) && errno != ENOTTY) - perror_msg("tcsetpgrp"); - } -} - -static int run_command(struct job *newjob, int inbg, int outpipe[2]) -{ - /* struct job *thejob; */ - int i; - int nextin, nextout; - int pipefds[2]; /* pipefd[0] is for reading */ - struct built_in_command *x; - struct child_prog *child; - - nextin = 0, nextout = 1; - for (i = 0; i < newjob->num_progs; i++) { - child = & (newjob->progs[i]); - - if ((i + 1) < newjob->num_progs) { - if (pipe(pipefds)<0) perror_msg_and_die("pipe"); - nextout = pipefds[1]; - } else { - if (outpipe[1]!=-1) { - nextout = outpipe[1]; - } else { - nextout = 1; - } - } - - - /* Check if the command matches any non-forking builtins, - * but only if this is a simple command. - * Non-forking builtins within pipes have to fork anyway, - * and are handled in pseudo_exec. "echo foo | read bar" - * is doomed to failure, and doesn't work on bash, either. - */ - if (newjob->num_progs == 1) { - for (x = bltins; x->cmd; x++) { - if (strcmp(child->argv[0], x->cmd) == 0 ) { - int squirrel[] = {-1, -1, -1}; - int rcode; - setup_redirects(child, squirrel); - rcode = x->function(child); - restore_redirects(squirrel); - return rcode; - } - } - } - - if (!(child->pid = fork())) { - /* Set the handling for job control signals back to the default. */ - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGTSTP, SIG_DFL); - signal(SIGTTIN, SIG_DFL); - signal(SIGTTOU, SIG_DFL); - signal(SIGCHLD, SIG_DFL); - - close_all(); - - if (outpipe[1]!=-1) { - close(outpipe[0]); - } - if (nextin != 0) { - dup2(nextin, 0); - close(nextin); - } - - if (nextout != 1) { - dup2(nextout, 1); - dup2(nextout, 2); /* Really? */ - close(nextout); - close(pipefds[0]); - } - - /* explicit redirects override pipes */ - setup_redirects(child,NULL); - - pseudo_exec(child); - } - if (outpipe[1]!=-1) { - close(outpipe[1]); - } - - /* put our child in the process group whose leader is the - first process in this pipe */ - setpgid(child->pid, newjob->progs[0].pid); - if (nextin != 0) - close(nextin); - if (nextout != 1) - close(nextout); - - /* If there isn't another process, nextin is garbage - but it doesn't matter */ - nextin = pipefds[0]; - } - - newjob->pgrp = newjob->progs[0].pid; - - insert_job(newjob, inbg); - - return 0; -} - -static int busy_loop(FILE * input) -{ - char *command; - char *next_command = NULL; - struct job newjob; - pid_t parent_pgrp; - int i; - int inbg; - int status; - newjob.job_list = &job_list; - newjob.job_context = DEFAULT_CONTEXT; - - /* save current owner of TTY so we can restore it on exit */ - parent_pgrp = tcgetpgrp(shell_terminal); - - command = (char *) xcalloc(BUFSIZ, sizeof(char)); - - while (1) { - if (!job_list.fg) { - /* no job is in the foreground */ - - /* see if any background processes have exited */ - checkjobs(&job_list); - - if (!next_command) { - if (get_command(input, command)) - break; - next_command = command; - } - - if (expand_arguments(next_command) == FALSE) { - free(command); - command = (char *) xcalloc(BUFSIZ, sizeof(char)); - next_command = NULL; - continue; - } - - if (!parse_command(&next_command, &newjob, &inbg) && - newjob.num_progs) { - int pipefds[2] = {-1,-1}; - debug_printf( "job=%p fed to run_command by busy_loop()'\n", - &newjob); - run_command(&newjob, inbg, pipefds); - } - else { - free(command); - command = (char *) xcalloc(BUFSIZ, sizeof(char)); - next_command = NULL; - } - } else { - /* a job is running in the foreground; wait for it */ - i = 0; - while (!job_list.fg->progs[i].pid || - job_list.fg->progs[i].is_stopped == 1) i++; - - if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED)<0) - perror_msg_and_die("waitpid(%d)",job_list.fg->progs[i].pid); - - if (WIFEXITED(status) || WIFSIGNALED(status)) { - /* the child exited */ - job_list.fg->running_progs--; - job_list.fg->progs[i].pid = 0; - - last_return_code=WEXITSTATUS(status); - - if (!job_list.fg->running_progs) { - /* child exited */ - remove_job(&job_list, job_list.fg); - job_list.fg = NULL; - } - } else { - /* the child was stopped */ - job_list.fg->stopped_progs++; - job_list.fg->progs[i].is_stopped = 1; - - if (job_list.fg->stopped_progs == job_list.fg->running_progs) { - printf("\n" JOB_STATUS_FORMAT, job_list.fg->jobid, - "Stopped", job_list.fg->text); - job_list.fg = NULL; - } - } - - if (!job_list.fg) { - /* move the shell to the foreground */ - /* suppress messages when run from /linuxrc mag@sysgo.de */ - if (tcsetpgrp(shell_terminal, getpgrp()) && errno != ENOTTY) - perror_msg("tcsetpgrp"); - } - } - } - free(command); - - /* return controlling TTY back to parent process group before exiting */ - if (tcsetpgrp(shell_terminal, parent_pgrp)) - perror_msg("tcsetpgrp"); - - /* return exit status if called with "-c" */ - if (input == NULL && WIFEXITED(status)) - return WEXITSTATUS(status); - - return 0; -} - - -#ifdef BB_FEATURE_CLEAN_UP -void free_memory(void) -{ - if (cwd && cwd!=unknown) { - free((char*)cwd); - } - if (local_pending_command) - free(local_pending_command); - - if (job_list.fg && !job_list.fg->running_progs) { - remove_job(&job_list, job_list.fg); - } -} -#endif - -/* Make sure we have a controlling tty. If we get started under a job - * aware app (like bash for example), make sure we are now in charge so - * we don't fight over who gets the foreground */ -static void setup_job_control() -{ - int status; - - /* Loop until we are in the foreground. */ - while ((status = tcgetpgrp (shell_terminal)) >= 0) { - if (status == (shell_pgrp = getpgrp ())) { - break; - } - kill (- shell_pgrp, SIGTTIN); - } - - /* Ignore interactive and job-control signals. */ - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - signal(SIGTSTP, SIG_IGN); - signal(SIGTTIN, SIG_IGN); - signal(SIGTTOU, SIG_IGN); - signal(SIGCHLD, SIG_IGN); - - /* Put ourselves in our own process group. */ - setsid(); - shell_pgrp = getpid (); - setpgid (shell_pgrp, shell_pgrp); - - /* Grab control of the terminal. */ - tcsetpgrp(shell_terminal, shell_pgrp); -} - -int lash_main(int argc_l, char **argv_l) -{ - int opt, interactive=FALSE; - FILE *input = stdin; - argc = argc_l; - argv = argv_l; - - /* These variables need re-initializing when recursing */ - last_jobid = 0; - local_pending_command = NULL; - close_me_head = NULL; - job_list.head = NULL; - job_list.fg = NULL; - last_return_code=1; - - if (argv[0] && argv[0][0] == '-') { - FILE *prof_input; - prof_input = fopen("/etc/profile", "r"); - if (prof_input) { - int tmp_fd = fileno(prof_input); - mark_open(tmp_fd); - /* Now run the file */ - busy_loop(prof_input); - fclose(prof_input); - mark_closed(tmp_fd); - } - } - - while ((opt = getopt(argc_l, argv_l, "cxi")) > 0) { - switch (opt) { - case 'c': - input = NULL; - if (local_pending_command != 0) - error_msg_and_die("multiple -c arguments"); - local_pending_command = xstrdup(argv[optind]); - optind++; - argv = argv+optind; - break; - case 'i': - interactive = TRUE; - break; - default: - show_usage(); - } - } - /* A shell is interactive if the `-i' flag was given, or if all of - * the following conditions are met: - * no -c command - * no arguments remaining or the -s flag given - * standard input is a terminal - * standard output is a terminal - * Refer to Posix.2, the description of the `sh' utility. */ - if (argv[optind]==NULL && input==stdin && - isatty(fileno(stdin)) && isatty(fileno(stdout))) { - interactive=TRUE; - } - setup_job_control(); - if (interactive==TRUE) { - //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]); - /* Looks like they want an interactive shell */ - printf( "\n\n" BB_BANNER " Built-in shell (lash)\n"); - printf( "Enter 'help' for a list of built-in commands.\n\n"); - } else if (local_pending_command==NULL) { - //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]); - input = xfopen(argv[optind], "r"); - mark_open(fileno(input)); /* be lazy, never mark this closed */ - } - - /* initialize the cwd -- this is never freed...*/ - cwd = xgetcwd(0); - if (!cwd) - cwd = unknown; - -#ifdef BB_FEATURE_CLEAN_UP - atexit(free_memory); -#endif - -#ifdef BB_FEATURE_COMMAND_EDITING - cmdedit_set_initial_prompt(); -#else - PS1 = NULL; -#endif - - return (busy_loop(input)); -} diff --git a/busybox/shell/msh.c b/busybox/shell/msh.c deleted file mode 100644 index e16d6f304..000000000 --- a/busybox/shell/msh.c +++ /dev/null @@ -1,4868 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Minix shell port for busybox - * - * This version of the Minix shell was adapted for use in busybox - * 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 - * - * Original copyright notice is retained at the end of this file. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cmdedit.h" -#include "busybox.h" - - -/* -------- sh.h -------- */ -/* - * shell - */ - -#define LINELIM 2100 -#define NPUSH 8 /* limit to input nesting */ - -#define NOFILE 20 /* Number of open files */ -#define NUFILE 10 /* Number of user-accessible files */ -#define FDBASE 10 /* First file usable by Shell */ - -/* - * values returned by wait - */ -#define WAITSIG(s) ((s)&0177) -#define WAITVAL(s) (((s)>>8)&0377) -#define WAITCORE(s) (((s)&0200)!=0) - -/* - * library and system defintions - */ -typedef void xint; /* base type of jmp_buf, for not broken compilers */ - -/* - * shell components - */ - -#define QUOTE 0200 - -#define NOBLOCK ((struct op *)NULL) -#define NOWORD ((char *)NULL) -#define NOWORDS ((char **)NULL) -#define NOPIPE ((int *)NULL) - -/* - * Description of a command or an operation on commands. - * Might eventually use a union. - */ -struct op { - int type; /* operation type, see below */ - char **words; /* arguments to a command */ - struct ioword **ioact; /* IO actions (eg, < > >>) */ - struct op *left; - struct op *right; - char *str; /* identifier for case and for */ -}; - -#define TCOM 1 /* command */ -#define TPAREN 2 /* (c-list) */ -#define TPIPE 3 /* a | b */ -#define TLIST 4 /* a [&;] b */ -#define TOR 5 /* || */ -#define TAND 6 /* && */ -#define TFOR 7 -#define TDO 8 -#define TCASE 9 -#define TIF 10 -#define TWHILE 11 -#define TUNTIL 12 -#define TELIF 13 -#define TPAT 14 /* pattern in case */ -#define TBRACE 15 /* {c-list} */ -#define TASYNC 16 /* c & */ - -/* - * actions determining the environment of a process - */ -#define BIT(i) (1<<(i)) -#define FEXEC BIT(0) /* execute without forking */ - -/* - * flags to control evaluation of words - */ -#define DOSUB 1 /* interpret $, `, and quotes */ -#define DOBLANK 2 /* perform blank interpretation */ -#define DOGLOB 4 /* interpret [?* */ -#define DOKEY 8 /* move words with `=' to 2nd arg. list */ -#define DOTRIM 16 /* trim resulting string */ - -#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM) - -static char **dolv; -static int dolc; -static int exstat; -static char gflg; -static int interactive; /* Is this an interactive shell */ -static int execflg; -static int multiline; /* \n changed to ; */ -static struct op *outtree; /* result from parser */ - -static xint *failpt; -static xint *errpt; -static struct brkcon *brklist; -static int isbreak; -static int newfile(char *s); -static char *findeq(char *cp); -static char *cclass(char *p, int sub); -static void initarea(void); -extern int msh_main(int argc, char **argv); - - -struct brkcon { - jmp_buf brkpt; - struct brkcon *nextlev; -} ; - -/* - * redirection - */ -struct ioword { - short io_unit; /* unit affected */ - short io_flag; /* action (below) */ - char *io_name; /* file name */ -}; -#define IOREAD 1 /* < */ -#define IOHERE 2 /* << (here file) */ -#define IOWRITE 4 /* > */ -#define IOCAT 8 /* >> */ -#define IOXHERE 16 /* ${}, ` in << */ -#define IODUP 32 /* >&digit */ -#define IOCLOSE 64 /* >&- */ - -#define IODEFAULT (-1) /* token for default IO unit */ - -static struct wdblock *wdlist; -static struct wdblock *iolist; - -/* - * parsing & execution environment - */ -static struct env { - char *linep; - struct io *iobase; - struct io *iop; - xint *errpt; - int iofd; - struct env *oenv; -} e; - -/* - * flags: - * -e: quit on error - * -k: look for name=value everywhere on command line - * -n: no execution - * -t: exit after reading and executing one command - * -v: echo as read - * -x: trace - * -u: unset variables net diagnostic - */ -static char *flag; - -static char *null; /* null value for variable */ -static int intr; /* interrupt pending */ - -static char *trap[_NSIG+1]; -static char ourtrap[_NSIG+1]; -static int trapset; /* trap pending */ - -static int heedint; /* heed interrupt signals */ - -static int yynerrs; /* yacc */ - -static char line[LINELIM]; -static char *elinep; - -/* - * other functions - */ -static int (*inbuilt(char *s ))(void); - -static char *rexecve (char *c , char **v, char **envp ); -static char *space (int n ); -static char *strsave (char *s, int a ); -static char *evalstr (char *cp, int f ); -static char *putn (int n ); -static char *itoa (unsigned u, int n ); -static char *unquote (char *as ); -static struct var *lookup (char *n ); -static int rlookup (char *n ); -static struct wdblock *glob (char *cp, struct wdblock *wb ); -static int my_getc( int ec); -static int subgetc (int ec, int quoted ); -static char **makenv (void); -static char **eval (char **ap, int f ); -static int setstatus (int s ); -static int waitfor (int lastpid, int canintr ); - -static void onintr (int s ); /* SIGINT handler */ - -static int newenv (int f ); -static void quitenv (void); -static void err (char *s ); -static int anys (char *s1, char *s2 ); -static int any (int c, char *s ); -static void next (int f ); -static void setdash (void); -static void onecommand (void); -static void runtrap (int i ); -static int gmatch (char *s, char *p ); - -/* - * error handling - */ -static void leave (void); /* abort shell (or fail in subshell) */ -static void fail (void); /* fail but return to process next command */ -static void warn (char *s ); -static void sig (int i ); /* default signal handler */ - - - -/* -------- area stuff -------- */ - -#define REGSIZE sizeof(struct region) -#define GROWBY 256 -//#define SHRINKBY 64 -#undef SHRINKBY -#define FREE 32767 -#define BUSY 0 -#define ALIGN (sizeof(int)-1) - - -struct region { - struct region *next; - int area; -}; - - - -/* -------- grammar stuff -------- */ -typedef union { - char *cp; - char **wp; - int i; - struct op *o; -} YYSTYPE; -#define WORD 256 -#define LOGAND 257 -#define LOGOR 258 -#define BREAK 259 -#define IF 260 -#define THEN 261 -#define ELSE 262 -#define ELIF 263 -#define FI 264 -#define CASE 265 -#define ESAC 266 -#define FOR 267 -#define WHILE 268 -#define UNTIL 269 -#define DO 270 -#define DONE 271 -#define IN 272 -#define YYERRCODE 300 - -/* flags to yylex */ -#define CONTIN 01 /* skip new lines to complete command */ - -#define SYNTAXERR zzerr() -static struct op *pipeline(int cf ); -static struct op *andor(void); -static struct op *c_list(void); -static int synio(int cf ); -static void musthave (int c, int cf ); -static struct op *simple(void); -static struct op *nested(int type, int mark ); -static struct op *command(int cf ); -static struct op *dogroup(int onlydone ); -static struct op *thenpart(void); -static struct op *elsepart(void); -static struct op *caselist(void); -static struct op *casepart(void); -static char **pattern(void); -static char **wordlist(void); -static struct op *list(struct op *t1, struct op *t2 ); -static struct op *block(int type, struct op *t1, struct op *t2, char **wp ); -static struct op *newtp(void); -static struct op *namelist(struct op *t ); -static char **copyw(void); -static void word(char *cp ); -static struct ioword **copyio(void); -static struct ioword *io (int u, int f, char *cp ); -static void zzerr(void); -static void yyerror(char *s ); -static int yylex(int cf ); -static int collect(int c, int c1 ); -static int dual(int c ); -static void diag(int ec ); -static char *tree(unsigned size ); - -/* -------- var.h -------- */ - -struct var { - char *value; - char *name; - struct var *next; - char status; -}; -#define COPYV 1 /* flag to setval, suggesting copy */ -#define RONLY 01 /* variable is read-only */ -#define EXPORT 02 /* variable is to be exported */ -#define GETCELL 04 /* name & value space was got with getcell */ - -static struct var *vlist; /* dictionary */ - -static struct var *homedir; /* home directory */ -static struct var *prompt; /* main prompt */ -static struct var *cprompt; /* continuation prompt */ -static struct var *path; /* search path for commands */ -static struct var *shell; /* shell to interpret command files */ -static struct var *ifs; /* field separators */ - -static int yyparse (void); -static struct var *lookup (char *n ); -static void setval (struct var *vp, char *val ); -static void nameval (struct var *vp, char *val, char *name ); -static void export (struct var *vp ); -static void ronly (struct var *vp ); -static int isassign (char *s ); -static int checkname (char *cp ); -static int assign (char *s, int cf ); -static void putvlist (int f, int out ); -static int eqname (char *n1, char *n2 ); - -static int execute (struct op *t, int *pin, int *pout, int act ); - -/* -------- io.h -------- */ -/* io buffer */ -struct iobuf { - unsigned id; /* buffer id */ - char buf[512]; /* buffer */ - char *bufp; /* pointer into buffer */ - char *ebufp; /* pointer to end of buffer */ -}; - -/* possible arguments to an IO function */ -struct ioarg { - char *aword; - char **awordlist; - int afile; /* file descriptor */ - unsigned afid; /* buffer id */ - long afpos; /* file position */ - struct iobuf *afbuf; /* buffer for this file */ -}; -//static struct ioarg ioargstack[NPUSH]; -#define AFID_NOBUF (~0) -#define AFID_ID 0 - -/* an input generator's state */ -struct io { - int (*iofn)(); - struct ioarg *argp; - int peekc; - char prev; /* previous character read by readc() */ - char nlcount; /* for `'s */ - char xchar; /* for `'s */ - char task; /* reason for pushed IO */ -}; -//static struct io iostack[NPUSH]; -#define XOTHER 0 /* none of the below */ -#define XDOLL 1 /* expanding ${} */ -#define XGRAVE 2 /* expanding `'s */ -#define XIO 3 /* file IO */ - -/* in substitution */ -#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL) - -/* - * input generators for IO structure - */ -static int nlchar (struct ioarg *ap ); -static int strchar (struct ioarg *ap ); -static int qstrchar (struct ioarg *ap ); -static int filechar (struct ioarg *ap ); -static int herechar (struct ioarg *ap ); -static int linechar (struct ioarg *ap ); -static int gravechar (struct ioarg *ap, struct io *iop ); -static int qgravechar (struct ioarg *ap, struct io *iop ); -static int dolchar (struct ioarg *ap ); -static int wdchar (struct ioarg *ap ); -static void scraphere (void); -static void freehere (int area ); -static void gethere (void); -static void markhere (char *s, struct ioword *iop ); -static int herein (char *hname, int xdoll ); -static int run (struct ioarg *argp, int (*f)()); - -/* - * IO functions - */ -static int eofc (void); -static int readc (void); -static void unget (int c ); -static void ioecho (int c ); -static void prs (char *s ); -static void prn (unsigned u ); -static void closef (int i ); -static void closeall (void); - -/* - * IO control - */ -static void pushio (struct ioarg *argp, int (*fn)()); -static int remap (int fd ); -static int openpipe (int *pv ); -static void closepipe (int *pv ); -static struct io *setbase (struct io *ip ); - -static struct ioarg temparg; /* temporary for PUSHIO */ -#define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen))) -#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen))) - -/* -------- word.h -------- */ - -#define NSTART 16 /* default number of words to allow for initially */ - -struct wdblock { - short w_bsize; - short w_nword; - /* bounds are arbitrary */ - char *w_words[1]; -}; - -static struct wdblock *addword (char *wd, struct wdblock *wb ); -static struct wdblock *newword (int nw ); -static char **getwords (struct wdblock *wb ); - -/* -------- area.h -------- */ - -/* - * storage allocation - */ -static char *getcell (unsigned nbytes ); -static void garbage (void); -static void setarea (char *cp, int a ); -static int getarea (char *cp ); -static void freearea (int a ); -static void freecell (char *cp ); -static int areanum; /* current allocation area */ - -#define NEW(type) (type *)getcell(sizeof(type)) -#define DELETE(obj) freecell((char *)obj) - - -/* -------- misc stuff -------- */ - -static int forkexec (struct op *t, int *pin, int *pout, int act, char **wp, int *pforked ); -static int iosetup (struct ioword *iop, int pipein, int pipeout ); -static void echo(char **wp ); -static struct op **find1case (struct op *t, char *w ); -static struct op *findcase (struct op *t, char *w ); -static void brkset(struct brkcon *bc ); -static int dolabel(void); -static int dohelp(void); -static int dochdir(struct op *t ); -static int doshift(struct op *t ); -static int dologin(struct op *t ); -static int doumask(struct op *t ); -static int doexec(struct op *t ); -static int dodot(struct op *t ); -static int dowait(struct op *t ); -static int doread(struct op *t ); -static int doeval(struct op *t ); -static int dotrap(struct op *t ); -static int getsig(char *s ); -static void setsig (int n, void (*f)()); -static int getn(char *as ); -static int dobreak(struct op *t ); -static int docontinue(struct op *t ); -static int brkcontin (char *cp, int val ); -static int doexit(struct op *t ); -static int doexport(struct op *t ); -static int doreadonly(struct op *t ); -static void rdexp (char **wp, void (*f)(), int key); -static void badid(char *s ); -static int doset(struct op *t ); -static void varput (char *s, int out ); -static int dotimes(void); -static int expand (char *cp, struct wdblock **wbp, int f ); -static char *blank(int f ); -static int dollar(int quoted ); -static int grave(int quoted ); -static void globname (char *we, char *pp ); -static char *generate (char *start1, char *end1, char *middle, char *end ); -static int anyspcl(struct wdblock *wb ); -static int xstrcmp (char *p1, char *p2 ); -static void glob0 (char *a0, unsigned int a1, int a2, int (*a3)(char *, char *)); -static void glob1 (char *base, char *lim ); -static void glob2 (char *i, char *j ); -static void glob3 (char *i, char *j, char *k ); -static void readhere (char **name, char *s, int ec ); -static void pushio(struct ioarg *argp, int (*fn)()); -static int xxchar(struct ioarg *ap ); - -struct here { - char *h_tag; - int h_dosub; - struct ioword *h_iop; - struct here *h_next; -}; - -static char *signame[] = { - "Signal 0", - "Hangup", - (char *)NULL, /* interrupt */ - "Quit", - "Illegal instruction", - "Trace/BPT trap", - "Abort", - "Bus error", - "Floating Point Exception", - "Killed", - "SIGUSR1", - "SIGSEGV", - "SIGUSR2", - (char *)NULL, /* broken pipe */ - "Alarm clock", - "Terminated", -}; -#define NSIGNAL (sizeof(signame)/sizeof(signame[0])) - -struct res { - char *r_name; - int r_val; -}; -static struct res restab[] = { - {"for", FOR}, - {"case", CASE}, - {"esac", ESAC}, - {"while", WHILE}, - {"do", DO}, - {"done", DONE}, - {"if", IF}, - {"in", IN}, - {"then", THEN}, - {"else", ELSE}, - {"elif", ELIF}, - {"until", UNTIL}, - {"fi", FI}, - - {";;", BREAK}, - {"||", LOGOR}, - {"&&", LOGAND}, - {"{", '{'}, - {"}", '}'}, - {0, 0}, -}; - - -struct builtincmd { - const char *name; - int (*builtinfunc)(); -}; -static const struct builtincmd builtincmds[] = { - {".", dodot}, - {":", dolabel}, - {"break", dobreak}, - {"cd", dochdir}, - {"continue",docontinue}, - {"eval", doeval}, - {"exec", doexec}, - {"exit", doexit}, - {"export", doexport}, - {"help", dohelp}, - {"login", dologin}, - {"newgrp", dologin}, - {"read", doread}, - {"readonly",doreadonly}, - {"set", doset}, - {"shift", doshift}, - {"times", dotimes}, - {"trap", dotrap}, - {"umask", doumask}, - {"wait", dowait}, - {0,0} -}; - -/* Globals */ -extern char **environ; /* environment pointer */ -static char **dolv; -static int dolc; -static int exstat; -static char gflg; -static int interactive; /* Is this an interactive shell */ -static int execflg; -static int multiline; /* \n changed to ; */ -static struct op *outtree; /* result from parser */ -static xint *failpt; -static xint *errpt; -static struct brkcon *brklist; -static int isbreak; -static struct wdblock *wdlist; -static struct wdblock *iolist; -static char *trap[_NSIG+1]; -static char ourtrap[_NSIG+1]; -static int trapset; /* trap pending */ -static int yynerrs; /* yacc */ -static char line[LINELIM]; -static struct var *vlist; /* dictionary */ -static struct var *homedir; /* home directory */ -static struct var *prompt; /* main prompt */ -static struct var *cprompt; /* continuation prompt */ -static struct var *path; /* search path for commands */ -static struct var *shell; /* shell to interpret command files */ -static struct var *ifs; /* field separators */ -static struct ioarg ioargstack[NPUSH]; -static struct io iostack[NPUSH]; -static int areanum; /* current allocation area */ -static int intr; -static int inparse; -static char flags['z'-'a'+1]; -static char *flag = flags-'a'; -static char *elinep = line+sizeof(line)-5; -static char *null = ""; -static int heedint =1; -static struct env e ={line, iostack, iostack-1, (xint *)NULL, FDBASE, (struct env *)NULL}; -static void (*qflag)(int) = SIG_IGN; -static char shellname[] = "/bin/sh"; -static char search[] = ":/bin:/usr/bin"; -static int startl; -static int peeksym; -static int nlseen; -static int iounit = IODEFAULT; -static YYSTYPE yylval; -static struct iobuf sharedbuf = {AFID_NOBUF}; -static struct iobuf mainbuf = {AFID_NOBUF}; -static unsigned bufid = AFID_ID; /* buffer id counter */ -static struct ioarg temparg = {0, 0, 0, AFID_NOBUF, 0}; -static struct here *inhere; /* list of hear docs while parsing */ -static struct here *acthere; /* list of active here documents */ -static struct region *areabot; /* bottom of area */ -static struct region *areatop; /* top of area */ -static struct region *areanxt; /* starting point of scan */ -static void * brktop; -static void * brkaddr; - - -#ifdef BB_FEATURE_COMMAND_EDITING -static char * current_prompt; -#endif - - -/* -------- sh.c -------- */ -/* - * shell - */ - - -extern int msh_main(int argc, char **argv) -{ - register int f; - register char *s; - int cflag; - char *name, **ap; - int (*iof)(); - - initarea(); - if ((ap = environ) != NULL) { - while (*ap) - assign(*ap++, !COPYV); - for (ap = environ; *ap;) - export(lookup(*ap++)); - } - closeall(); - areanum = 1; - - shell = lookup("SHELL"); - if (shell->value == null) - setval(shell, shellname); - export(shell); - - homedir = lookup("HOME"); - if (homedir->value == null) - setval(homedir, "/"); - export(homedir); - - setval(lookup("$"), itoa(getpid(), 5)); - - path = lookup("PATH"); - if (path->value == null) - setval(path, search); - export(path); - - ifs = lookup("IFS"); - if (ifs->value == null) - setval(ifs, " \t\n"); - - prompt = lookup("PS1"); -#ifdef BB_FEATURE_SH_FANCY_PROMPT - if (prompt->value == null) -#endif - setval(prompt, "$ "); - if (geteuid() == 0) { - setval(prompt, "# "); - prompt->status &= ~EXPORT; - } - cprompt = lookup("PS2"); -#ifdef BB_FEATURE_SH_FANCY_PROMPT - if (cprompt->value == null) -#endif - setval(cprompt, "> "); - - iof = filechar; - cflag = 0; - name = *argv++; - if (--argc >= 1) { - if(argv[0][0] == '-' && argv[0][1] != '\0') { - for (s = argv[0]+1; *s; s++) - switch (*s) { - case 'c': - prompt->status &= ~EXPORT; - cprompt->status &= ~EXPORT; - setval(prompt, ""); - setval(cprompt, ""); - cflag = 1; - if (--argc > 0) - PUSHIO(aword, *++argv, iof = nlchar); - break; - - case 'q': - qflag = SIG_DFL; - break; - - case 's': - /* standard input */ - break; - - case 't': - prompt->status &= ~EXPORT; - setval(prompt, ""); - iof = linechar; - break; - - case 'i': - interactive++; - default: - if (*s>='a' && *s<='z') - flag[(int)*s]++; - } - } else { - argv--; - argc++; - } - if (iof == filechar && --argc > 0) { - setval(prompt, ""); - setval(cprompt, ""); - prompt->status &= ~EXPORT; - cprompt->status &= ~EXPORT; - if (newfile(name = *++argv)) - exit(1); - } - } - setdash(); - if (e.iop < iostack) { - PUSHIO(afile, 0, iof); - if (isatty(0) && isatty(1) && !cflag) { - interactive++; - printf( "\n\n" BB_BANNER " Built-in shell (msh)\n"); - printf( "Enter 'help' for a list of built-in commands.\n\n"); - } - } - signal(SIGQUIT, qflag); - if (name && name[0] == '-') { - interactive++; - if ((f = open(".profile", 0)) >= 0) - next(remap(f)); - if ((f = open("/etc/profile", 0)) >= 0) - next(remap(f)); - } - if (interactive) - signal(SIGTERM, sig); - if (signal(SIGINT, SIG_IGN) != SIG_IGN) - signal(SIGINT, onintr); - dolv = argv; - dolc = argc; - dolv[0] = name; - if (dolc > 1) { - for (ap = ++argv; --argc > 0;) { - if (assign(*ap = *argv++, !COPYV)) { - dolc--; /* keyword */ - } else { - ap++; - } - } - } - setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc)); - - for (;;) { - if (interactive && e.iop <= iostack) { -#ifdef BB_FEATURE_COMMAND_EDITING - current_prompt=prompt->value; -#else - prs(prompt->value); -#endif - } - onecommand(); - } -} - -static void -setdash() -{ - register char *cp; - register int c; - char m['z'-'a'+1]; - - cp = m; - for (c='a'; c<='z'; c++) - if (flag[c]) - *cp++ = c; - *cp = 0; - setval(lookup("-"), m); -} - -static int -newfile(s) -register char *s; -{ - register int f; - - if (strcmp(s, "-") != 0) { - f = open(s, 0); - if (f < 0) { - prs(s); - err(": cannot open"); - return(1); - } - } else - f = 0; - next(remap(f)); - return(0); -} - -static void -onecommand() -{ - register int i; - jmp_buf m1; - - while (e.oenv) - quitenv(); - areanum = 1; - freehere(areanum); - freearea(areanum); - garbage(); - wdlist = 0; - iolist = 0; - e.errpt = 0; - e.linep = line; - yynerrs = 0; - multiline = 0; - inparse = 1; - intr = 0; - execflg = 0; - setjmp(failpt = m1); /* Bruce Evans' fix */ - if (setjmp(failpt = m1) || yyparse() || intr) { - while (e.oenv) - quitenv(); - scraphere(); - if (!interactive && intr) - leave(); - inparse = 0; - intr = 0; - return; - } - inparse = 0; - brklist = 0; - intr = 0; - execflg = 0; - if (!flag['n']) - execute(outtree, NOPIPE, NOPIPE, 0); - if (!interactive && intr) { - execflg = 0; - leave(); - } - if ((i = trapset) != 0) { - trapset = 0; - runtrap(i); - } -} - -static void -fail() -{ - longjmp(failpt, 1); - /* NOTREACHED */ -} - -static void -leave() -{ - if (execflg) - fail(); - scraphere(); - freehere(1); - runtrap(0); - exit(exstat); - /* NOTREACHED */ -} - -static void -warn(s) -register char *s; -{ - if(*s) { - prs(s); - exstat = -1; - } - prs("\n"); - if (flag['e']) - leave(); -} - -static void -err(s) -char *s; -{ - warn(s); - if (flag['n']) - return; - if (!interactive) - leave(); - if (e.errpt) - longjmp(e.errpt, 1); - closeall(); - e.iop = e.iobase = iostack; -} - -static int -newenv(f) -int f; -{ - register struct env *ep; - - if (f) { - quitenv(); - return(1); - } - ep = (struct env *) space(sizeof(*ep)); - if (ep == NULL) { - while (e.oenv) - quitenv(); - fail(); - } - *ep = e; - e.oenv = ep; - e.errpt = errpt; - return(0); -} - -static void -quitenv() -{ - register struct env *ep; - register int fd; - - if ((ep = e.oenv) != NULL) { - fd = e.iofd; - e = *ep; - /* should close `'d files */ - DELETE(ep); - while (--fd >= e.iofd) - close(fd); - } -} - -/* - * Is any character from s1 in s2? - */ -static int -anys(s1, s2) -register char *s1, *s2; -{ - while (*s1) - if (any(*s1++, s2)) - return(1); - return(0); -} - -/* - * Is character c in s? - */ -static int -any(c, s) -register int c; -register char *s; -{ - while (*s) - if (*s++ == c) - return(1); - return(0); -} - -static char * -putn(n) -register int n; -{ - return(itoa(n, -1)); -} - -static char * -itoa(u, n) -register unsigned u; -int n; -{ - register char *cp; - static char s[20]; - int m; - - m = 0; - if (n < 0 && (int) u < 0) { - m++; - u = -u; - } - cp = s+sizeof(s); - *--cp = 0; - do { - *--cp = u%10 + '0'; - u /= 10; - } while (--n > 0 || u); - if (m) - *--cp = '-'; - return(cp); -} - -static void -next(f) -int f; -{ - PUSHIO(afile, f, filechar); -} - -static void -onintr(s) -int s; /* ANSI C requires a parameter */ -{ - signal(SIGINT, onintr); - intr = 1; - if (interactive) { - if (inparse) { - prs("\n"); - fail(); - } - } - else if (heedint) { - execflg = 0; - leave(); - } -} - -static char * -space(n) -int n; -{ - register char *cp; - - if ((cp = getcell(n)) == 0) - err("out of string space"); - return(cp); -} - -static char * -strsave(s, a) -register char *s; -int a; -{ - register char *cp, *xp; - - if ((cp = space(strlen(s)+1)) != NULL) { - setarea((char *)cp, a); - for (xp = cp; (*xp++ = *s++) != '\0';) - ; - return(cp); - } - return(""); -} - -/* - * trap handling - */ -static void -sig(i) -register int i; -{ - trapset = i; - signal(i, sig); -} - -static void runtrap(i) -int i; -{ - char *trapstr; - - if ((trapstr = trap[i]) == NULL) - return; - if (i == 0) - trap[i] = 0; - RUN(aword, trapstr, nlchar); -} - -/* -------- var.c -------- */ - -/* - * Find the given name in the dictionary - * and return its value. If the name was - * not previously there, enter it now and - * return a null value. - */ -static struct var * -lookup(n) -register char *n; -{ - register struct var *vp; - register char *cp; - register int c; - static struct var dummy; - - if (isdigit(*n)) { - dummy.name = n; - for (c = 0; isdigit(*n) && c < 1000; n++) - c = c*10 + *n-'0'; - dummy.status = RONLY; - dummy.value = c <= dolc? dolv[c]: null; - return(&dummy); - } - for (vp = vlist; vp; vp = vp->next) - if (eqname(vp->name, n)) - return(vp); - cp = findeq(n); - vp = (struct var *)space(sizeof(*vp)); - if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) { - dummy.name = dummy.value = ""; - return(&dummy); - } - for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++) - ; - if (*cp == 0) - *cp = '='; - *++cp = 0; - setarea((char *)vp, 0); - setarea((char *)vp->name, 0); - vp->value = null; - vp->next = vlist; - vp->status = GETCELL; - vlist = vp; - return(vp); -} - -/* - * give variable at `vp' the value `val'. - */ -static void -setval(vp, val) -struct var *vp; -char *val; -{ - nameval(vp, val, (char *)NULL); -} - -/* - * if name is not NULL, it must be - * a prefix of the space `val', - * and end with `='. - * this is all so that exporting - * values is reasonably painless. - */ -static void -nameval(vp, val, name) -register struct var *vp; -char *val, *name; -{ - register char *cp, *xp; - char *nv; - int fl; - - if (vp->status & RONLY) { - for (xp = vp->name; *xp && *xp != '=';) - putc(*xp++, stderr); - err(" is read-only"); - return; - } - fl = 0; - if (name == NULL) { - xp = space(strlen(vp->name)+strlen(val)+2); - if (xp == 0) - return; - /* make string: name=value */ - setarea((char *)xp, 0); - name = xp; - for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++) - ; - if (*xp++ == 0) - xp[-1] = '='; - nv = xp; - for (cp = val; (*xp++ = *cp++) != '\0';) - ; - val = nv; - fl = GETCELL; - } - if (vp->status & GETCELL) - freecell(vp->name); /* form new string `name=value' */ - vp->name = name; - vp->value = val; - vp->status |= fl; -} - -static void -export(vp) -struct var *vp; -{ - vp->status |= EXPORT; -} - -static void -ronly(vp) -struct var *vp; -{ - if (isalpha(vp->name[0]) || vp->name[0] == '_') /* not an internal symbol */ - vp->status |= RONLY; -} - -static int -isassign(s) -register char *s; -{ - if (!isalpha((int)*s) && *s != '_') - return(0); - for (; *s != '='; s++) - if (*s == 0 || (!isalnum(*s) && *s != '_')) - return(0); - return(1); -} - -static int -assign(s, cf) -register char *s; -int cf; -{ - register char *cp; - struct var *vp; - - if (!isalpha(*s) && *s != '_') - return(0); - for (cp = s; *cp != '='; cp++) - if (*cp == 0 || (!isalnum(*cp) && *cp != '_')) - return(0); - vp = lookup(s); - nameval(vp, ++cp, cf == COPYV? (char *)NULL: s); - if (cf != COPYV) - vp->status &= ~GETCELL; - return(1); -} - -static int -checkname(cp) -register char *cp; -{ - if (!isalpha(*cp++) && *(cp-1) != '_') - return(0); - while (*cp) - if (!isalnum(*cp++) && *(cp-1) != '_') - return(0); - return(1); -} - -static void -putvlist(f, out) -register int f, out; -{ - register struct var *vp; - - for (vp = vlist; vp; vp = vp->next) - if (vp->status & f && (isalpha(*vp->name) || *vp->name == '_')) { - if (vp->status & EXPORT) - write(out, "export ", 7); - if (vp->status & RONLY) - write(out, "readonly ", 9); - write(out, vp->name, (int)(findeq(vp->name) - vp->name)); - write(out, "\n", 1); - } -} - -static int -eqname(n1, n2) -register char *n1, *n2; -{ - for (; *n1 != '=' && *n1 != 0; n1++) - if (*n2++ != *n1) - return(0); - return(*n2 == 0 || *n2 == '='); -} - -static char * -findeq(cp) -register char *cp; -{ - while (*cp != '\0' && *cp != '=') - cp++; - return(cp); -} - -/* -------- gmatch.c -------- */ -/* - * int gmatch(string, pattern) - * char *string, *pattern; - * - * Match a pattern as in sh(1). - */ - -#define CMASK 0377 -#define QUOTE 0200 -#define QMASK (CMASK&~QUOTE) -#define NOT '!' /* might use ^ */ - -static int -gmatch(s, p) -register char *s, *p; -{ - register int sc, pc; - - if (s == NULL || p == NULL) - return(0); - while ((pc = *p++ & CMASK) != '\0') { - sc = *s++ & QMASK; - switch (pc) { - case '[': - if ((p = cclass(p, sc)) == NULL) - return(0); - break; - - case '?': - if (sc == 0) - return(0); - break; - - case '*': - s--; - do { - if (*p == '\0' || gmatch(s, p)) - return(1); - } while (*s++ != '\0'); - return(0); - - default: - if (sc != (pc&~QUOTE)) - return(0); - } - } - return(*s == 0); -} - -static char * -cclass(p, sub) -register char *p; -register int sub; -{ - register int c, d, not, found; - - if ((not = *p == NOT) != 0) - p++; - found = not; - do { - if (*p == '\0') - return((char *)NULL); - c = *p & CMASK; - if (p[1] == '-' && p[2] != ']') { - d = p[2] & CMASK; - p++; - } else - d = c; - if (c == sub || (c <= sub && sub <= d)) - found = !not; - } while (*++p != ']'); - return(found? p+1: (char *)NULL); -} - - -/* -------- area.c -------- */ - -/* - * All memory between (char *)areabot and (char *)(areatop+1) is - * exclusively administered by the area management routines. - * It is assumed that sbrk() and brk() manipulate the high end. - */ - -#define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;}) - -static void -initarea() -{ - brkaddr = malloc(65000); - brktop = brkaddr + 65000; - - while ((int)sbrk(0) & ALIGN) - sbrk(1); - areabot = (struct region *)sbrk(REGSIZE); - - areabot->next = areabot; - areabot->area = BUSY; - areatop = areabot; - areanxt = areabot; -} - -char * -getcell(nbytes) -unsigned nbytes; -{ - register int nregio; - register struct region *p, *q; - register int i; - - if (nbytes == 0) { - puts("getcell(0)"); - abort(); - } /* silly and defeats the algorithm */ - /* - * round upwards and add administration area - */ - nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1; - for (p = areanxt;;) { - if (p->area > areanum) { - /* - * merge free cells - */ - while ((q = p->next)->area > areanum && q != areanxt) - p->next = q->next; - /* - * exit loop if cell big enough - */ - if (q >= p + nregio) - goto found; - } - p = p->next; - if (p == areanxt) - break; - } - i = nregio >= GROWBY ? nregio : GROWBY; - p = (struct region *)sbrk(i * REGSIZE); - if (p == (struct region *)-1) - return((char *)NULL); - p--; - if (p != areatop) { - puts("not contig"); - abort(); /* allocated areas are contiguous */ - } - q = p + i; - p->next = q; - p->area = FREE; - q->next = areabot; - q->area = BUSY; - areatop = q; -found: - /* - * we found a FREE area big enough, pointed to by 'p', and up to 'q' - */ - areanxt = p + nregio; - if (areanxt < q) { - /* - * split into requested area and rest - */ - if (areanxt+1 > q) { - puts("OOM"); - abort(); /* insufficient space left for admin */ - } - areanxt->next = q; - areanxt->area = FREE; - p->next = areanxt; - } - p->area = areanum; - return((char *)(p+1)); -} - -static void -freecell(cp) -char *cp; -{ - register struct region *p; - - if ((p = (struct region *)cp) != NULL) { - p--; - if (p < areanxt) - areanxt = p; - p->area = FREE; - } -} - -static void -freearea(a) -register int a; -{ - register struct region *p, *top; - - top = areatop; - for (p = areabot; p != top; p = p->next) - if (p->area >= a) - p->area = FREE; -} - -static void -setarea(cp,a) -char *cp; -int a; -{ - register struct region *p; - - if ((p = (struct region *)cp) != NULL) - (p-1)->area = a; -} - -int -getarea(cp) -char *cp; -{ - return ((struct region*)cp-1)->area; -} - -static void -garbage() -{ - register struct region *p, *q, *top; - - top = areatop; - for (p = areabot; p != top; p = p->next) { - if (p->area > areanum) { - while ((q = p->next)->area > areanum) - p->next = q->next; - areanxt = p; - } - } -#ifdef SHRINKBY - if (areatop >= q + SHRINKBY && q->area > areanum) { - brk((char *)(q+1)); - q->next = areabot; - q->area = BUSY; - areatop = q; - } -#endif -} - -/* -------- csyn.c -------- */ -/* - * shell: syntax (C version) - */ - - -int -yyparse() -{ - startl = 1; - peeksym = 0; - yynerrs = 0; - outtree = c_list(); - musthave('\n', 0); - return(yynerrs!=0); -} - -static struct op * -pipeline(cf) -int cf; -{ - register struct op *t, *p; - register int c; - - t = command(cf); - if (t != NULL) { - while ((c = yylex(0)) == '|') { - if ((p = command(CONTIN)) == NULL) - SYNTAXERR; - if (t->type != TPAREN && t->type != TCOM) { - /* shell statement */ - t = block(TPAREN, t, NOBLOCK, NOWORDS); - } - t = block(TPIPE, t, p, NOWORDS); - } - peeksym = c; - } - return(t); -} - -static struct op * -andor() -{ - register struct op *t, *p; - register int c; - - t = pipeline(0); - if (t != NULL) { - while ((c = yylex(0)) == LOGAND || c == LOGOR) { - if ((p = pipeline(CONTIN)) == NULL) - SYNTAXERR; - t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS); - } - peeksym = c; - } - return(t); -} - -static struct op * -c_list() -{ - register struct op *t, *p; - register int c; - - t = andor(); - if (t != NULL) { - if((peeksym = yylex(0)) == '&') - t = block(TASYNC, t, NOBLOCK, NOWORDS); - while ((c = yylex(0)) == ';' || c == '&' || (multiline && c == '\n')) { - if ((p = andor()) == NULL) - return(t); - if((peeksym = yylex(0)) == '&') - p = block(TASYNC, p, NOBLOCK, NOWORDS); - t = list(t, p); - } - peeksym = c; - } - return(t); -} - - -static int -synio(cf) -int cf; -{ - register struct ioword *iop; - register int i; - register int c; - - if ((c = yylex(cf)) != '<' && c != '>') { - peeksym = c; - return(0); - } - i = yylval.i; - musthave(WORD, 0); - iop = io(iounit, i, yylval.cp); - iounit = IODEFAULT; - if (i & IOHERE) - markhere(yylval.cp, iop); - return(1); -} - -static void -musthave(c, cf) -int c, cf; -{ - if ((peeksym = yylex(cf)) != c) - SYNTAXERR; - peeksym = 0; -} - -static struct op * -simple() -{ - register struct op *t; - - t = NULL; - for (;;) { - switch (peeksym = yylex(0)) { - case '<': - case '>': - (void) synio(0); - break; - - case WORD: - if (t == NULL) { - t = newtp(); - t->type = TCOM; - } - peeksym = 0; - word(yylval.cp); - break; - - default: - return(t); - } - } -} - -static struct op * -nested(type, mark) -int type, mark; -{ - register struct op *t; - - multiline++; - t = c_list(); - musthave(mark, 0); - multiline--; - return(block(type, t, NOBLOCK, NOWORDS)); -} - -static struct op * -command(cf) -int cf; -{ - register struct op *t; - struct wdblock *iosave; - register int c; - - iosave = iolist; - iolist = NULL; - if (multiline) - cf |= CONTIN; - while (synio(cf)) - cf = 0; - switch (c = yylex(cf)) { - default: - peeksym = c; - if ((t = simple()) == NULL) { - if (iolist == NULL) - return((struct op *)NULL); - t = newtp(); - t->type = TCOM; - } - break; - - case '(': - t = nested(TPAREN, ')'); - break; - - case '{': - t = nested(TBRACE, '}'); - break; - - case FOR: - t = newtp(); - t->type = TFOR; - musthave(WORD, 0); - startl = 1; - t->str = yylval.cp; - multiline++; - t->words = wordlist(); - if ((c = yylex(0)) != '\n' && c != ';') - peeksym = c; - t->left = dogroup(0); - multiline--; - break; - - case WHILE: - case UNTIL: - multiline++; - t = newtp(); - t->type = c == WHILE? TWHILE: TUNTIL; - t->left = c_list(); - t->right = dogroup(1); - t->words = NULL; - multiline--; - break; - - case CASE: - t = newtp(); - t->type = TCASE; - musthave(WORD, 0); - t->str = yylval.cp; - startl++; - multiline++; - musthave(IN, CONTIN); - startl++; - t->left = caselist(); - musthave(ESAC, 0); - multiline--; - break; - - case IF: - multiline++; - t = newtp(); - t->type = TIF; - t->left = c_list(); - t->right = thenpart(); - musthave(FI, 0); - multiline--; - break; - } - while (synio(0)) - ; - t = namelist(t); - iolist = iosave; - return(t); -} - -static struct op * -dogroup(onlydone) -int onlydone; -{ - register int c; - register struct op *mylist; - - c = yylex(CONTIN); - if (c == DONE && onlydone) - return((struct op *)NULL); - if (c != DO) - SYNTAXERR; - mylist = c_list(); - musthave(DONE, 0); - return(mylist); -} - -static struct op * -thenpart() -{ - register int c; - register struct op *t; - - if ((c = yylex(0)) != THEN) { - peeksym = c; - return((struct op *)NULL); - } - t = newtp(); - t->type = 0; - t->left = c_list(); - if (t->left == NULL) - SYNTAXERR; - t->right = elsepart(); - return(t); -} - -static struct op * -elsepart() -{ - register int c; - register struct op *t; - - switch (c = yylex(0)) { - case ELSE: - if ((t = c_list()) == NULL) - SYNTAXERR; - return(t); - - case ELIF: - t = newtp(); - t->type = TELIF; - t->left = c_list(); - t->right = thenpart(); - return(t); - - default: - peeksym = c; - return((struct op *)NULL); - } -} - -static struct op * -caselist() -{ - register struct op *t; - - t = NULL; - while ((peeksym = yylex(CONTIN)) != ESAC) - t = list(t, casepart()); - return(t); -} - -static struct op * -casepart() -{ - register struct op *t; - - t = newtp(); - t->type = TPAT; - t->words = pattern(); - musthave(')', 0); - t->left = c_list(); - if ((peeksym = yylex(CONTIN)) != ESAC) - musthave(BREAK, CONTIN); - return(t); -} - -static char ** -pattern() -{ - register int c, cf; - - cf = CONTIN; - do { - musthave(WORD, cf); - word(yylval.cp); - cf = 0; - } while ((c = yylex(0)) == '|'); - peeksym = c; - word(NOWORD); - return(copyw()); -} - -static char ** -wordlist() -{ - register int c; - - if ((c = yylex(0)) != IN) { - peeksym = c; - return((char **)NULL); - } - startl = 0; - while ((c = yylex(0)) == WORD) - word(yylval.cp); - word(NOWORD); - peeksym = c; - return(copyw()); -} - -/* - * supporting functions - */ -static struct op * -list(t1, t2) -register struct op *t1, *t2; -{ - if (t1 == NULL) - return(t2); - if (t2 == NULL) - return(t1); - return(block(TLIST, t1, t2, NOWORDS)); -} - -static struct op * -block(type, t1, t2, wp) -int type; -struct op *t1, *t2; -char **wp; -{ - register struct op *t; - - t = newtp(); - t->type = type; - t->left = t1; - t->right = t2; - t->words = wp; - return(t); -} - -static int -rlookup(n) -register char *n; -{ - register struct res *rp; - - for (rp = restab; rp->r_name; rp++) - if (strcmp(rp->r_name, n) == 0) - return(rp->r_val); - return(0); -} - -static struct op * -newtp() -{ - register struct op *t; - - t = (struct op *)tree(sizeof(*t)); - t->type = 0; - t->words = NULL; - t->ioact = NULL; - t->left = NULL; - t->right = NULL; - t->str = NULL; - return(t); -} - -static struct op * -namelist(t) -register struct op *t; -{ - if (iolist) { - iolist = addword((char *)NULL, iolist); - t->ioact = copyio(); - } else - t->ioact = NULL; - if (t->type != TCOM) { - if (t->type != TPAREN && t->ioact != NULL) { - t = block(TPAREN, t, NOBLOCK, NOWORDS); - t->ioact = t->left->ioact; - t->left->ioact = NULL; - } - return(t); - } - word(NOWORD); - t->words = copyw(); - return(t); -} - -static char ** -copyw() -{ - register char **wd; - - wd = getwords(wdlist); - wdlist = 0; - return(wd); -} - -static void -word(cp) -char *cp; -{ - wdlist = addword(cp, wdlist); -} - -static struct ioword ** -copyio() -{ - register struct ioword **iop; - - iop = (struct ioword **) getwords(iolist); - iolist = 0; - return(iop); -} - -static struct ioword * -io(u, f, cp) -int u; -int f; -char *cp; -{ - register struct ioword *iop; - - iop = (struct ioword *) tree(sizeof(*iop)); - iop->io_unit = u; - iop->io_flag = f; - iop->io_name = cp; - iolist = addword((char *)iop, iolist); - return(iop); -} - -static void -zzerr() -{ - yyerror("syntax error"); -} - -static void -yyerror(s) -char *s; -{ - yynerrs++; - if (interactive && e.iop <= iostack) { - multiline = 0; - while (eofc() == 0 && yylex(0) != '\n') - ; - } - err(s); - fail(); -} - -static int -yylex(cf) -int cf; -{ - register int c, c1; - int atstart; - - if ((c = peeksym) > 0) { - peeksym = 0; - if (c == '\n') - startl = 1; - return(c); - } - nlseen = 0; - e.linep = line; - atstart = startl; - startl = 0; - yylval.i = 0; - -loop: - while ((c = my_getc(0)) == ' ' || c == '\t') - ; - switch (c) { - default: - if (any(c, "0123456789")) { - unget(c1 = my_getc(0)); - if (c1 == '<' || c1 == '>') { - iounit = c - '0'; - goto loop; - } - *e.linep++ = c; - c = c1; - } - break; - - case '#': - while ((c = my_getc(0)) != 0 && c != '\n') - ; - unget(c); - goto loop; - - case 0: - return(c); - - case '$': - *e.linep++ = c; - if ((c = my_getc(0)) == '{') { - if ((c = collect(c, '}')) != '\0') - return(c); - goto pack; - } - break; - - case '`': - case '\'': - case '"': - if ((c = collect(c, c)) != '\0') - return(c); - goto pack; - - case '|': - case '&': - case ';': - if ((c1 = dual(c)) != '\0') { - startl = 1; - return(c1); - } - startl = 1; - return(c); - case '^': - startl = 1; - return('|'); - case '>': - case '<': - diag(c); - return(c); - - case '\n': - nlseen++; - gethere(); - startl = 1; - if (multiline || cf & CONTIN) { - if (interactive && e.iop <= iostack) { -#ifdef BB_FEATURE_COMMAND_EDITING - current_prompt=cprompt->value; -#else - prs(cprompt->value); -#endif - } - if (cf & CONTIN) - goto loop; - } - return(c); - - case '(': - case ')': - startl = 1; - return(c); - } - - unget(c); - -pack: - while ((c = my_getc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n")) - if (e.linep >= elinep) - err("word too long"); - else - *e.linep++ = c; - unget(c); - if(any(c, "\"'`$")) - goto loop; - *e.linep++ = '\0'; - if (atstart && (c = rlookup(line))!=0) { - startl = 1; - return(c); - } - yylval.cp = strsave(line, areanum); - return(WORD); -} - -static int -collect(c, c1) -register int c, c1; -{ - char s[2]; - - *e.linep++ = c; - while ((c = my_getc(c1)) != c1) { - if (c == 0) { - unget(c); - s[0] = c1; - s[1] = 0; - prs("no closing "); yyerror(s); - return(YYERRCODE); - } - if (interactive && c == '\n' && e.iop <= iostack) { -#ifdef BB_FEATURE_COMMAND_EDITING - current_prompt=cprompt->value; -#else - prs(cprompt->value); -#endif - } - *e.linep++ = c; - } - *e.linep++ = c; - return(0); -} - -static int -dual(c) -register int c; -{ - char s[3]; - register char *cp = s; - - *cp++ = c; - *cp++ = my_getc(0); - *cp = 0; - if ((c = rlookup(s)) == 0) - unget(*--cp); - return(c); -} - -static void -diag(ec) -register int ec; -{ - register int c; - - c = my_getc(0); - if (c == '>' || c == '<') { - if (c != ec) - zzerr(); - yylval.i = ec == '>'? IOWRITE|IOCAT: IOHERE; - c = my_getc(0); - } else - yylval.i = ec == '>'? IOWRITE: IOREAD; - if (c != '&' || yylval.i == IOHERE) - unget(c); - else - yylval.i |= IODUP; -} - -static char * -tree(size) -unsigned size; -{ - register char *t; - - if ((t = getcell(size)) == NULL) { - prs("command line too complicated\n"); - fail(); - /* NOTREACHED */ - } - return(t); -} - -/* VARARGS1 */ -/* ARGSUSED */ - -/* -------- exec.c -------- */ - -/* - * execute tree - */ - - -static int -execute(t, pin, pout, act) -register struct op *t; -int *pin, *pout; -int act; -{ - register struct op *t1; - volatile int i, rv, a; - char *cp, **wp, **wp2; - struct var *vp; - struct brkcon bc; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) ℘ -#endif - - - if (t == NULL) - return(0); - rv = 0; - a = areanum++; - wp = (wp2 = t->words) != NULL - ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY) - : NULL; - - switch(t->type) { - case TPAREN: - case TCOM: - { - int child; - rv = forkexec(t, pin, pout, act, wp, &child); - if (child) { - exstat = rv; - leave(); - } - } - break; - - case TPIPE: - { - int pv[2]; - if ((rv = openpipe(pv)) < 0) - break; - pv[0] = remap(pv[0]); - pv[1] = remap(pv[1]); - (void) execute(t->left, pin, pv, 0); - rv = execute(t->right, pv, pout, 0); - } - break; - - case TLIST: - (void) execute(t->left, pin, pout, 0); - rv = execute(t->right, pin, pout, 0); - break; - - case TASYNC: - { - int hinteractive = interactive; - - i = vfork(); - if (i != 0) { - interactive = hinteractive; - if (i != -1) { - setval(lookup("!"), putn(i)); - if (pin != NULL) - closepipe(pin); - if (interactive) { - prs(putn(i)); - prs("\n"); - } - } else - rv = -1; - setstatus(rv); - } else { - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - if (interactive) - signal(SIGTERM, SIG_DFL); - interactive = 0; - if (pin == NULL) { - close(0); - open("/dev/null", 0); - } - exit(execute(t->left, pin, pout, FEXEC)); - } - } - break; - - case TOR: - case TAND: - rv = execute(t->left, pin, pout, 0); - if ((t1 = t->right)!=NULL && (rv == 0) == (t->type == TAND)) - rv = execute(t1, pin, pout, 0); - break; - - case TFOR: - if (wp == NULL) { - wp = dolv+1; - if ((i = dolc) < 0) - i = 0; - } else { - i = -1; - while (*wp++ != NULL) - ; - } - vp = lookup(t->str); - while (setjmp(bc.brkpt)) - if (isbreak) - goto broken; - brkset(&bc); - for (t1 = t->left; i-- && *wp != NULL;) { - setval(vp, *wp++); - rv = execute(t1, pin, pout, 0); - } - brklist = brklist->nextlev; - break; - - case TWHILE: - case TUNTIL: - while (setjmp(bc.brkpt)) - if (isbreak) - goto broken; - brkset(&bc); - t1 = t->left; - while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE)) - rv = execute(t->right, pin, pout, 0); - brklist = brklist->nextlev; - break; - - case TIF: - case TELIF: - if (t->right != NULL) { - rv = !execute(t->left, pin, pout, 0) ? - execute(t->right->left, pin, pout, 0): - execute(t->right->right, pin, pout, 0); - } - break; - - case TCASE: - if ((cp = evalstr(t->str, DOSUB|DOTRIM)) == 0) - cp = ""; - if ((t1 = findcase(t->left, cp)) != NULL) - rv = execute(t1, pin, pout, 0); - break; - - case TBRACE: -/* - if (iopp = t->ioact) - while (*iopp) - if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) { - rv = -1; - break; - } -*/ - if (rv >= 0 && (t1 = t->left)) - rv = execute(t1, pin, pout, 0); - break; - } - -broken: - t->words = wp2; - isbreak = 0; - freehere(areanum); - freearea(areanum); - areanum = a; - if (interactive && intr) { - closeall(); - fail(); - } - if ((i = trapset) != 0) { - trapset = 0; - runtrap(i); - } - return(rv); -} - -static int -forkexec( register struct op *t, int *pin, int *pout, int act, char **wp, int *pforked) -{ - int i, rv; - int (*shcom)() = NULL; - register int f; - char *cp = NULL; - struct ioword **iopp; - int resetsig; - char **owp; - - int *hpin = pin; - int *hpout = pout; - int hforked; - char *hwp; - int hinteractive; - int hintr; - struct brkcon * hbrklist; - int hexecflg; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &pin; - (void) &pout; - (void) ℘ - (void) &shcom; - (void) &cp; - (void) &resetsig; - (void) &owp; -#endif - - owp = wp; - resetsig = 0; - *pforked = 0; - rv = -1; /* system-detected error */ - if (t->type == TCOM) { - while ((cp = *wp++) != NULL) - ; - cp = *wp; - - /* strip all initial assignments */ - /* not correct wrt PATH=yyy command etc */ - if (flag['x']) - echo (cp ? wp: owp); - if (cp == NULL && t->ioact == NULL) { - while ((cp = *owp++) != NULL && assign(cp, COPYV)) - ; - return(setstatus(0)); - } - else if (cp != NULL) - shcom = inbuilt(cp); - } - t->words = wp; - f = act; - if (shcom == NULL && (f & FEXEC) == 0) { - - hpin = pin; - hpout = pout; - hforked = *pforked; - hwp = *wp; - hinteractive = interactive; - hintr = intr; - hbrklist = brklist; - hexecflg = execflg; - - i = vfork(); - if (i != 0) { - /* who wrote this crappy non vfork safe shit? */ - pin = hpin; - pout = hpout; - *pforked = hforked; - *wp = hwp; - interactive = hinteractive; - intr = hintr; - brklist = hbrklist; - execflg = hexecflg; - - *pforked = 0; - if (i == -1) - return(rv); - if (pin != NULL) - closepipe(pin); - return(pout==NULL? setstatus(waitfor(i,0)): 0); - } - - if (interactive) { - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - resetsig = 1; - } - interactive = 0; - intr = 0; - (*pforked)++; - brklist = 0; - execflg = 0; - } - if (owp != NULL) - while ((cp = *owp++) != NULL && assign(cp, COPYV)) - if (shcom == NULL) - export(lookup(cp)); -#ifdef COMPIPE - if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) { - err("piping to/from shell builtins not yet done"); - return(-1); - } -#endif - if (pin != NULL) { - dup2(pin[0], 0); - closepipe(pin); - } - if (pout != NULL) { - dup2(pout[1], 1); - closepipe(pout); - } - if ((iopp = t->ioact) != NULL) { - if (shcom != NULL && shcom != doexec) { - prs(cp); - err(": cannot redirect shell command"); - return(-1); - } - while (*iopp) - if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) - return(rv); - } - if (shcom) - return(setstatus((*shcom)(t))); - /* should use FIOCEXCL */ - for (i=FDBASE; itype == TPAREN) - exit(execute(t->left, NOPIPE, NOPIPE, FEXEC)); - if (wp[0] == NULL) - exit(0); - - cp = rexecve(wp[0], wp, makenv()); - prs(wp[0]); prs(": "); warn(cp); - if (!execflg) - trap[0] = NULL; - leave(); - /* NOTREACHED */ - exit(1); -} - -/* - * 0< 1> are ignored as required - * within pipelines. - */ -static int -iosetup(iop, pipein, pipeout) -register struct ioword *iop; -int pipein, pipeout; -{ - register int u = -1; - char *cp=NULL, *msg; - - if (iop->io_unit == IODEFAULT) /* take default */ - iop->io_unit = iop->io_flag&(IOREAD|IOHERE)? 0: 1; - if (pipein && iop->io_unit == 0) - return(0); - if (pipeout && iop->io_unit == 1) - return(0); - msg = iop->io_flag&(IOREAD|IOHERE)? "open": "create"; - if ((iop->io_flag & IOHERE) == 0) { - cp = iop->io_name; - if ((cp = evalstr(cp, DOSUB|DOTRIM)) == NULL) - return(1); - } - if (iop->io_flag & IODUP) { - if (cp[1] || (!isdigit(*cp) && *cp != '-')) { - prs(cp); - err(": illegal >& argument"); - return(1); - } - if (*cp == '-') - iop->io_flag = IOCLOSE; - iop->io_flag &= ~(IOREAD|IOWRITE); - } - switch (iop->io_flag) { - case IOREAD: - u = open(cp, 0); - break; - - case IOHERE: - case IOHERE|IOXHERE: - u = herein(iop->io_name, iop->io_flag&IOXHERE); - cp = "here file"; - break; - - case IOWRITE|IOCAT: - if ((u = open(cp, 1)) >= 0) { - lseek(u, (long)0, 2); - break; - } - case IOWRITE: - u = creat(cp, 0666); - break; - - case IODUP: - u = dup2(*cp-'0', iop->io_unit); - break; - - case IOCLOSE: - close(iop->io_unit); - return(0); - } - if (u < 0) { - prs(cp); - prs(": cannot "); - warn(msg); - return(1); - } else { - if (u != iop->io_unit) { - dup2(u, iop->io_unit); - close(u); - } - } - return(0); -} - -static void -echo(wp) -register char **wp; -{ - register int i; - - prs("+"); - for (i=0; wp[i]; i++) { - if (i) - prs(" "); - prs(wp[i]); - } - prs("\n"); -} - -static struct op ** -find1case(t, w) -struct op *t; -char *w; -{ - register struct op *t1; - struct op **tp; - register char **wp, *cp; - - if (t == NULL) - return((struct op **)NULL); - if (t->type == TLIST) { - if ((tp = find1case(t->left, w)) != NULL) - return(tp); - t1 = t->right; /* TPAT */ - } else - t1 = t; - for (wp = t1->words; *wp;) - if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp)) - return(&t1->left); - return((struct op **)NULL); -} - -static struct op * -findcase(t, w) -struct op *t; -char *w; -{ - register struct op **tp; - - return((tp = find1case(t, w)) != NULL? *tp: (struct op *)NULL); -} - -/* - * Enter a new loop level (marked for break/continue). - */ -static void -brkset(bc) -struct brkcon *bc; -{ - bc->nextlev = brklist; - brklist = bc; -} - -/* - * Wait for the last process created. - * Print a message for each process found - * that was killed by a signal. - * Ignore interrupt signals while waiting - * unless `canintr' is true. - */ -static int -waitfor(lastpid, canintr) -register int lastpid; -int canintr; -{ - register int pid, rv; - int s; - int oheedint = heedint; - - heedint = 0; - rv = 0; - do { - pid = wait(&s); - if (pid == -1) { - if (errno != EINTR || canintr) - break; - } else { - if ((rv = WAITSIG(s)) != 0) { - if (rv < NSIGNAL) { - if (signame[rv] != NULL) { - if (pid != lastpid) { - prn(pid); - prs(": "); - } - prs(signame[rv]); - } - } else { - if (pid != lastpid) { - prn(pid); - prs(": "); - } - prs("Signal "); prn(rv); prs(" "); - } - if (WAITCORE(s)) - prs(" - core dumped"); - if (rv >= NSIGNAL || signame[rv]) - prs("\n"); - rv = -1; - } else - rv = WAITVAL(s); - } - } while (pid != lastpid); - heedint = oheedint; - if (intr) { - if (interactive) { - if (canintr) - intr = 0; - } else { - if (exstat == 0) exstat = rv; - onintr(0); - } - } - return(rv); -} - -static int -setstatus(s) -register int s; -{ - exstat = s; - setval(lookup("?"), putn(s)); - return(s); -} - -/* - * PATH-searching interface to execve. - * If getenv("PATH") were kept up-to-date, - * execvp might be used. - */ -static char * -rexecve(c, v, envp) -char *c, **v, **envp; -{ - register int i; - register char *sp, *tp; - int eacces = 0, asis = 0; - -#ifdef BB_FEATURE_SH_STANDALONE_SHELL - char *name = c; -#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN - name = get_last_path_component(name); -#endif - optind = 1; - if (find_applet_by_name(name)) { - /* We have to exec here since we vforked. Running - * run_applet_by_name() won't work and bad things - * will happen. */ - execve("/proc/self/exe", v, envp); - execve("busybox", v, envp); - } -#endif - - sp = any('/', c)? "": path->value; - asis = *sp == '\0'; - while (asis || *sp != '\0') { - asis = 0; - tp = e.linep; - for (; *sp != '\0'; tp++) - if ((*tp = *sp++) == ':') { - asis = *sp == '\0'; - break; - } - if (tp != e.linep) - *tp++ = '/'; - for (i = 0; (*tp++ = c[i++]) != '\0';) - ; - - execve(e.linep, v, envp); - switch (errno) { - case ENOEXEC: - *v = e.linep; - tp = *--v; - *v = e.linep; - execve("/bin/sh", v, envp); - *v = tp; - return("no Shell"); - - case ENOMEM: - return("program too big"); - - case E2BIG: - return("argument list too long"); - - case EACCES: - eacces++; - break; - } - } - return(errno==ENOENT ? "not found" : "cannot execute"); -} - -/* - * Run the command produced by generator `f' - * applied to stream `arg'. - */ -static int -run(argp, f) -struct ioarg *argp; -int (*f)(); -{ - struct op *otree; - struct wdblock *swdlist; - struct wdblock *siolist; - jmp_buf ev, rt; - xint *ofail; - int rv; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &rv; -#endif - - areanum++; - swdlist = wdlist; - siolist = iolist; - otree = outtree; - ofail = failpt; - rv = -1; - if (newenv(setjmp(errpt = ev)) == 0) { - wdlist = 0; - iolist = 0; - pushio(argp, f); - e.iobase = e.iop; - yynerrs = 0; - if (setjmp(failpt = rt) == 0 && yyparse() == 0) - rv = execute(outtree, NOPIPE, NOPIPE, 0); - quitenv(); - } - wdlist = swdlist; - iolist = siolist; - failpt = ofail; - outtree = otree; - freearea(areanum--); - return(rv); -} - -/* -------- do.c -------- */ - -/* - * built-in commands: doX - */ - -static int dohelp() -{ - int col; - const struct builtincmd *x; - - printf("\nBuilt-in commands:\n"); - printf("-------------------\n"); - - for (col=0, x = builtincmds; x->builtinfunc != NULL; x++) { - if (!x->name) - continue; - col += printf("%s%s", ((col == 0) ? "\t" : " "), x->name); - if (col > 60) { - printf("\n"); - col = 0; - } - } -#ifdef BB_FEATURE_SH_STANDALONE_SHELL - { - int i; - const struct BB_applet *applet; - extern const struct BB_applet applets[]; - extern const size_t NUM_APPLETS; - - for (i=0, applet = applets; i < NUM_APPLETS; applet++, i++) { - if (!applet->name) - continue; - - col += printf("%s%s", ((col == 0) ? "\t" : " "), - applet->name); - if (col > 60) { - printf("\n"); - col = 0; - } - } - } -#endif - printf("\n\n"); - return EXIT_SUCCESS; -} - - - -static int -dolabel() -{ - return(0); -} - -static int -dochdir(t) -register struct op *t; -{ - register char *cp, *er; - - if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL) - er = ": no home directory"; - else if(chdir(cp) < 0) - er = ": bad directory"; - else - return(0); - prs(cp != NULL? cp: "cd"); - err(er); - return(1); -} - -static int -doshift(t) -register struct op *t; -{ - register int n; - - n = t->words[1]? getn(t->words[1]): 1; - if(dolc < n) { - err("nothing to shift"); - return(1); - } - dolv[n] = dolv[0]; - dolv += n; - dolc -= n; - setval(lookup("#"), putn(dolc)); - return(0); -} - -/* - * execute login and newgrp directly - */ -static int -dologin(t) -struct op *t; -{ - register char *cp; - - if (interactive) { - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - } - cp = rexecve(t->words[0], t->words, makenv()); - prs(t->words[0]); prs(": "); err(cp); - return(1); -} - -static int -doumask(t) -register struct op *t; -{ - register int i, n; - register char *cp; - - if ((cp = t->words[1]) == NULL) { - i = umask(0); - umask(i); - for (n=3*4; (n-=3) >= 0;) - putc('0'+((i>>n)&07), stderr); - putc('\n', stderr); - } else { - for (n=0; *cp>='0' && *cp<='9'; cp++) - n = n*8 + (*cp-'0'); - umask(n); - } - return(0); -} - -static int -doexec(t) -register struct op *t; -{ - register int i; - jmp_buf ex; - xint *ofail; - - t->ioact = NULL; - for(i = 0; (t->words[i]=t->words[i+1]) != NULL; i++) - ; - if (i == 0) - return(1); - execflg = 1; - ofail = failpt; - if (setjmp(failpt = ex) == 0) - execute(t, NOPIPE, NOPIPE, FEXEC); - failpt = ofail; - execflg = 0; - return(1); -} - -static int -dodot(t) -struct op *t; -{ - register int i; - register char *sp, *tp; - char *cp; - - if ((cp = t->words[1]) == NULL) - return(0); - sp = any('/', cp)? ":": path->value; - while (*sp) { - tp = e.linep; - while (*sp && (*tp = *sp++) != ':') - tp++; - if (tp != e.linep) - *tp++ = '/'; - for (i = 0; (*tp++ = cp[i++]) != '\0';) - ; - if ((i = open(e.linep, 0)) >= 0) { - exstat = 0; - next(remap(i)); - return(exstat); - } - } - prs(cp); - err(": not found"); - return(-1); -} - -static int -dowait(t) -struct op *t; -{ - register int i; - register char *cp; - - if ((cp = t->words[1]) != NULL) { - i = getn(cp); - if (i == 0) - return(0); - } else - i = -1; - setstatus(waitfor(i, 1)); - return(0); -} - -static int -doread(t) -struct op *t; -{ - register char *cp, **wp; - register int nb = 0; - register int nl = 0; - - if (t->words[1] == NULL) { - err("Usage: read name ..."); - return(1); - } - for (wp = t->words+1; *wp; wp++) { - for (cp = e.linep; !nl && cp < elinep-1; cp++) - if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) || - (nl = (*cp == '\n')) || - (wp[1] && any(*cp, ifs->value))) - break; - *cp = 0; - if (nb <= 0) - break; - setval(lookup(*wp), e.linep); - } - return(nb <= 0); -} - -static int -doeval(t) -register struct op *t; -{ - return(RUN(awordlist, t->words+1, wdchar)); -} - -static int -dotrap(t) -register struct op *t; -{ - register int n, i; - register int resetsig; - - if (t->words[1] == NULL) { - for (i=0; i<=_NSIG; i++) - if (trap[i]) { - prn(i); - prs(": "); - prs(trap[i]); - prs("\n"); - } - return(0); - } - resetsig = isdigit(*t->words[1]); - for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) { - n = getsig(t->words[i]); - freecell(trap[n]); - trap[n] = 0; - if (!resetsig) { - if (*t->words[1] != '\0') { - trap[n] = strsave(t->words[1], 0); - setsig(n, sig); - } else - setsig(n, SIG_IGN); - } else { - if (interactive) - if (n == SIGINT) - setsig(n, onintr); - else - setsig(n, n == SIGQUIT ? SIG_IGN - : SIG_DFL); - else - setsig(n, SIG_DFL); - } - } - return(0); -} - -static int -getsig(s) -char *s; -{ - register int n; - - if ((n = getn(s)) < 0 || n > _NSIG) { - err("trap: bad signal number"); - n = 0; - } - return(n); -} - -static void -setsig( register int n, void (*f)(int)) -{ - if (n == 0) - return; - if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) { - ourtrap[n] = 1; - signal(n, f); - } -} - -static int -getn(as) -char *as; -{ - register char *s; - register int n, m; - - s = as; - m = 1; - if (*s == '-') { - m = -1; - s++; - } - for (n = 0; isdigit(*s); s++) - n = (n*10) + (*s-'0'); - if (*s) { - prs(as); - err(": bad number"); - } - return(n*m); -} - -static int -dobreak(t) -struct op *t; -{ - return(brkcontin(t->words[1], 1)); -} - -static int -docontinue(t) -struct op *t; -{ - return(brkcontin(t->words[1], 0)); -} - -static int -brkcontin(cp, val) -register char *cp; -int val; -{ - register struct brkcon *bc; - register int nl; - - nl = cp == NULL? 1: getn(cp); - if (nl <= 0) - nl = 999; - do { - if ((bc = brklist) == NULL) - break; - brklist = bc->nextlev; - } while (--nl); - if (nl) { - err("bad break/continue level"); - return(1); - } - isbreak = val; - longjmp(bc->brkpt, 1); - /* NOTREACHED */ -} - -static int -doexit(t) -struct op *t; -{ - register char *cp; - - execflg = 0; - if ((cp = t->words[1]) != NULL) - setstatus(getn(cp)); - leave(); - /* NOTREACHED */ - return(0); -} - -static int -doexport(t) -struct op *t; -{ - rdexp(t->words+1, export, EXPORT); - return(0); -} - -static int -doreadonly(t) -struct op *t; -{ - rdexp(t->words+1, ronly, RONLY); - return(0); -} - -static void -rdexp(wp, f, key) -register char **wp; -void (*f)(); -int key; -{ - if (*wp != NULL) { - for (; *wp != NULL; wp++) { - if (isassign(*wp)) { - char *cp; - assign(*wp, COPYV); - for (cp = *wp; *cp != '='; cp++) - ; - *cp = '\0'; - } - if (checkname(*wp)) - (*f)(lookup(*wp)); - else - badid(*wp); - } - } else - putvlist(key, 1); -} - -static void -badid(s) -register char *s; -{ - prs(s); - err(": bad identifier"); -} - -static int -doset(t) -register struct op *t; -{ - register struct var *vp; - register char *cp; - register int n; - - if ((cp = t->words[1]) == NULL) { - for (vp = vlist; vp; vp = vp->next) - varput(vp->name, 1); - return(0); - } - if (*cp == '-') { - /* bad: t->words++; */ - for(n = 0; (t->words[n]=t->words[n+1]) != NULL; n++) - ; - if (*++cp == 0) - flag['x'] = flag['v'] = 0; - else - for (; *cp; cp++) - switch (*cp) { - case 'e': - if (!interactive) - flag['e']++; - break; - - default: - if (*cp>='a' && *cp<='z') - flag[(int)*cp]++; - break; - } - setdash(); - } - if (t->words[1]) { - t->words[0] = dolv[0]; - for (n=1; t->words[n]; n++) - setarea((char *)t->words[n], 0); - dolc = n-1; - dolv = t->words; - setval(lookup("#"), putn(dolc)); - setarea((char *)(dolv-1), 0); - } - return(0); -} - -static void -varput(s, out) -register char *s; -int out; -{ - if (isalnum(*s) || *s == '_') { - write(out, s, strlen(s)); - write(out, "\n", 1); - } -} - - -/* - * Copyright (c) 1999 Herbert Xu - * This file contains code for the times builtin. - */ -static int dotimes () -{ - struct tms buf; - long int clk_tck = sysconf(_SC_CLK_TCK); - - times(&buf); - printf("%dm%fs %dm%fs\n%dm%fs %dm%fs\n", - (int) (buf.tms_utime / clk_tck / 60), - ((double) buf.tms_utime) / clk_tck, - (int) (buf.tms_stime / clk_tck / 60), - ((double) buf.tms_stime) / clk_tck, - (int) (buf.tms_cutime / clk_tck / 60), - ((double) buf.tms_cutime) / clk_tck, - (int) (buf.tms_cstime / clk_tck / 60), - ((double) buf.tms_cstime) / clk_tck); - return 0; -} - - -static int (*inbuilt(char *s))() -{ - const struct builtincmd *bp; - - for (bp = builtincmds; bp->name != NULL; bp++) - if (strcmp(bp->name, s) == 0) - return(bp->builtinfunc); - - return((int(*)())NULL); -} - -/* -------- eval.c -------- */ - -/* - * ${} - * `command` - * blank interpretation - * quoting - * glob - */ - -static char ** eval( char **ap, int f) -{ - struct wdblock *wb; - char **wp; - char **wf; - jmp_buf ev; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) ℘ - (void) ≈ -#endif - wp = NULL; - wb = NULL; - wf = NULL; - if (newenv(setjmp(errpt = ev)) == 0) { - while (*ap && isassign(*ap)) - expand(*ap++, &wb, f & ~DOGLOB); - if (flag['k']) { - for (wf = ap; *wf; wf++) { - if (isassign(*wf)) - expand(*wf, &wb, f & ~DOGLOB); - } - } - for (wb = addword((char *)0, wb); *ap; ap++) { - if (!flag['k'] || !isassign(*ap)) - expand(*ap, &wb, f & ~DOKEY); - } - wb = addword((char *)0, wb); - wp = getwords(wb); - quitenv(); - } else - gflg = 1; - return(gflg? (char **)NULL: wp); -} - -/* - * Make the exported environment from the exported - * names in the dictionary. Keyword assignments - * will already have been done. - */ -static char ** -makenv() - -{ - register struct wdblock *wb; - register struct var *vp; - - wb = NULL; - for (vp = vlist; vp; vp = vp->next) - if (vp->status & EXPORT) - wb = addword(vp->name, wb); - wb = addword((char *)0, wb); - return(getwords(wb)); -} - -static char * -evalstr(cp, f) -register char *cp; -int f; -{ - struct wdblock *wb; - - wb = NULL; - if (expand(cp, &wb, f)) { - if (wb == NULL || wb->w_nword == 0 || (cp = wb->w_words[0]) == NULL) - cp = ""; - DELETE(wb); - } else - cp = NULL; - return(cp); -} - -static int -expand( char *cp, register struct wdblock **wbp, int f) -{ - jmp_buf ev; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &cp; -#endif - gflg = 0; - if (cp == NULL) - return(0); - if (!anys("$`'\"", cp) && - !anys(ifs->value, cp) && - ((f&DOGLOB)==0 || !anys("[*?", cp))) { - cp = strsave(cp, areanum); - if (f & DOTRIM) - unquote(cp); - *wbp = addword(cp, *wbp); - return(1); - } - if (newenv(setjmp(errpt = ev)) == 0) { - PUSHIO(aword, cp, strchar); - e.iobase = e.iop; - while ((cp = blank(f)) && gflg == 0) { - e.linep = cp; - cp = strsave(cp, areanum); - if ((f&DOGLOB) == 0) { - if (f & DOTRIM) - unquote(cp); - *wbp = addword(cp, *wbp); - } else - *wbp = glob(cp, *wbp); - } - quitenv(); - } else - gflg = 1; - return(gflg == 0); -} - -/* - * Blank interpretation and quoting - */ -static char * -blank(f) -int f; -{ - register int c, c1; - register char *sp; - int scanequals, foundequals; - - sp = e.linep; - scanequals = f & DOKEY; - foundequals = 0; - -loop: - switch (c = subgetc('"', foundequals)) { - case 0: - if (sp == e.linep) - return(0); - *e.linep++ = 0; - return(sp); - - default: - if (f & DOBLANK && any(c, ifs->value)) - goto loop; - break; - - case '"': - case '\'': - scanequals = 0; - if (INSUB()) - break; - for (c1 = c; (c = subgetc(c1, 1)) != c1;) { - if (c == 0) - break; - if (c == '\'' || !any(c, "$`\"")) - c |= QUOTE; - *e.linep++ = c; - } - c = 0; - } - unget(c); - if (!isalpha(c) && c != '_') - scanequals = 0; - for (;;) { - c = subgetc('"', foundequals); - if (c == 0 || - f & (DOBLANK && any(c, ifs->value)) || - (!INSUB() && any(c, "\"'"))) { - scanequals = 0; - unget(c); - if (any(c, "\"'")) - goto loop; - break; - } - if (scanequals) { - if (c == '=') { - foundequals = 1; - scanequals = 0; - } - else if (!isalnum(c) && c != '_') - scanequals = 0; - } - *e.linep++ = c; - } - *e.linep++ = 0; - return(sp); -} - -/* - * Get characters, substituting for ` and $ - */ -static int -subgetc(ec, quoted) -register int ec; -int quoted; -{ - register char c; - -again: - c = my_getc(ec); - if (!INSUB() && ec != '\'') { - if (c == '`') { - if (grave(quoted) == 0) - return(0); - e.iop->task = XGRAVE; - goto again; - } - if (c == '$' && (c = dollar(quoted)) == 0) { - e.iop->task = XDOLL; - goto again; - } - } - return(c); -} - -/* - * Prepare to generate the string returned by ${} substitution. - */ -static int -dollar(quoted) -int quoted; -{ - int otask; - struct io *oiop; - char *dolp; - register char *s, c, *cp=NULL; - struct var *vp; - - c = readc(); - s = e.linep; - if (c != '{') { - *e.linep++ = c; - if (isalpha(c) || c == '_') { - while ((c = readc())!=0 && (isalnum(c) || c == '_')) - if (e.linep < elinep) - *e.linep++ = c; - unget(c); - } - c = 0; - } else { - oiop = e.iop; - otask = e.iop->task; - e.iop->task = XOTHER; - while ((c = subgetc('"', 0))!=0 && c!='}' && c!='\n') - if (e.linep < elinep) - *e.linep++ = c; - if (oiop == e.iop) - e.iop->task = otask; - if (c != '}') { - err("unclosed ${"); - gflg++; - return(c); - } - } - if (e.linep >= elinep) { - err("string in ${} too long"); - gflg++; - e.linep -= 10; - } - *e.linep = 0; - if (*s) - for (cp = s+1; *cp; cp++) - if (any(*cp, "=-+?")) { - c = *cp; - *cp++ = 0; - break; - } - if (s[1] == 0 && (*s == '*' || *s == '@')) { - if (dolc > 1) { - /* currently this does not distinguish $* and $@ */ - /* should check dollar */ - e.linep = s; - PUSHIO(awordlist, dolv+1, dolchar); - return(0); - } else { /* trap the nasty ${=} */ - s[0] = '1'; - s[1] = 0; - } - } - vp = lookup(s); - if ((dolp = vp->value) == null) { - switch (c) { - case '=': - if (isdigit(*s)) { - err("cannot use ${...=...} with $n"); - gflg++; - break; - } - setval(vp, cp); - dolp = vp->value; - break; - - case '-': - dolp = strsave(cp, areanum); - break; - - case '?': - if (*cp == 0) { - prs("missing value for "); - err(s); - } else - err(cp); - gflg++; - break; - } - } else if (c == '+') - dolp = strsave(cp, areanum); - if (flag['u'] && dolp == null) { - prs("unset variable: "); - err(s); - gflg++; - } - e.linep = s; - PUSHIO(aword, dolp, quoted ? qstrchar : strchar); - return(0); -} - -/* - * Run the command in `...` and read its output. - */ -static int -grave(quoted) -int quoted; -{ - register int i; - char *cp; - int pf[2]; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &cp; -#endif - for (cp = e.iop->argp->aword; *cp != '`'; cp++) - if (*cp == 0) { - err("no closing `"); - return(0); - } - if (openpipe(pf) < 0) - return(0); - if ((i = vfork()) == -1) { - closepipe(pf); - err("try again"); - return(0); - } - if (i != 0) { - e.iop->argp->aword = ++cp; - close(pf[1]); - PUSHIO(afile, remap(pf[0]), quoted? qgravechar: gravechar); - return(1); - } - *cp = 0; - /* allow trapped signals */ - for (i=0; i<=_NSIG; i++) - if (ourtrap[i] && signal(i, SIG_IGN) != SIG_IGN) - signal(i, SIG_DFL); - dup2(pf[1], 1); - closepipe(pf); - flag['e'] = 0; - flag['v'] = 0; - flag['n'] = 0; - cp = strsave(e.iop->argp->aword, 0); - areanum = 1; - freehere(areanum); - freearea(areanum); /* free old space */ - e.oenv = NULL; - e.iop = (e.iobase = iostack) - 1; - unquote(cp); - interactive = 0; - PUSHIO(aword, cp, nlchar); - onecommand(); - exit(1); -} - -static char * -unquote(as) -register char *as; -{ - register char *s; - - if ((s = as) != NULL) - while (*s) - *s++ &= ~QUOTE; - return(as); -} - -/* -------- glob.c -------- */ - -/* - * glob - */ - -#define scopy(x) strsave((x), areanum) -#define BLKSIZ 512 -#define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent)) - -static struct wdblock *cl, *nl; -static char spcl[] = "[?*"; - -static struct wdblock * -glob(cp, wb) -char *cp; -struct wdblock *wb; -{ - register int i; - register char *pp; - - if (cp == 0) - return(wb); - i = 0; - for (pp = cp; *pp; pp++) - if (any(*pp, spcl)) - i++; - else if (!any(*pp & ~QUOTE, spcl)) - *pp &= ~QUOTE; - if (i != 0) { - for (cl = addword(scopy(cp), (struct wdblock *)0); anyspcl(cl); cl = nl) { - nl = newword(cl->w_nword*2); - for(i=0; iw_nword; i++) { /* for each argument */ - for (pp = cl->w_words[i]; *pp; pp++) - if (any(*pp, spcl)) { - globname(cl->w_words[i], pp); - break; - } - if (*pp == '\0') - nl = addword(scopy(cl->w_words[i]), nl); - } - for(i=0; iw_nword; i++) - DELETE(cl->w_words[i]); - DELETE(cl); - } - for(i=0; iw_nword; i++) - unquote(cl->w_words[i]); - glob0((char *)cl->w_words, cl->w_nword, sizeof(char *), xstrcmp); - if (cl->w_nword) { - for (i=0; iw_nword; i++) - wb = addword(cl->w_words[i], wb); - DELETE(cl); - return(wb); - } - } - wb = addword(unquote(cp), wb); - return(wb); -} - -static void -globname(we, pp) -char *we; -register char *pp; -{ - register char *np, *cp; - char *name, *gp, *dp; - int k; - DIR *dirp; - struct dirent *de; - char dname[NAME_MAX+1]; - struct stat dbuf; - - for (np = we; np != pp; pp--) - if (pp[-1] == '/') - break; - for (dp = cp = space((int)(pp-np)+3); np < pp;) - *cp++ = *np++; - *cp++ = '.'; - *cp = '\0'; - for (gp = cp = space(strlen(pp)+1); *np && *np != '/';) - *cp++ = *np++; - *cp = '\0'; - dirp = opendir(dp); - if (dirp == 0) { - DELETE(dp); - DELETE(gp); - return; - } - dname[NAME_MAX] = '\0'; - while ((de=readdir(dirp))!=NULL) { - /* XXX Hmmm... What this could be? (abial) */ - /* - if (ent[j].d_ino == 0) - continue; - */ - strncpy(dname, de->d_name, NAME_MAX); - if (dname[0] == '.') - if (*gp != '.') - continue; - for(k=0; kw_words; - for (i=0; iw_nword; i++) - if (anys(spcl, *wd++)) - return(1); - return(0); -} - -static int -xstrcmp(p1, p2) -char *p1, *p2; -{ - return(strcmp(*(char **)p1, *(char **)p2)); -} - -/* -------- word.c -------- */ - -static struct wdblock * -newword(nw) -register int nw; -{ - register struct wdblock *wb; - - wb = (struct wdblock *) space(sizeof(*wb) + nw*sizeof(char *)); - wb->w_bsize = nw; - wb->w_nword = 0; - return(wb); -} - -static struct wdblock * -addword(wd, wb) -char *wd; -register struct wdblock *wb; -{ - register struct wdblock *wb2; - register int nw; - - if (wb == NULL) - wb = newword(NSTART); - if ((nw = wb->w_nword) >= wb->w_bsize) { - wb2 = newword(nw * 2); - memcpy((char *)wb2->w_words, (char *)wb->w_words, nw*sizeof(char *)); - wb2->w_nword = nw; - DELETE(wb); - wb = wb2; - } - wb->w_words[wb->w_nword++] = wd; - return(wb); -} -static -char ** -getwords(wb) -register struct wdblock *wb; -{ - register char **wd; - register int nb; - - if (wb == NULL) - return((char **)NULL); - if (wb->w_nword == 0) { - DELETE(wb); - return((char **)NULL); - } - wd = (char **) space(nb = sizeof(*wd) * wb->w_nword); - memcpy((char *)wd, (char *)wb->w_words, nb); - DELETE(wb); /* perhaps should done by caller */ - return(wd); -} - -int (*func)(char *, char *); -int globv; - -static void -glob0(a0, a1, a2, a3) -char *a0; -unsigned a1; -int a2; -int (*a3) (char *, char *); -{ - func = a3; - globv = a2; - glob1(a0, a0 + a1 * a2); -} - -static void -glob1(base, lim) -char *base, *lim; -{ - register char *i, *j; - int v2; - char *lptr, *hptr; - int c; - unsigned n; - - - v2 = globv; - -top: - if ((n=(int)(lim-base)) <= v2) - return; - n = v2 * (n / (2*v2)); - hptr = lptr = base+n; - i = base; - j = lim-v2; - for(;;) { - if (i < lptr) { - if ((c = (*func)(i, lptr)) == 0) { - glob2(i, lptr -= v2); - continue; - } - if (c < 0) { - i += v2; - continue; - } - } - -begin: - if (j > hptr) { - if ((c = (*func)(hptr, j)) == 0) { - glob2(hptr += v2, j); - goto begin; - } - if (c > 0) { - if (i == lptr) { - glob3(i, hptr += v2, j); - i = lptr += v2; - goto begin; - } - glob2(i, j); - j -= v2; - i += v2; - continue; - } - j -= v2; - goto begin; - } - - - if (i == lptr) { - if (lptr-base >= lim-hptr) { - glob1(hptr+v2, lim); - lim = lptr; - } else { - glob1(base, lptr); - base = hptr+v2; - } - goto top; - } - - - glob3(j, lptr -= v2, i); - j = hptr -= v2; - } -} - -static void -glob2(i, j) -char *i, *j; -{ - register char *index1, *index2, c; - int m; - - m = globv; - index1 = i; - index2 = j; - do { - c = *index1; - *index1++ = *index2; - *index2++ = c; - } while(--m); -} - -static void -glob3(i, j, k) -char *i, *j, *k; -{ - register char *index1, *index2, *index3; - int c; - int m; - - m = globv; - index1 = i; - index2 = j; - index3 = k; - do { - c = *index1; - *index1++ = *index3; - *index3++ = *index2; - *index2++ = c; - } while(--m); -} - -/* -------- io.c -------- */ - -/* - * shell IO - */ - -static int my_getc( int ec) -{ - register int c; - - if(e.linep > elinep) { - while((c=readc()) != '\n' && c) - ; - err("input line too long"); - gflg++; - return(c); - } - c = readc(); - if (ec != '\'' && e.iop->task != XGRAVE) { - if(c == '\\') { - c = readc(); - if (c == '\n' && ec != '\"') - return(my_getc(ec)); - c |= QUOTE; - } - } - return(c); -} - -static void -unget(c) -int c; -{ - if (e.iop >= e.iobase) - e.iop->peekc = c; -} - -static int -eofc() - -{ - return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0); -} - -static int -readc() -{ - register int c; - - for (; e.iop >= e.iobase; e.iop--) - if ((c = e.iop->peekc) != '\0') { - e.iop->peekc = 0; - return(c); - } - else { - if (e.iop->prev != 0) { - if ((c = (*e.iop->iofn)(e.iop->argp, e.iop)) != '\0') { - if (c == -1) { - e.iop++; - continue; - } - if (e.iop == iostack) - ioecho(c); - return(e.iop->prev = c); - } - else if (e.iop->task == XIO && e.iop->prev != '\n') { - e.iop->prev = 0; - if (e.iop == iostack) - ioecho('\n'); - return '\n'; - } - } - if (e.iop->task == XIO) { - if (multiline) - return e.iop->prev = 0; - if (interactive && e.iop == iostack+1) { -#ifdef BB_FEATURE_COMMAND_EDITING - current_prompt=prompt->value; -#else - prs(prompt->value); -#endif - } - } - } - if (e.iop >= iostack) - return(0); - leave(); - /* NOTREACHED */ - return(0); -} - -static void -ioecho(c) -char c; -{ - if (flag['v']) - write(2, &c, sizeof c); -} - -static void -pushio(argp, fn) -struct ioarg *argp; -int (*fn)(); -{ - if (++e.iop >= &iostack[NPUSH]) { - e.iop--; - err("Shell input nested too deeply"); - gflg++; - return; - } - e.iop->iofn = fn; - - if (argp->afid != AFID_NOBUF) - e.iop->argp = argp; - else { - e.iop->argp = ioargstack + (e.iop - iostack); - *e.iop->argp = *argp; - e.iop->argp->afbuf = e.iop == &iostack[0] ? &mainbuf : &sharedbuf; - if (isatty(e.iop->argp->afile) == 0 && - (e.iop == &iostack[0] || - lseek(e.iop->argp->afile, 0L, 1) != -1)) { - if (++bufid == AFID_NOBUF) - bufid = AFID_ID; - e.iop->argp->afid = bufid; - } - } - - e.iop->prev = ~'\n'; - e.iop->peekc = 0; - e.iop->xchar = 0; - e.iop->nlcount = 0; - if (fn == filechar || fn == linechar) - e.iop->task = XIO; - else if (fn == gravechar || fn == qgravechar) - e.iop->task = XGRAVE; - else - e.iop->task = XOTHER; -} - -static struct io * -setbase(ip) -struct io *ip; -{ - register struct io *xp; - - xp = e.iobase; - e.iobase = ip; - return(xp); -} - -/* - * Input generating functions - */ - -/* - * Produce the characters of a string, then a newline, then EOF. - */ -static int -nlchar(ap) -register struct ioarg *ap; -{ - register int c; - - if (ap->aword == NULL) - return(0); - if ((c = *ap->aword++) == 0) { - ap->aword = NULL; - return('\n'); - } - return(c); -} - -/* - * Given a list of words, produce the characters - * in them, with a space after each word. - */ -static int -wdchar(ap) -register struct ioarg *ap; -{ - register char c; - register char **wl; - - if ((wl = ap->awordlist) == NULL) - return(0); - if (*wl != NULL) { - if ((c = *(*wl)++) != 0) - return(c & 0177); - ap->awordlist++; - return(' '); - } - ap->awordlist = NULL; - return('\n'); -} - -/* - * Return the characters of a list of words, - * producing a space between them. - */ -static int -dolchar(ap) -register struct ioarg *ap; -{ - register char *wp; - - if ((wp = *ap->awordlist++) != NULL) { - PUSHIO(aword, wp, *ap->awordlist == NULL? strchar: xxchar); - return(-1); - } - return(0); -} - -static int -xxchar(ap) -register struct ioarg *ap; -{ - register int c; - - if (ap->aword == NULL) - return(0); - if ((c = *ap->aword++) == '\0') { - ap->aword = NULL; - return(' '); - } - return(c); -} - -/* - * Produce the characters from a single word (string). - */ -static int -strchar(ap) -register struct ioarg *ap; -{ - register int c; - - if (ap->aword == NULL || (c = *ap->aword++) == 0) - return(0); - return(c); -} - -/* - * Produce quoted characters from a single word (string). - */ -static int -qstrchar(ap) -register struct ioarg *ap; -{ - register int c; - - if (ap->aword == NULL || (c = *ap->aword++) == 0) - return(0); - return(c|QUOTE); -} - -/* - * Return the characters from a file. - */ -static int -filechar(ap) -register struct ioarg *ap; -{ - register int i; - char c; - struct iobuf *bp = ap->afbuf; - - if (ap->afid != AFID_NOBUF) { - if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) { - if (i) - lseek(ap->afile, ap->afpos, 0); - i = safe_read(ap->afile, bp->buf, sizeof(bp->buf)); - if (i <= 0) { - closef(ap->afile); - return 0; - } - bp->id = ap->afid; - bp->ebufp = (bp->bufp = bp->buf) + i; - } - ap->afpos++; - return *bp->bufp++ & 0177; - } - -#ifdef BB_FEATURE_COMMAND_EDITING - if (interactive) { - static char mycommand[BUFSIZ]; - static int position = 0, size = 0; - - while (size == 0 || position >= size) { - cmdedit_read_input(current_prompt, mycommand); - size = strlen(mycommand); - position = 0; - } - c = mycommand[position]; - position++; - return(c); - } else -#endif - { - i = safe_read(ap->afile, &c, sizeof(c)); - return(i == sizeof(c)? c&0177: (closef(ap->afile), 0)); - } -} - -/* - * Return the characters from a here temp file. - */ -static int -herechar(ap) -register struct ioarg *ap; -{ - char c; - - - if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) { - close(ap->afile); - c = 0; - } - return (c); - -} - -/* - * Return the characters produced by a process (`...`). - * Quote them if required, and remove any trailing newline characters. - */ -static int -gravechar(ap, iop) -struct ioarg *ap; -struct io *iop; -{ - register int c; - - if ((c = qgravechar(ap, iop)&~QUOTE) == '\n') - c = ' '; - return(c); -} - -static int -qgravechar(ap, iop) -register struct ioarg *ap; -struct io *iop; -{ - register int c; - - if (iop->xchar) { - if (iop->nlcount) { - iop->nlcount--; - return('\n'|QUOTE); - } - c = iop->xchar; - iop->xchar = 0; - } else if ((c = filechar(ap)) == '\n') { - iop->nlcount = 1; - while ((c = filechar(ap)) == '\n') - iop->nlcount++; - iop->xchar = c; - if (c == 0) - return(c); - iop->nlcount--; - c = '\n'; - } - return(c!=0? c|QUOTE: 0); -} - -/* - * Return a single command (usually the first line) from a file. - */ -static int -linechar(ap) -register struct ioarg *ap; -{ - register int c; - - if ((c = filechar(ap)) == '\n') { - if (!multiline) { - closef(ap->afile); - ap->afile = -1; /* illegal value */ - } - } - return(c); -} - -static void -prs(s) -register char *s; -{ - if (*s) - write(2, s, strlen(s)); -} - -static void -prn(u) -unsigned u; -{ - prs(itoa(u, 0)); -} - -static void -closef(i) -register int i; -{ - if (i > 2) - close(i); -} - -static void -closeall() -{ - register int u; - - for (u=NUFILE; u= 0 && fd < e.iofd); - for (i=0; ih_tag = evalstr(s, DOSUB); - if (h->h_tag == 0) - return; - h->h_iop = iop; - iop->io_name = 0; - h->h_next = NULL; - if (inhere == 0) - inhere = h; - else - for (lh = inhere; lh!=NULL; lh = lh->h_next) - if (lh->h_next == 0) { - lh->h_next = h; - break; - } - iop->io_flag |= IOHERE|IOXHERE; - for (s = h->h_tag; *s; s++) - if (*s & QUOTE) { - iop->io_flag &= ~ IOXHERE; - *s &= ~ QUOTE; - } - h->h_dosub = iop->io_flag & IOXHERE; -} - -static void -gethere() -{ - register struct here *h, *hp; - - /* Scan here files first leaving inhere list in place */ - for (hp = h = inhere; h != NULL; hp = h, h = h->h_next) - readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub? 0: '\''); - - /* Make inhere list active - keep list intact for scraphere */ - if (hp != NULL) { - hp->h_next = acthere; - acthere = inhere; - inhere = NULL; - } -} - -static void -readhere(name, s, ec) -char **name; -register char *s; -int ec; -{ - int tf; - char tname[30] = ".msh_XXXXXX"; - register int c; - jmp_buf ev; - char myline [LINELIM+1]; - char *thenext; - - tf = mkstemp(tname); - if (tf < 0) - return; - *name = strsave(tname, areanum); - if (newenv(setjmp(errpt = ev)) != 0) - unlink(tname); - else { - pushio(e.iop->argp, e.iop->iofn); - e.iobase = e.iop; - for (;;) { - if (interactive && e.iop <= iostack) { -#ifdef BB_FEATURE_COMMAND_EDITING - current_prompt=cprompt->value; -#else - prs(cprompt->value); -#endif - } - thenext = myline; - while ((c = my_getc(ec)) != '\n' && c) { - if (ec == '\'') - c &= ~ QUOTE; - if (thenext >= &myline[LINELIM]) { - c = 0; - break; - } - *thenext++ = c; - } - *thenext = 0; - if (strcmp(s, myline) == 0 || c == 0) - break; - *thenext++ = '\n'; - write (tf, myline, (int)(thenext-myline)); - } - if (c == 0) { - prs("here document `"); prs(s); err("' unclosed"); - } - quitenv(); - } - close(tf); -} - -/* - * open here temp file. - * if unquoted here, expand here temp file into second temp file. - */ -static int -herein(hname, xdoll) -char *hname; -int xdoll; -{ - register int hf; - int tf; - -#if __GNUC__ - /* Avoid longjmp clobbering */ - (void) &tf; -#endif - if (hname == 0) - return(-1); - hf = open(hname, 0); - if (hf < 0) - return (-1); - if (xdoll) { - char c; - char tname[30] = ".msh_XXXXXX"; - jmp_buf ev; - - tf = mkstemp(tname); - if (tf < 0) - return (-1); - if (newenv(setjmp(errpt = ev)) == 0) { - PUSHIO(afile, hf, herechar); - setbase(e.iop); - while ((c = subgetc(0, 0)) != 0) { - c &= ~ QUOTE; - write(tf, &c, sizeof c); - } - quitenv(); - } else - unlink(tname); - close(tf); - tf = open(tname, 0); - unlink(tname); - return (tf); - } else - return (hf); -} - -static void -scraphere() -{ - register struct here *h; - - for (h = inhere; h != NULL; h = h->h_next) { - if (h->h_iop && h->h_iop->io_name) - unlink(h->h_iop->io_name); - } - inhere = NULL; -} - -/* unlink here temp files before a freearea(area) */ -static void -freehere(area) -int area; -{ - register struct here *h, *hl; - - hl = NULL; - for (h = acthere; h != NULL; h = h->h_next) - if (getarea((char *) h) >= area) { - if (h->h_iop->io_name != NULL) - unlink(h->h_iop->io_name); - if (hl == NULL) - acthere = h->h_next; - else - hl->h_next = h->h_next; - } else - hl = h; -} - - - -/* - * 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. - * - */ - diff --git a/busybox/sleep.c b/busybox/sleep.c deleted file mode 100644 index 3bcab88ee..000000000 --- a/busybox/sleep.c +++ /dev/null @@ -1,38 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini sleep implementation for busybox - * - * - * 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 - * - */ - -#include -#include -#include -#include "busybox.h" - -extern int sleep_main(int argc, char **argv) -{ - if ((argc < 2) || (**(argv + 1) == '-')) { - show_usage(); - } - - if (sleep(atoi(*(++argv))) != 0) - perror_msg_and_die("sleep"); - return EXIT_SUCCESS; -} diff --git a/busybox/sort.c b/busybox/sort.c deleted file mode 100644 index 4f4979cc5..000000000 --- a/busybox/sort.c +++ /dev/null @@ -1,106 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini sort implementation for busybox - * - * - * Copyright (C) 2000 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 - * - */ - -#include -#include -#include -#include "busybox.h" - -static int compare_ascii(const void *x, const void *y) -{ - return strcmp(*(char **)x, *(char **)y); -} - -static int compare_numeric(const void *x, const void *y) -{ - int z = atoi(*(char **)x) - atoi(*(char **)y); - return z ? z : strcmp(*(char **)x, *(char **)y); -} - -int sort_main(int argc, char **argv) -{ - FILE *fp; - char *line, **lines = NULL; - int i, opt, nlines = 0; - int (*compare)(const void *, const void *) = compare_ascii; -#ifdef BB_FEATURE_SORT_REVERSE - int reverse = FALSE; -#endif -#ifdef BB_FEATURE_SORT_UNIQUE - int unique = FALSE; -#endif - - while ((opt = getopt(argc, argv, "nru")) != -1) { - switch (opt) { - case 'n': - compare = compare_numeric; - break; -#ifdef BB_FEATURE_SORT_REVERSE - case 'r': - reverse = TRUE; - break; -#endif -#ifdef BB_FEATURE_SORT_UNIQUE - case 'u': - unique = TRUE; - break; -#endif - default: - show_usage(); - } - } - - /* read the input */ - for (i = optind; i == optind || i < argc; i++) { - if (argv[i] == NULL) - fp = stdin; - else - fp = xfopen(argv[i], "r"); - - while ((line = get_line_from_file(fp)) != NULL) { - lines = xrealloc(lines, sizeof(char *) * (nlines + 1)); - chomp(line); - lines[nlines++] = line; - } - } - - /* sort it */ - qsort(lines, nlines, sizeof(char *), compare); - - /* print it */ -#ifdef BB_FEATURE_SORT_REVERSE - if (reverse) { - for (i = --nlines; 0 <= i; i--) -#ifdef BB_FEATURE_SORT_UNIQUE - if((!unique) || (i == nlines) || (strcmp(lines[i + 1], lines[i]))) -#endif - puts(lines[i]); - } else -#endif - for (i = 0; i < nlines; i++) -#ifdef BB_FEATURE_SORT_UNIQUE - if((!unique) || (!i) || (strcmp(lines[i - 1], lines[i]))) -#endif - puts(lines[i]); - return EXIT_SUCCESS; -} diff --git a/busybox/stty.c b/busybox/stty.c deleted file mode 100644 index 2e00a496d..000000000 --- a/busybox/stty.c +++ /dev/null @@ -1,1376 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* 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. */ - -/* Usage: stty [-ag] [-F device] [setting...] - - Options: - -a Write all current settings to stdout in human-readable form. - -g Write all current settings to stdout in stty-readable form. - -F Open and use the specified device instead of stdin - - If no args are given, write to stdout the baud rate and settings that - have been changed from their defaults. Mode reading and changes - are done on the specified device, or stdin if none was specified. - - David MacKenzie - - Special for busybox ported by Vladimir Oleynik 2001 - - */ - -//#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) - - -#ifndef _POSIX_VDISABLE -# define _POSIX_VDISABLE ((unsigned char) 0) -#endif - -#define Control(c) ((c) & 0x1f) -/* Canonical values for control characters. */ -#ifndef CINTR -# define CINTR Control ('c') -#endif -#ifndef CQUIT -# define CQUIT 28 -#endif -#ifndef CERASE -# define CERASE 127 -#endif -#ifndef CKILL -# define CKILL Control ('u') -#endif -#ifndef CEOF -# define CEOF Control ('d') -#endif -#ifndef CEOL -# define CEOL _POSIX_VDISABLE -#endif -#ifndef CSTART -# define CSTART Control ('q') -#endif -#ifndef CSTOP -# define CSTOP Control ('s') -#endif -#ifndef CSUSP -# 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. */ -#if defined(VSUSP) && !defined(VSWTCH) -# define VSWTCH VSUSP -# define CSWTCH CSUSP -#endif -#if defined(VSWTCH) && !defined(CSWTCH) -# 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__) -# undef CSWTCH -# define CSWTCH _POSIX_VDISABLE -#endif - -#if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */ -# define VWERASE VWERSE -#endif -#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') -#endif -#if defined(VWERASE) && !defined(CWERASE) -# define CWERASE Control ('w') -#endif -#if defined(VLNEXT) && !defined(CLNEXT) -# define CLNEXT Control ('v') -#endif -#if defined(VDISCARD) && !defined(VFLUSHO) -# define VFLUSHO VDISCARD -#endif -#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */ -# define VFLUSHO VFLUSH -#endif -#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */ -# define ECHOCTL CTLECH -#endif -#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */ -# define ECHOCTL TCTLECH -#endif -#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */ -# define ECHOKE CRTKIL -#endif -#if defined(VFLUSHO) && !defined(CFLUSHO) -# define CFLUSHO Control ('o') -#endif -#if defined(VSTATUS) && !defined(CSTATUS) -# define CSTATUS Control ('t') -#endif - -/* Which speeds to set. */ -enum speed_setting { - input_speed, output_speed, both_speeds -}; - -/* What to output and how. */ -enum output_type { - changed, all, recoverable /* Default, -a, -g. */ -}; - -/* Which member(s) of `struct termios' a mode uses. */ -enum mode_type { - control, input, output, local, combination -}; - - -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. */ -struct mode_info { - const char *name; /* Name given on command line. */ - enum mode_type type; /* Which structure element to change. */ - char flags; /* Setting and display options. */ - unsigned long bits; /* Bits to set for this mode. */ - unsigned long mask; /* Other bits to turn off for this mode. */ -}; - -static const struct mode_info mode_info[] = { - {"parenb", control, REV, PARENB, 0 }, - {"parodd", control, REV, PARODD, 0 }, - {"cs5", control, 0, CS5, CSIZE}, - {"cs6", control, 0, CS6, CSIZE}, - {"cs7", control, 0, CS7, CSIZE}, - {"cs8", control, 0, CS8, CSIZE}, - {"hupcl", control, REV, HUPCL, 0 }, - {"hup", control, REV | OMIT, HUPCL, 0 }, - {"cstopb", control, REV, CSTOPB, 0 }, - {"cread", control, SANE_SET | REV, CREAD, 0 }, - {"clocal", control, REV, CLOCAL, 0 }, -#ifdef CRTSCTS - {"crtscts", control, REV, CRTSCTS, 0 }, -#endif - {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 }, - {"brkint", input, SANE_SET | REV, BRKINT, 0 }, - {"ignpar", input, REV, IGNPAR, 0 }, - {"parmrk", input, REV, PARMRK, 0 }, - {"inpck", input, REV, INPCK, 0 }, - {"istrip", input, REV, ISTRIP, 0 }, - {"inlcr", input, SANE_UNSET | REV, INLCR, 0 }, - {"igncr", input, SANE_UNSET | REV, IGNCR, 0 }, - {"icrnl", input, SANE_SET | REV, ICRNL, 0 }, - {"ixon", input, REV, IXON, 0 }, - {"ixoff", input, SANE_UNSET | REV, IXOFF, 0 }, - {"tandem", input, REV | OMIT, IXOFF, 0 }, -#ifdef IUCLC - {"iuclc", input, SANE_UNSET | REV, IUCLC, 0 }, -#endif -#ifdef IXANY - {"ixany", input, SANE_UNSET | REV, IXANY, 0 }, -#endif -#ifdef IMAXBEL - {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0 }, -#endif - {"opost", output, SANE_SET | REV, OPOST, 0 }, -#ifdef OLCUC - {"olcuc", output, SANE_UNSET | REV, OLCUC, 0 }, -#endif -#ifdef OCRNL - {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0 }, -#endif -#ifdef ONLCR - {"onlcr", output, SANE_SET | REV, ONLCR, 0 }, -#endif -#ifdef ONOCR - {"onocr", output, SANE_UNSET | REV, ONOCR, 0 }, -#endif -#ifdef ONLRET - {"onlret", output, SANE_UNSET | REV, ONLRET, 0 }, -#endif -#ifdef OFILL - {"ofill", output, SANE_UNSET | REV, OFILL, 0 }, -#endif -#ifdef OFDEL - {"ofdel", output, SANE_UNSET | REV, OFDEL, 0 }, -#endif -#ifdef NLDLY - {"nl1", output, SANE_UNSET, NL1, NLDLY}, - {"nl0", output, SANE_SET, NL0, NLDLY}, -#endif -#ifdef CRDLY - {"cr3", output, SANE_UNSET, CR3, CRDLY}, - {"cr2", output, SANE_UNSET, CR2, CRDLY}, - {"cr1", output, SANE_UNSET, CR1, CRDLY}, - {"cr0", output, SANE_SET, CR0, CRDLY}, -#endif - -#ifdef TABDLY - {"tab3", output, SANE_UNSET, TAB3, TABDLY}, - {"tab2", output, SANE_UNSET, TAB2, TABDLY}, - {"tab1", output, SANE_UNSET, TAB1, TABDLY}, - {"tab0", output, SANE_SET, TAB0, TABDLY}, -#else -# ifdef OXTABS - {"tab3", output, SANE_UNSET, OXTABS, 0 }, -# endif -#endif - -#ifdef BSDLY - {"bs1", output, SANE_UNSET, BS1, BSDLY}, - {"bs0", output, SANE_SET, BS0, BSDLY}, -#endif -#ifdef VTDLY - {"vt1", output, SANE_UNSET, VT1, VTDLY}, - {"vt0", output, SANE_SET, VT0, VTDLY}, -#endif -#ifdef FFDLY - {"ff1", output, SANE_UNSET, FF1, FFDLY}, - {"ff0", output, SANE_SET, FF0, FFDLY}, -#endif - {"isig", local, SANE_SET | REV, ISIG, 0 }, - {"icanon", local, SANE_SET | REV, ICANON, 0 }, -#ifdef IEXTEN - {"iexten", local, SANE_SET | REV, IEXTEN, 0 }, -#endif - {"echo", local, SANE_SET | REV, ECHO, 0 }, - {"echoe", local, SANE_SET | REV, ECHOE, 0 }, - {"crterase", local, REV | OMIT, ECHOE, 0 }, - {"echok", local, SANE_SET | REV, ECHOK, 0 }, - {"echonl", local, SANE_UNSET | REV, ECHONL, 0 }, - {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0 }, -#ifdef XCASE - {"xcase", local, SANE_UNSET | REV, XCASE, 0 }, -#endif -#ifdef TOSTOP - {"tostop", local, SANE_UNSET | REV, TOSTOP, 0 }, -#endif -#ifdef ECHOPRT - {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 }, - {"prterase", local, REV | OMIT, ECHOPRT, 0 }, -#endif -#ifdef ECHOCTL - {"echoctl", local, SANE_SET | REV, ECHOCTL, 0 }, - {"ctlecho", local, REV | OMIT, ECHOCTL, 0 }, -#endif -#ifdef ECHOKE - {"echoke", local, SANE_SET | REV, ECHOKE, 0 }, - {"crtkill", local, REV | OMIT, ECHOKE, 0 }, -#endif - {evenp, combination, REV | OMIT, 0, 0 }, - {parity, combination, REV | OMIT, 0, 0 }, - {stty_oddp, combination, REV | OMIT, 0, 0 }, - {stty_nl, combination, REV | OMIT, 0, 0 }, - {stty_ek, combination, OMIT, 0, 0 }, - {stty_sane, combination, OMIT, 0, 0 }, - {cooked, combination, REV | OMIT, 0, 0 }, - {raw, combination, REV | OMIT, 0, 0 }, - {stty_pass8, combination, REV | OMIT, 0, 0 }, - {litout, combination, REV | OMIT, 0, 0 }, - {cbreak, combination, REV | OMIT, 0, 0 }, -#ifdef IXANY - {decctlq, combination, REV | OMIT, 0, 0 }, -#endif -#if defined (TABDLY) || defined (OXTABS) - {stty_tabs, combination, REV | OMIT, 0, 0 }, -#endif -#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) - {stty_lcase, combination, REV | OMIT, 0, 0 }, - {stty_LCASE, combination, REV | OMIT, 0, 0 }, -#endif - {stty_crt, combination, OMIT, 0, 0 }, - {stty_dec, combination, OMIT, 0, 0 }, -}; - -static const int NUM_mode_info = - - (sizeof(mode_info) / sizeof(struct mode_info)); - -/* Control character settings. */ -struct control_info { - const char *name; /* Name given on command line. */ - unsigned char saneval; /* Value to set for `stty sane'. */ - int 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}, -#ifdef VEOL2 - {"eol2", CEOL2, VEOL2}, -#endif -#ifdef VSWTCH - {stty_swtch, CSWTCH, VSWTCH}, -#endif - {"start", CSTART, VSTART}, - {"stop", CSTOP, VSTOP}, - {"susp", CSUSP, VSUSP}, -#ifdef VDSUSP - {"dsusp", CDSUSP, VDSUSP}, -#endif -#ifdef VREPRINT - {"rprnt", CRPRNT, VREPRINT}, -#endif -#ifdef VWERASE - {"werase", CWERASE, VWERASE}, -#endif -#ifdef VLNEXT - {"lnext", CLNEXT, VLNEXT}, -#endif -#ifdef VFLUSHO - {"flush", CFLUSHO, VFLUSHO}, -#endif -#ifdef VSTATUS - {"status", CSTATUS, VSTATUS}, -#endif - /* These must be last because of the display routines. */ - {stty_min, 1, VMIN}, - {stty_time, 0, VTIME}, -}; - -static const int NUM_control_info = - (sizeof(control_info) / sizeof(struct control_info)); - - -static const char * visible(unsigned int ch); -static unsigned long baud_to_value(speed_t speed); -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, - const char *device_name); -static void display_changed(struct termios *mode); -static void display_recoverable(struct termios *mode); -static void display_settings(enum output_type output_type, - struct termios *mode, int fd, - const char *device_name); -static void display_speed(struct termios *mode, int fancy); -static void display_window_size(int fancy, int fd, - const char *device_name); -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, - const char *device_name); - -/* The width of the screen, for output wrapping. */ -static int max_col; - -/* Current position, to know when to wrap. */ -static int current_col; - -/* Print format string MESSAGE and optional args. - Wrap to next line first if it won't fit. - Print a space first unless MESSAGE will start a new line. */ - -static void wrapf(const char *message, ...) -{ - va_list args; - char buf[1024]; /* Plenty long for our needs. */ - int buflen; - - va_start(args, message); - vsprintf(buf, message, args); - va_end(args); - buflen = strlen(buf); - if (current_col + (current_col > 0) + buflen >= max_col) { - putchar('\n'); - current_col = 0; - } - if (current_col > 0) { - putchar(' '); - current_col++; - } - fputs(buf, stdout); - current_col += buflen; -} - -static const struct suffix_mult stty_suffixes[] = { - {"b", 512 }, - {"k", 1024}, - {"B", 1024}, - {NULL, 0 } -}; - -#ifndef TEST -extern int stty_main(int argc, char **argv) -#else -extern int main(int argc, char **argv) -#endif -{ - struct termios mode; - enum output_type output_type; - 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; - const char *device_name; - - output_type = 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_type = all; - break; - - case 'g': - recoverable_output = 1; - output_type = recoverable; - break; - - case 'F': - if (file_name) - error_msg_and_die("only one device may be specified"); - file_name = optarg; - break; - - default: /* unrecognized option */ - noargs = 0; - break; - } - - if (noargs == 0) - break; - } - - if (optind < argc) - noargs = 0; - - /* Specifying both -a and -g gets an error. */ - if (verbose_output && recoverable_output) - error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive"); - - /* Specifying any other arguments with -a or -g gets an error. */ - if (!noargs && (verbose_output || recoverable_output)) - error_msg_and_die ("modes may not be set when specifying an output style"); - - /* FIXME: it'd be better not to open the file until we've verified - that all arguments are valid. Otherwise, we could end up doing - only some of the requested operations and then failing, probably - leaving things in an undesirable state. */ - - if (file_name) { - int fdflags; - - device_name = file_name; - fd = open(device_name, O_RDONLY | O_NONBLOCK); - if (fd < 0) - perror_msg_and_die("%s", device_name); - if ((fdflags = fcntl(fd, F_GETFL)) == -1 - || fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) - perror_msg_and_die("%s: couldn't reset non-blocking mode", - device_name); - } else { - fd = 0; - device_name = "standard input"; - } - - /* Initialize to all zeroes so there is no risk memcmp will report a - spurious difference in an uninitialized portion of the structure. */ - memset(&mode, 0, sizeof(mode)); - if (tcgetattr(fd, &mode)) - perror_msg_and_die("%s", device_name); - - if (verbose_output || recoverable_output || noargs) { - max_col = screen_columns(); - current_col = 0; - display_settings(output_type, &mode, fd, device_name); - return EXIT_SUCCESS; - } - - speed_was_set = 0; - require_set_attr = 0; - k = optind; - while (k < argc) { - int match_found = 0; - int reversed = 0; - int i; - - if (argv[k][0] == '-') { - ++argv[k]; - reversed = 1; - } - for (i = 0; i < NUM_mode_info; ++i) - if (STREQ(argv[k], mode_info[i].name)) { - match_found = set_mode(&mode_info[i], reversed, &mode); - require_set_attr = 1; - break; - } - - if (match_found == 0 && reversed) - 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) - error_msg_and_die("missing argument to `%s'", argv[k]); - match_found = 1; - ++k; - set_control_char(&control_info[i], argv[k], &mode); - require_set_attr = 1; - break; - } - - if (match_found == 0) { - if (STREQ(argv[k], "ispeed")) { - if (k == argc - 1) - 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) - 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) - error_msg_and_die("missing argument to `%s'", argv[k]); - ++k; - set_window_size((int) parse_number(argv[k], stty_suffixes), - -1, fd, device_name); - } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) { - if (k == argc - 1) - error_msg_and_die("missing argument to `%s'", argv[k]); - ++k; - set_window_size(-1, - (int) parse_number(argv[k], stty_suffixes), - fd, device_name); - } else if (STREQ(argv[k], "size")) { - max_col = screen_columns(); - current_col = 0; - display_window_size(0, fd, device_name); - } -#endif -#ifdef HAVE_C_LINE - else if (STREQ(argv[k], "line")) { - if (k == argc - 1) - error_msg_and_die("missing argument to `%s'", argv[k]); - ++k; - mode.c_line = parse_number(argv[k], stty_suffixes); - require_set_attr = 1; - } -#endif - else if (STREQ(argv[k], "speed")) { - max_col = screen_columns(); - display_speed(&mode, 0); - } else if (recover_mode(argv[k], &mode) == 1) - require_set_attr = 1; - else if (string_to_baud(argv[k]) != (speed_t) - 1) { - set_speed(both_speeds, argv[k], &mode); - speed_was_set = 1; - require_set_attr = 1; - } else - error_msg_and_die("invalid argument `%s'", argv[k]); - } - k++; - } - - if (require_set_attr) { - struct termios new_mode; - - if (tcsetattr(fd, TCSADRAIN, &mode)) - perror_msg_and_die("%s", device_name); - - /* POSIX (according to Zlotnick's book) tcsetattr returns zero if - it performs *any* of the requested operations. This means it - can report `success' when it has actually failed to perform - some proper subset of the requested operations. To detect - this partial failure, get the current terminal attributes and - compare them to the requested ones. */ - - /* Initialize to all zeroes so there is no risk memcmp will report a - spurious difference in an uninitialized portion of the structure. */ - memset(&new_mode, 0, sizeof(new_mode)); - if (tcgetattr(fd, &new_mode)) - perror_msg_and_die("%s", device_name); - - /* Normally, one shouldn't use memcmp to compare structures that - may have `holes' containing uninitialized data, but we have been - careful to initialize the storage of these two variables to all - zeroes. One might think it more efficient simply to compare the - modified fields, but that would require enumerating those fields -- - and not all systems have the same fields in this structure. */ - - if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) { -#ifdef CIBAUD - /* SunOS 4.1.3 (at least) has the problem that after this sequence, - tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2); - sometimes (m1 != m2). The only difference is in the four bits - of the c_cflag field corresponding to the baud rate. To save - Sun users a little confusion, don't report an error if this - happens. But suppress the error only if we haven't tried to - set the baud rate explicitly -- otherwise we'd never give an - error for a true failure to set the baud rate. */ - - new_mode.c_cflag &= (~CIBAUD); - if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0) -#endif - error_msg_and_die ("%s: unable to perform all requested operations", - device_name); - } - } - - return EXIT_SUCCESS; -} - -/* Return 0 if not applied because not reversible; otherwise return 1. */ - -static int -set_mode(const struct mode_info *info, int reversed, struct termios *mode) -{ - tcflag_t *bitsp; - - if (reversed && (info->flags & REV) == 0) - return 0; - - bitsp = mode_type_flag(info->type, mode); - - if (bitsp == NULL) { - /* Combination mode. */ - if (info->name == evenp || info->name == parity) { - if (reversed) - mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; - else - mode->c_cflag = - (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7; - } else if (info->name == stty_oddp) { - if (reversed) - mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; - else - mode->c_cflag = - (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB; - } else if (info->name == stty_nl) { - if (reversed) { - mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR; - mode->c_oflag = (mode->c_oflag -#ifdef ONLCR - | ONLCR -#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 & ~info->mask & ~info->bits; - else - *bitsp = (*bitsp & ~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 = parse_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 = parse_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 == input_speed || type == both_speeds) - cfsetispeed(mode, baud); - if (type == output_speed || type == both_speeds) - 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, const char *device_name) -{ - struct winsize win; - - if (get_win_size(fd, &win)) { - if (errno != EINVAL) - perror_msg_and_die("%s", device_name); - 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 = 1; - win.ws_col = 1; - - if (ioctl(fd, TIOCSWINSZ, (char *) &win)) - perror_msg_and_die("%s", device_name); - - if (ioctl(fd, TIOCSSIZE, (char *) &ttysz)) - perror_msg_and_die("%s", device_name); - return; - } -# endif - - if (ioctl(fd, TIOCSWINSZ, (char *) &win)) - perror_msg_and_die("%s", device_name); -} - -static void display_window_size(int fancy, int fd, const char *device_name) -{ - struct winsize win; - - if (get_win_size(fd, &win)) { - if (errno != EINVAL) - perror_msg_and_die("%s", device_name); - if (!fancy) - perror_msg_and_die("%s: no size information for this device", - device_name); - } else { - wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n", - win.ws_row, win.ws_col); - if (!fancy) - current_col = 0; - } -} -#endif - -static int screen_columns(void) -{ -#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 - - if (getenv("COLUMNS")) - return atoi(getenv("COLUMNS")); - return 80; -} - -static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode) -{ - switch (type) { - case control: - return &mode->c_cflag; - - case input: - return &mode->c_iflag; - - case output: - return &mode->c_oflag; - - case local: - return &mode->c_lflag; - - default: /* combination: */ - return NULL; - } -} - -static void -display_settings(enum output_type output_type, struct termios *mode, - int fd, const char *device_name) -{ - switch (output_type) { - case changed: - display_changed(mode); - break; - - case all: - display_all(mode, fd, device_name); - break; - - case recoverable: - display_recoverable(mode); - break; - } -} - -static void display_changed(struct termios *mode) -{ - int i; - int empty_line; - tcflag_t *bitsp; - unsigned long mask; - enum mode_type prev_type = control; - - display_speed(mode, 1); -#ifdef HAVE_C_LINE - wrapf("line = %d;", mode->c_line); -#endif - putchar('\n'); - current_col = 0; - - empty_line = 1; - for (i = 0; control_info[i].name != stty_min; ++i) { - if (mode->c_cc[control_info[i].offset] == control_info[i].saneval) - continue; - /* If swtch is the same as susp, don't print both. */ -#if VSWTCH == VSUSP - if (control_info[i].name == stty_swtch) - continue; -#endif - /* If eof uses the same slot as min, only print whichever applies. */ -#if VEOF == VMIN - if ((mode->c_lflag & ICANON) == 0 - && (control_info[i].name == stty_eof - || control_info[i].name == stty_eol)) continue; -#endif - - empty_line = 0; - wrapf("%s = %s;", control_info[i].name, - visible(mode->c_cc[control_info[i].offset])); - } - if ((mode->c_lflag & ICANON) == 0) { - wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN], - (int) mode->c_cc[VTIME]); - } else if (empty_line == 0) - putchar('\n'); - current_col = 0; - - empty_line = 1; - for (i = 0; i < NUM_mode_info; ++i) { - if (mode_info[i].flags & OMIT) - continue; - if (mode_info[i].type != prev_type) { - if (empty_line == 0) { - putchar('\n'); - current_col = 0; - empty_line = 1; - } - prev_type = mode_info[i].type; - } - - bitsp = mode_type_flag(mode_info[i].type, mode); - mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; - if ((*bitsp & mask) == mode_info[i].bits) { - if (mode_info[i].flags & SANE_UNSET) { - wrapf("%s", mode_info[i].name); - empty_line = 0; - } - } - else if ((mode_info[i].flags & (SANE_SET | REV)) == - (SANE_SET | REV)) { - wrapf("-%s", mode_info[i].name); - empty_line = 0; - } - } - if (empty_line == 0) - putchar('\n'); - current_col = 0; -} - -static void -display_all(struct termios *mode, int fd, const char *device_name) -{ - 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, device_name); -#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; -#endif - wrapf("%s = %s;", control_info[i].name, - visible(mode->c_cc[control_info[i].offset])); - } -#if VEOF == VMIN - if ((mode->c_lflag & ICANON) == 0) -#endif - wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]); - if (current_col != 0) - putchar('\n'); - current_col = 0; - - 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; - } - - 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) -{ - if (cfgetispeed(mode) == 0 || cfgetispeed(mode) == cfgetospeed(mode)) - wrapf(fancy ? "speed %lu baud;" : "%lu\n", - baud_to_value(cfgetospeed(mode))); - else - wrapf(fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n", - baud_to_value(cfgetispeed(mode)), - baud_to_value(cfgetospeed(mode))); - if (!fancy) - current_col = 0; -} - -static void display_recoverable(struct termios *mode) -{ - int i; - - printf("%lx:%lx:%lx:%lx", - (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag, - (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag); - for (i = 0; i < NCCS; ++i) - printf(":%x", (unsigned int) mode->c_cc[i]); - putchar('\n'); -} - -static int recover_mode(char *arg, struct termios *mode) -{ - int i, n; - unsigned int chr; - unsigned long iflag, oflag, cflag, lflag; - - /* Scan into temporaries since it is too much trouble to figure out - the right format for `tcflag_t'. */ - if (sscanf(arg, "%lx:%lx:%lx:%lx%n", - &iflag, &oflag, &cflag, &lflag, &n) != 4) - return 0; - mode->c_iflag = iflag; - mode->c_oflag = oflag; - mode->c_cflag = cflag; - mode->c_lflag = lflag; - arg += n; - for (i = 0; i < NCCS; ++i) { - if (sscanf(arg, ":%x%n", &chr, &n) != 1) - return 0; - mode->c_cc[i] = chr; - arg += n; - } - - /* Fail if there are too many fields. */ - if (*arg != '\0') - return 0; - - return 1; -} - -struct speed_map { - speed_t speed; /* Internal form. */ - unsigned long value; /* Numeric value. */ -}; - -static const struct speed_map speeds[] = { - {B0, 0}, - {B50, 50}, - {B75, 75}, - {B110, 110}, - {B134, 134}, - {B150, 150}, - {B200, 200}, - {B300, 300}, - {B600, 600}, - {B1200, 1200}, - {B1800, 1800}, - {B2400, 2400}, - {B4800, 4800}, - {B9600, 9600}, - {B19200, 19200}, - {B38400, 38400}, -#ifdef B57600 - {B57600, 57600}, -#endif -#ifdef B115200 - {B115200, 115200}, -#endif -#ifdef B230400 - {B230400, 230400}, -#endif -#ifdef B460800 - {B460800, 460800}, -#endif -}; - -static const int NUM_SPEEDS = (sizeof(speeds) / sizeof(struct speed_map)); - -static speed_t string_to_baud(const char *arg) -{ - int i; - - for (i = 0; i < NUM_SPEEDS; ++i) - if (parse_number(arg, 0) == speeds[i].value) - return speeds[i].speed; - return (speed_t) - 1; -} - -static unsigned long baud_to_value(speed_t speed) -{ - int i; - - for (i = 0; i < NUM_SPEEDS; ++i) - if (speed == speeds[i].speed) - return speeds[i].value; - return 0; -} - -static void sane_mode(struct termios *mode) -{ - int i; - tcflag_t *bitsp; - - for (i = 0; i < NUM_control_info; ++i) { -#if VMIN == VEOF - if (control_info[i].name == stty_min) - break; -#endif - mode->c_cc[control_info[i].offset] = control_info[i].saneval; - } - - 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 & ~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 & ~mode_info[i].mask & ~mode_info[i].bits; - } - } -} - -/* 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; - - if (ch == _POSIX_VDISABLE) - return ""; - - if (ch >= 32) { - if (ch < 127) - *bpout++ = ch; - else if (ch == 127) { - *bpout++ = '^'; - *bpout++ = '?'; - } else { - *bpout++ = 'M', *bpout++ = '-'; - if (ch >= 128 + 32) { - if (ch < 128 + 127) - *bpout++ = ch - 128; - else { - *bpout++ = '^'; - *bpout++ = '?'; - } - } else { - *bpout++ = '^'; - *bpout++ = ch - 128 + 64; - } - } - } else { - *bpout++ = '^'; - *bpout++ = ch + 64; - } - *bpout = '\0'; - return (const char *) buf; -} - -#ifdef TEST - -const char *applet_name = "stty"; - -#endif - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/swaponoff.c b/busybox/swaponoff.c deleted file mode 100644 index ce0e2c6cc..000000000 --- a/busybox/swaponoff.c +++ /dev/null @@ -1,115 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini swapon/swapoff implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#if __GNU_LIBRARY__ < 5 -/* libc5 doesn't have sys/swap.h, define these here. */ -extern int swapon (__const char *__path, int __flags); -extern int swapoff (__const char *__path); -#else -#include -#endif - -#include "busybox.h" - -static int whichApp; - -static const int SWAPON_APP = 1; -static const int SWAPOFF_APP = 2; - - -static void swap_enable_disable(char *device) -{ - int status; - - if (whichApp == SWAPON_APP) - status = swapon(device, 0); - else - status = swapoff(device); - - if (status != 0) - perror_msg_and_die(applet_name); -} - -static void do_em_all() -{ - struct mntent *m; - FILE *f = setmntent("/etc/fstab", "r"); - - if (f == NULL) - perror_msg_and_die("/etc/fstab"); - while ((m = getmntent(f)) != NULL) { - if (strcmp(m->mnt_type, MNTTYPE_SWAP)==0) { - swap_enable_disable(m->mnt_fsname); - } - } - endmntent(f); - exit(EXIT_SUCCESS); -} - - -extern int swap_on_off_main(int argc, char **argv) -{ - if (strcmp(applet_name, "swapon") == 0) { - whichApp = SWAPON_APP; - } else { - whichApp = SWAPOFF_APP; - } - - if (argc != 2) { - goto usage_and_exit; - } - argc--; - argv++; - - /* Parse any options */ - while (**argv == '-') { - while (*++(*argv)) - switch (**argv) { - case 'a': - { - struct stat statBuf; - - if (stat("/etc/fstab", &statBuf) < 0) - error_msg_and_die("/etc/fstab file missing"); - } - do_em_all(); - break; - default: - goto usage_and_exit; - } - } - swap_enable_disable(*argv); - return EXIT_SUCCESS; - - usage_and_exit: - show_usage(); -} diff --git a/busybox/sync.c b/busybox/sync.c deleted file mode 100644 index ee22ae109..000000000 --- a/busybox/sync.c +++ /dev/null @@ -1,35 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini sync implementation for busybox - * - * - * 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 - * - */ - -#include -#include -#include -#include "busybox.h" - -extern int sync_main(int argc, char **argv) -{ - if (argc > 1 && **(argv + 1) == '-') - show_usage(); - sync(); - return(EXIT_SUCCESS); -} diff --git a/busybox/sysklogd/klogd.c b/busybox/sysklogd/klogd.c deleted file mode 100644 index d7b54e9c8..000000000 --- a/busybox/sysklogd/klogd.c +++ /dev/null @@ -1,153 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini klogd implementation for busybox - * - * Copyright (C) 2001 by Gennady Feldman . - * Changes: Made this a standalone busybox module which uses standalone - * syslog() client interface. - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * - * Copyright (C) 2000 by Karl M. Hegbloom - * - * "circular buffer" Copyright (C) 2000 by Gennady Feldman - * - * Maintainer: Gennady Feldman as of Mar 12, 2001 - * - * 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 /* for our signal() handlers */ -#include /* strncpy() */ -#include /* errno and friends */ -#include -#include -#include - -#if __GNU_LIBRARY__ < 5 -# ifdef __alpha__ -# define klogctl syslog -# endif -#else -# include -#endif - -#include "busybox.h" - -static void klogd_signal(int sig) -{ - klogctl(7, NULL, 0); - klogctl(0, 0, 0); - //logMessage(0, "Kernel log daemon exiting."); - syslog_msg(LOG_DAEMON, 0, "Kernel log daemon exiting."); - exit(TRUE); -} - -static void doKlogd (void) __attribute__ ((noreturn)); -static void doKlogd (void) -{ - int priority = LOG_INFO; - char log_buffer[4096]; - int i, n, lastc; - char *start; - - /* Set up sig handlers */ - signal(SIGINT, klogd_signal); - signal(SIGKILL, klogd_signal); - signal(SIGTERM, klogd_signal); - signal(SIGHUP, SIG_IGN); - - /* "Open the log. Currently a NOP." */ - klogctl(1, NULL, 0); - - syslog_msg(LOG_DAEMON, 0, "klogd started: " BB_BANNER); - - while (1) { - /* Use kernel syscalls */ - memset(log_buffer, '\0', sizeof(log_buffer)); - n = klogctl(2, log_buffer, sizeof(log_buffer)); - if (n < 0) { - char message[80]; - - if (errno == EINTR) - continue; - snprintf(message, 79, "klogd: Error return from sys_sycall: %d - %s.\n", - errno, strerror(errno)); - syslog_msg(LOG_DAEMON, LOG_SYSLOG | LOG_ERR, message); - exit(1); - } - - /* klogctl buffer parsing modelled after code in dmesg.c */ - start=&log_buffer[0]; - lastc='\0'; - for (i=0; i') i++; - start = &log_buffer[i]; - } - if (log_buffer[i] == '\n') { - log_buffer[i] = '\0'; /* zero terminate this message */ - syslog_msg(LOG_DAEMON, LOG_KERN | priority, start); - start = &log_buffer[i+1]; - priority = LOG_INFO; - } - lastc = log_buffer[i]; - } - } -} - -extern int klogd_main(int argc, char **argv) -{ - /* no options, no getopt */ - int opt; - int doFork = TRUE; - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "n")) > 0) { - switch (opt) { - case 'n': - doFork = FALSE; - break; - default: - show_usage(); - } - } - - if (doFork == TRUE) { - if (daemon(0, 1) < 0) - perror_msg_and_die("daemon"); - } - doKlogd(); - - return EXIT_SUCCESS; -} - -/* -Local Variables -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/sysklogd/logger.c b/busybox/sysklogd/logger.c deleted file mode 100644 index 9f730915f..000000000 --- a/busybox/sysklogd/logger.c +++ /dev/null @@ -1,200 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini logger implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "busybox.h" -#if !defined BB_SYSLOGD - -#define SYSLOG_NAMES -#include - -#else -#include -# ifndef __dietlibc__ - /* We have to do this since the header file defines static - * structures. Argh.... bad libc, bad, bad... - */ - typedef struct _code { - char *c_name; - int c_val; - } CODE; - extern CODE prioritynames[]; - extern CODE facilitynames[]; -# endif -#endif - -/* Decode a symbolic name to a numeric value - * this function is based on code - * Copyright (c) 1983, 1993 - * The Regents of the University of California. All rights reserved. - * - * Original copyright notice is retained at the end of this file. - */ -static int decode(char *name, CODE * codetab) -{ - CODE *c; - - if (isdigit(*name)) - return (atoi(name)); - for (c = codetab; c->c_name; c++) { - if (!strcasecmp(name, c->c_name)) { - return (c->c_val); - } - } - - return (-1); -} - -/* Decode a symbolic name to a numeric value - * this function is based on code - * Copyright (c) 1983, 1993 - * The Regents of the University of California. All rights reserved. - * - * Original copyright notice is retained at the end of this file. - */ -static int pencode(char *s) -{ - char *save; - int lev, fac = LOG_USER; - - for (save = s; *s && *s != '.'; ++s); - if (*s) { - *s = '\0'; - fac = decode(save, facilitynames); - if (fac < 0) - error_msg_and_die("unknown facility name: %s", save); - *s++ = '.'; - } else { - s = save; - } - lev = decode(s, prioritynames); - if (lev < 0) - error_msg_and_die("unknown priority name: %s", save); - return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK)); -} - - -extern int logger_main(int argc, char **argv) -{ - int pri = LOG_USER | LOG_NOTICE; - int option = 0; - int c, i, len, opt; - char *message=NULL, buf[1024], name[128]; - - /* Fill out the name string early (may be overwritten later) */ - my_getpwuid(name, geteuid()); - - /* Parse any options */ - while ((opt = getopt(argc, argv, "p:st:")) > 0) { - switch (opt) { - case 's': - option |= LOG_PERROR; - break; - case 'p': - pri = pencode(optarg); - break; - case 't': - strncpy(name, optarg, sizeof(name)); - break; - default: - show_usage(); - } - } - - openlog(name, option, (pri | LOG_FACMASK)); - if (optind == argc) { - do { - /* read from stdin */ - i = 0; - while ((c = getc(stdin)) != EOF && c != '\n' && - i < (sizeof(buf)-1)) { - buf[i++] = c; - } - if (i > 0) { - buf[i++] = '\0'; - syslog(pri, "%s", buf); - } - } while (c != EOF); - } else { - len = 1; /* for the '\0' */ - message=xcalloc(1, 1); - for (i = optind; i < argc; i++) { - len += strlen(argv[i]); - len += 1; /* for the space between the args */ - message = xrealloc(message, len); - strcat(message, argv[i]); - strcat(message, " "); - } - message[strlen(message)-1] = '\0'; - syslog(pri, "%s", message); - } - - closelog(); - return EXIT_SUCCESS; -} - - -/*- - * Copyright (c) 1983, 1993 - * The Regents of the University of California. All rights reserved. - * - * This is the original license statement for the decode and pencode functions. - * - * 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. - */ - - - diff --git a/busybox/sysklogd/logread.c b/busybox/sysklogd/logread.c deleted file mode 100644 index d3349625c..000000000 --- a/busybox/sysklogd/logread.c +++ /dev/null @@ -1,144 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * circular buffer syslog implementation for busybox - * - * Copyright (C) 2000 by Gennady Feldman - * - * Maintainer: Gennady Feldman as of Mar 12, 2001 - * - * 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" - -#if __GNU_LIBRARY__ < 5 -#error Sorry. Looks like you are using libc5. -#error libc5 shm support isnt good enough. -#error Please disable BB_FEATURE_IPC_SYSLOG -#endif - - -static const long KEY_ID = 0x414e4547; /*"GENA"*/ - -static struct shbuf_ds { - int size; // size of data written - int head; // start of message list - int tail; // end of message list - char data[1]; // data/messages -} *buf = NULL; // shared memory pointer - - -// Semaphore operation structures -static struct sembuf SMrup[1] = {{0, -1, IPC_NOWAIT | SEM_UNDO}}; // set SMrup -static struct sembuf SMrdn[2] = {{1, 0}, {0, +1, SEM_UNDO}}; // set SMrdn - -static int log_shmid = -1; // ipc shared memory id -static int log_semid = -1; // ipc semaphore id -static jmp_buf jmp_env; - -static void error_exit(const char *str); -static void interrupted(int sig); - -/* - * sem_up - up()'s a semaphore. - */ -static inline void sem_up(int semid) -{ - if ( semop(semid, SMrup, 1) == -1 ) - error_exit("semop[SMrup]"); -} - -/* - * sem_down - down()'s a semaphore - */ -static inline void sem_down(int semid) -{ - if ( semop(semid, SMrdn, 2) == -1 ) - error_exit("semop[SMrdn]"); -} - -extern int logread_main(int argc, char **argv) -{ - int i; - - /* no options, no getopt */ - if (argc > 1) - show_usage(); - - // handle intrrupt signal - if (setjmp(jmp_env)) goto output_end; - - // attempt to redefine ^C signal - signal(SIGINT, interrupted); - - if ( (log_shmid = shmget(KEY_ID, 0, 0)) == -1) - error_exit("Can't find circular buffer"); - - // Attach shared memory to our char* - if ( (buf = shmat(log_shmid, NULL, SHM_RDONLY)) == NULL) - error_exit("Can't get access to circular buffer from syslogd"); - - if ( (log_semid = semget(KEY_ID, 0, 0)) == -1) - error_exit("Can't get access to semaphone(s) for circular buffer from syslogd"); - - sem_down(log_semid); - // Read Memory - i=buf->head; - - //printf("head: %i tail: %i size: %i\n",buf->head,buf->tail,buf->size); - if (buf->head == buf->tail) { - printf("\n"); - } - - while ( i != buf->tail) { - printf("%s", buf->data+i); - i+= strlen(buf->data+i) + 1; - if (i >= buf->size ) - i=0; - } - sem_up(log_semid); - -output_end: - if (log_shmid != -1) - shmdt(buf); - - return EXIT_SUCCESS; -} - -static void interrupted(int sig){ - signal(SIGINT, SIG_IGN); - longjmp(jmp_env, 1); -} - -static void error_exit(const char *str){ - perror(str); - //release all acquired resources - if (log_shmid != -1) - shmdt(buf); - - exit(1); -} diff --git a/busybox/sysklogd/syslogd.c b/busybox/sysklogd/syslogd.c deleted file mode 100644 index 25bc68f20..000000000 --- a/busybox/sysklogd/syslogd.c +++ /dev/null @@ -1,641 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini syslogd implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * - * Copyright (C) 2000 by Karl M. Hegbloom - * - * "circular buffer" Copyright (C) 2001 by Gennady Feldman - * - * Maintainer: Gennady Feldman as of Mar 12, 2001 - * - * 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 -#include -#include -#include -#include -#include -#include - -#include "busybox.h" - -/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */ -#define SYSLOG_NAMES -#include -#include - -/* Path for the file where all log messages are written */ -#define __LOG_FILE "/var/log/messages" - -/* Path to the unix socket */ -static char lfile[BUFSIZ]; - -static char *logFilePath = __LOG_FILE; - -/* interval between marks in seconds */ -static int MarkInterval = 20 * 60; - -/* localhost's name */ -static char LocalHostName[32]; - -#ifdef BB_FEATURE_REMOTE_LOG -#include -/* udp socket for logging to remote host */ -static int remotefd = -1; -/* where do we log? */ -static char *RemoteHost; -/* what port to log to? */ -static int RemotePort = 514; -/* To remote log or not to remote log, that is the question. */ -static int doRemoteLog = FALSE; -static int local_logging = FALSE; -#endif - -/* circular buffer variables/structures */ -#ifdef BB_FEATURE_IPC_SYSLOG - -#include -#include -#include - -/* our shared key */ -static const long KEY_ID = 0x414e4547; /*"GENA"*/ - -// Semaphore operation structures -static struct shbuf_ds { - int size; // size of data written - int head; // start of message list - int tail; // end of message list - char data[1]; // data/messages -} *buf = NULL; // shared memory pointer - -static struct sembuf SMwup[1] = {{1, -1, IPC_NOWAIT}}; // set SMwup -static struct sembuf SMwdn[3] = {{0, 0}, {1, 0}, {1, +1}}; // set SMwdn - -static int shmid = -1; // ipc shared memory id -static int s_semid = -1; // ipc semaphore id -int data_size = 16000; // data size -int shm_size = 16000 + sizeof(*buf); // our buffer size -static int circular_logging = FALSE; - -/* - * sem_up - up()'s a semaphore. - */ -static inline void sem_up(int semid) -{ - if ( semop(semid, SMwup, 1) == -1 ) - perror_msg_and_die("semop[SMwup]"); -} - -/* - * sem_down - down()'s a semaphore - */ -static inline void sem_down(int semid) -{ - if ( semop(semid, SMwdn, 3) == -1 ) - perror_msg_and_die("semop[SMwdn]"); -} - - -void ipcsyslog_cleanup(void){ - printf("Exiting Syslogd!\n"); - if (shmid != -1) - shmdt(buf); - - if (shmid != -1) - shmctl(shmid, IPC_RMID, NULL); - if (s_semid != -1) - semctl(s_semid, 0, IPC_RMID, 0); -} - -void ipcsyslog_init(void){ - if (buf == NULL){ - if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1) - perror_msg_and_die("shmget"); - - - if ((buf = shmat(shmid, NULL, 0)) == NULL) - perror_msg_and_die("shmat"); - - - buf->size=data_size; - buf->head=buf->tail=0; - - // we'll trust the OS to set initial semval to 0 (let's hope) - if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1){ - if (errno == EEXIST){ - if ((s_semid = semget(KEY_ID, 2, 0)) == -1) - perror_msg_and_die("semget"); - }else - perror_msg_and_die("semget"); - } - }else{ - printf("Buffer already allocated just grab the semaphore?"); - } -} - -/* write message to buffer */ -void circ_message(const char *msg){ - int l=strlen(msg)+1; /* count the whole message w/ '\0' included */ - - sem_down(s_semid); - - /* - * Circular Buffer Algorithm: - * -------------------------- - * - * Start-off w/ empty buffer of specific size SHM_SIZ - * Start filling it up w/ messages. I use '\0' as separator to break up messages. - * This is also very handy since we can do printf on message. - * - * Once the buffer is full we need to get rid of the first message in buffer and - * insert the new message. (Note: if the message being added is >1 message then - * we will need to "remove" >1 old message from the buffer). The way this is done - * is the following: - * When we reach the end of the buffer we set a mark and start from the beginning. - * Now what about the beginning and end of the buffer? Well we have the "head" - * index/pointer which is the starting point for the messages and we have "tail" - * index/pointer which is the ending point for the messages. When we "display" the - * messages we start from the beginning and continue until we reach "tail". If we - * reach end of buffer, then we just start from the beginning (offset 0). "head" and - * "tail" are actually offsets from the beginning of the buffer. - * - * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide - * a threasafe way of handling shared memory operations. - */ - if ( (buf->tail + l) < buf->size ){ - /* before we append the message we need to check the HEAD so that we won't - overwrite any of the message that we still need and adjust HEAD to point - to the next message! */ - if ( buf->tail < buf->head){ - if ( (buf->tail + l) >= buf->head ){ - /* we need to move the HEAD to point to the next message - * Theoretically we have enough room to add the whole message to the - * buffer, because of the first outer IF statement, so we don't have - * to worry about overflows here! - */ - int k= buf->tail + l - buf->head; /* we need to know how many bytes - we are overwriting to make - enough room */ - char *c=memchr(buf->data+buf->head + k,'\0',buf->size - (buf->head + k)); - if (c != NULL) {/* do a sanity check just in case! */ - buf->head = c - buf->data + 1; /* we need to convert pointer to - offset + skip the '\0' since - we need to point to the beginning - of the next message */ - /* Note: HEAD is only used to "retrieve" messages, it's not used - when writing messages into our buffer */ - }else{ /* show an error message to know we messed up? */ - printf("Weird! Can't find the terminator token??? \n"); - buf->head=0; - } - } - } /* in other cases no overflows have been done yet, so we don't care! */ - - /* we should be ok to append the message now */ - strncpy(buf->data + buf->tail,msg,l); /* append our message */ - buf->tail+=l; /* count full message w/ '\0' terminating char */ - }else{ - /* we need to break up the message and "circle" it around */ - char *c; - int k=buf->tail + l - buf->size; /* count # of bytes we don't fit */ - - /* We need to move HEAD! This is always the case since we are going - * to "circle" the message. - */ - c=memchr(buf->data + k ,'\0', buf->size - k); - - if (c != NULL) /* if we don't have '\0'??? weird!!! */{ - /* move head pointer*/ - buf->head=c-buf->data+1; - - /* now write the first part of the message */ - strncpy(buf->data + buf->tail, msg, l - k - 1); - - /* ALWAYS terminate end of buffer w/ '\0' */ - buf->data[buf->size-1]='\0'; - - /* now write out the rest of the string to the beginning of the buffer */ - strcpy(buf->data, &msg[l-k-1]); - - /* we need to place the TAIL at the end of the message */ - buf->tail = k + 1; - }else{ - printf("Weird! Can't find the terminator token from the beginning??? \n"); - buf->head = buf->tail = 0; /* reset buffer, since it's probably corrupted */ - } - - } - sem_up(s_semid); -} -#endif -/* Note: There is also a function called "message()" in init.c */ -/* Print a message to the log file. */ -static void message (char *fmt, ...) __attribute__ ((format (printf, 1, 2))); -static void message (char *fmt, ...) -{ - int fd; - struct flock fl; - va_list arguments; - - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 1; - -#ifdef BB_FEATURE_IPC_SYSLOG - if ((circular_logging == TRUE) && (buf != NULL)){ - char b[1024]; - va_start (arguments, fmt); - vsprintf (b, fmt, arguments); - va_end (arguments); - circ_message(b); - - }else -#endif - if ((fd = device_open (logFilePath, - O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND | - O_NONBLOCK)) >= 0) { - fl.l_type = F_WRLCK; - fcntl (fd, F_SETLKW, &fl); - va_start (arguments, fmt); - vdprintf (fd, fmt, arguments); - va_end (arguments); - fl.l_type = F_UNLCK; - fcntl (fd, F_SETLKW, &fl); - close (fd); - } else { - /* Always send console messages to /dev/console so people will see them. */ - if ((fd = device_open (_PATH_CONSOLE, - O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) { - va_start (arguments, fmt); - vdprintf (fd, fmt, arguments); - va_end (arguments); - close (fd); - } else { - fprintf (stderr, "Bummer, can't print: "); - va_start (arguments, fmt); - vfprintf (stderr, fmt, arguments); - fflush (stderr); - va_end (arguments); - } - } -} - -static void logMessage (int pri, char *msg) -{ - time_t now; - char *timestamp; - static char res[20] = ""; - CODE *c_pri, *c_fac; - - if (pri != 0) { - for (c_fac = facilitynames; - c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++); - for (c_pri = prioritynames; - c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++); - if (c_fac->c_name == NULL || c_pri->c_name == NULL) - snprintf(res, sizeof(res), "<%d>", pri); - else - snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name); - } - - if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' || - msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') { - time(&now); - timestamp = ctime(&now) + 4; - timestamp[15] = '\0'; - } else { - timestamp = msg; - timestamp[15] = '\0'; - msg += 16; - } - - /* todo: supress duplicates */ - -#ifdef BB_FEATURE_REMOTE_LOG - /* send message to remote logger */ - if ( -1 != remotefd){ -static const int IOV_COUNT = 2; - struct iovec iov[IOV_COUNT]; - struct iovec *v = iov; - - memset(&res, 0, sizeof(res)); - snprintf(res, sizeof(res), "<%d>", pri); - v->iov_base = res ; - v->iov_len = strlen(res); - v++; - - v->iov_base = msg; - v->iov_len = strlen(msg); - - if ( -1 == writev(remotefd,iov, IOV_COUNT)){ - error_msg_and_die("syslogd: cannot write to remote file handle on" - "%s:%d",RemoteHost,RemotePort); - } - } - if (local_logging == TRUE) -#endif - /* now spew out the message to wherever it is supposed to go */ - message("%s %s %s %s\n", timestamp, LocalHostName, res, msg); - - -} - -static void quit_signal(int sig) -{ - logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting."); - unlink(lfile); -#ifdef BB_FEATURE_IPC_SYSLOG - ipcsyslog_cleanup(); -#endif - - exit(TRUE); -} - -static void domark(int sig) -{ - if (MarkInterval > 0) { - logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --"); - alarm(MarkInterval); - } -} - -/* This must be a #define, since when DODEBUG and BUFFERS_GO_IN_BSS are - * enabled, we otherwise get a "storage size isn't constant error. */ -#define BUFSIZE 1023 -static int serveConnection (int conn) -{ - RESERVE_BB_BUFFER(tmpbuf, BUFSIZE + 1); - int n_read; - char *p = tmpbuf; - - n_read = read (conn, tmpbuf, BUFSIZE ); - - while (p < tmpbuf + n_read) { - - int pri = (LOG_USER | LOG_NOTICE); - char line[ BUFSIZE + 1 ]; - unsigned char c; - - char *q = line; - - tmpbuf[ n_read - 1 ] = '\0'; - - while (p && (c = *p) && q < &line[ sizeof (line) - 1 ]) { - if (c == '<') { - /* Parse the magic priority number. */ - pri = 0; - while (isdigit (*(++p))) { - pri = 10 * pri + (*p - '0'); - } - if (pri & ~(LOG_FACMASK | LOG_PRIMASK)){ - pri = (LOG_USER | LOG_NOTICE); - } - } else if (c == '\n') { - *q++ = ' '; - } else if (iscntrl (c) && (c < 0177)) { - *q++ = '^'; - *q++ = c ^ 0100; - } else { - *q++ = c; - } - p++; - } - *q = '\0'; - p++; - /* Now log it */ - logMessage (pri, line); - } - RELEASE_BB_BUFFER (tmpbuf); - return n_read; -} - - -#ifdef BB_FEATURE_REMOTE_LOG -static void init_RemoteLog (void){ - - struct sockaddr_in remoteaddr; - struct hostent *hostinfo; - int len = sizeof(remoteaddr); - - memset(&remoteaddr, 0, len); - - remotefd = socket(AF_INET, SOCK_DGRAM, 0); - - if (remotefd < 0) { - error_msg_and_die("syslogd: cannot create socket"); - } - - hostinfo = xgethostbyname(RemoteHost); - - remoteaddr.sin_family = AF_INET; - remoteaddr.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; - remoteaddr.sin_port = htons(RemotePort); - - /* - Since we are using UDP sockets, connect just sets the default host and port - for future operations - */ - if ( 0 != (connect(remotefd, (struct sockaddr *) &remoteaddr, len))){ - error_msg_and_die("syslogd: cannot connect to remote host %s:%d", RemoteHost, RemotePort); - } - -} -#endif - -static void doSyslogd (void) __attribute__ ((noreturn)); -static void doSyslogd (void) -{ - struct sockaddr_un sunx; - socklen_t addrLength; - - - int sock_fd; - fd_set fds; - - /* Set up signal handlers. */ - signal (SIGINT, quit_signal); - signal (SIGTERM, quit_signal); - signal (SIGQUIT, quit_signal); - signal (SIGHUP, SIG_IGN); - signal (SIGCHLD, SIG_IGN); -#ifdef SIGCLD - signal (SIGCLD, SIG_IGN); -#endif - signal (SIGALRM, domark); - alarm (MarkInterval); - - /* Create the syslog file so realpath() can work. */ - if (realpath (_PATH_LOG, lfile) != NULL) - unlink (lfile); - - memset (&sunx, 0, sizeof (sunx)); - sunx.sun_family = AF_UNIX; - strncpy (sunx.sun_path, lfile, sizeof (sunx.sun_path)); - if ((sock_fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) - perror_msg_and_die ("Couldn't get file descriptor for socket " _PATH_LOG); - - addrLength = sizeof (sunx.sun_family) + strlen (sunx.sun_path); - if ((bind (sock_fd, (struct sockaddr *) &sunx, addrLength)) || (listen (sock_fd, 5))) - perror_msg_and_die ("Could not connect to socket " _PATH_LOG); - - if (chmod (lfile, 0666) < 0) - perror_msg_and_die ("Could not set permission on " _PATH_LOG); - - FD_ZERO (&fds); - FD_SET (sock_fd, &fds); - -#ifdef BB_FEATURE_IPC_SYSLOG - if (circular_logging == TRUE ){ - ipcsyslog_init(); - } -#endif - - #ifdef BB_FEATURE_REMOTE_LOG - if (doRemoteLog == TRUE){ - init_RemoteLog(); - } - #endif - - logMessage (LOG_SYSLOG | LOG_INFO, "syslogd started: " BB_BANNER); - - for (;;) { - - fd_set readfds; - int n_ready; - int fd; - - memcpy (&readfds, &fds, sizeof (fds)); - - if ((n_ready = select (FD_SETSIZE, &readfds, NULL, NULL, NULL)) < 0) { - if (errno == EINTR) continue; /* alarm may have happened. */ - perror_msg_and_die ("select error"); - } - - for (fd = 0; (n_ready > 0) && (fd < FD_SETSIZE); fd++) { - if (FD_ISSET (fd, &readfds)) { - - --n_ready; - - if (fd == sock_fd) { - int conn; - - //printf("New Connection request.\n"); - if ((conn = accept (sock_fd, (struct sockaddr *) &sunx, &addrLength)) < 0) { - perror_msg_and_die ("accept error"); - } - - FD_SET(conn, &fds); - //printf("conn: %i, set_size: %i\n",conn,FD_SETSIZE); - } else { - //printf("Serving connection: %i\n",fd); - if ( serveConnection(fd) <= 0 ) { - close (fd); - FD_CLR(fd, &fds); - } - } /* fd == sock_fd */ - }/* FD_ISSET() */ - }/* for */ - } /* for main loop */ -} - -extern int syslogd_main(int argc, char **argv) -{ - int opt; - int doFork = TRUE; - - char *p; - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "m:nO:R:LC")) > 0) { - switch (opt) { - case 'm': - MarkInterval = atoi(optarg) * 60; - break; - case 'n': - doFork = FALSE; - break; - case 'O': - logFilePath = strdup(optarg); - break; -#ifdef BB_FEATURE_REMOTE_LOG - case 'R': - RemoteHost = strdup(optarg); - if ( (p = strchr(RemoteHost, ':'))){ - RemotePort = atoi(p+1); - *p = '\0'; - } - doRemoteLog = TRUE; - break; - case 'L': - local_logging = TRUE; - break; -#endif -#ifdef BB_FEATURE_IPC_SYSLOG - case 'C': - circular_logging = TRUE; - break; -#endif - default: - show_usage(); - } - } - -#ifdef BB_FEATURE_REMOTE_LOG - /* If they have not specified remote logging, then log locally */ - if (doRemoteLog == FALSE) - local_logging = TRUE; -#endif - - - /* Store away localhost's name before the fork */ - gethostname(LocalHostName, sizeof(LocalHostName)); - if ((p = strchr(LocalHostName, '.'))) { - *p++ = '\0'; - } - - umask(0); - - if (doFork == TRUE) { - if (daemon(0, 1) < 0) - perror_msg_and_die("daemon"); - } - doSyslogd(); - - return EXIT_SUCCESS; -} - -/* -Local Variables -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/syslogd.c b/busybox/syslogd.c deleted file mode 100644 index 25bc68f20..000000000 --- a/busybox/syslogd.c +++ /dev/null @@ -1,641 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini syslogd implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * - * Copyright (C) 2000 by Karl M. Hegbloom - * - * "circular buffer" Copyright (C) 2001 by Gennady Feldman - * - * Maintainer: Gennady Feldman as of Mar 12, 2001 - * - * 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 -#include -#include -#include -#include -#include -#include - -#include "busybox.h" - -/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */ -#define SYSLOG_NAMES -#include -#include - -/* Path for the file where all log messages are written */ -#define __LOG_FILE "/var/log/messages" - -/* Path to the unix socket */ -static char lfile[BUFSIZ]; - -static char *logFilePath = __LOG_FILE; - -/* interval between marks in seconds */ -static int MarkInterval = 20 * 60; - -/* localhost's name */ -static char LocalHostName[32]; - -#ifdef BB_FEATURE_REMOTE_LOG -#include -/* udp socket for logging to remote host */ -static int remotefd = -1; -/* where do we log? */ -static char *RemoteHost; -/* what port to log to? */ -static int RemotePort = 514; -/* To remote log or not to remote log, that is the question. */ -static int doRemoteLog = FALSE; -static int local_logging = FALSE; -#endif - -/* circular buffer variables/structures */ -#ifdef BB_FEATURE_IPC_SYSLOG - -#include -#include -#include - -/* our shared key */ -static const long KEY_ID = 0x414e4547; /*"GENA"*/ - -// Semaphore operation structures -static struct shbuf_ds { - int size; // size of data written - int head; // start of message list - int tail; // end of message list - char data[1]; // data/messages -} *buf = NULL; // shared memory pointer - -static struct sembuf SMwup[1] = {{1, -1, IPC_NOWAIT}}; // set SMwup -static struct sembuf SMwdn[3] = {{0, 0}, {1, 0}, {1, +1}}; // set SMwdn - -static int shmid = -1; // ipc shared memory id -static int s_semid = -1; // ipc semaphore id -int data_size = 16000; // data size -int shm_size = 16000 + sizeof(*buf); // our buffer size -static int circular_logging = FALSE; - -/* - * sem_up - up()'s a semaphore. - */ -static inline void sem_up(int semid) -{ - if ( semop(semid, SMwup, 1) == -1 ) - perror_msg_and_die("semop[SMwup]"); -} - -/* - * sem_down - down()'s a semaphore - */ -static inline void sem_down(int semid) -{ - if ( semop(semid, SMwdn, 3) == -1 ) - perror_msg_and_die("semop[SMwdn]"); -} - - -void ipcsyslog_cleanup(void){ - printf("Exiting Syslogd!\n"); - if (shmid != -1) - shmdt(buf); - - if (shmid != -1) - shmctl(shmid, IPC_RMID, NULL); - if (s_semid != -1) - semctl(s_semid, 0, IPC_RMID, 0); -} - -void ipcsyslog_init(void){ - if (buf == NULL){ - if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1) - perror_msg_and_die("shmget"); - - - if ((buf = shmat(shmid, NULL, 0)) == NULL) - perror_msg_and_die("shmat"); - - - buf->size=data_size; - buf->head=buf->tail=0; - - // we'll trust the OS to set initial semval to 0 (let's hope) - if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1){ - if (errno == EEXIST){ - if ((s_semid = semget(KEY_ID, 2, 0)) == -1) - perror_msg_and_die("semget"); - }else - perror_msg_and_die("semget"); - } - }else{ - printf("Buffer already allocated just grab the semaphore?"); - } -} - -/* write message to buffer */ -void circ_message(const char *msg){ - int l=strlen(msg)+1; /* count the whole message w/ '\0' included */ - - sem_down(s_semid); - - /* - * Circular Buffer Algorithm: - * -------------------------- - * - * Start-off w/ empty buffer of specific size SHM_SIZ - * Start filling it up w/ messages. I use '\0' as separator to break up messages. - * This is also very handy since we can do printf on message. - * - * Once the buffer is full we need to get rid of the first message in buffer and - * insert the new message. (Note: if the message being added is >1 message then - * we will need to "remove" >1 old message from the buffer). The way this is done - * is the following: - * When we reach the end of the buffer we set a mark and start from the beginning. - * Now what about the beginning and end of the buffer? Well we have the "head" - * index/pointer which is the starting point for the messages and we have "tail" - * index/pointer which is the ending point for the messages. When we "display" the - * messages we start from the beginning and continue until we reach "tail". If we - * reach end of buffer, then we just start from the beginning (offset 0). "head" and - * "tail" are actually offsets from the beginning of the buffer. - * - * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide - * a threasafe way of handling shared memory operations. - */ - if ( (buf->tail + l) < buf->size ){ - /* before we append the message we need to check the HEAD so that we won't - overwrite any of the message that we still need and adjust HEAD to point - to the next message! */ - if ( buf->tail < buf->head){ - if ( (buf->tail + l) >= buf->head ){ - /* we need to move the HEAD to point to the next message - * Theoretically we have enough room to add the whole message to the - * buffer, because of the first outer IF statement, so we don't have - * to worry about overflows here! - */ - int k= buf->tail + l - buf->head; /* we need to know how many bytes - we are overwriting to make - enough room */ - char *c=memchr(buf->data+buf->head + k,'\0',buf->size - (buf->head + k)); - if (c != NULL) {/* do a sanity check just in case! */ - buf->head = c - buf->data + 1; /* we need to convert pointer to - offset + skip the '\0' since - we need to point to the beginning - of the next message */ - /* Note: HEAD is only used to "retrieve" messages, it's not used - when writing messages into our buffer */ - }else{ /* show an error message to know we messed up? */ - printf("Weird! Can't find the terminator token??? \n"); - buf->head=0; - } - } - } /* in other cases no overflows have been done yet, so we don't care! */ - - /* we should be ok to append the message now */ - strncpy(buf->data + buf->tail,msg,l); /* append our message */ - buf->tail+=l; /* count full message w/ '\0' terminating char */ - }else{ - /* we need to break up the message and "circle" it around */ - char *c; - int k=buf->tail + l - buf->size; /* count # of bytes we don't fit */ - - /* We need to move HEAD! This is always the case since we are going - * to "circle" the message. - */ - c=memchr(buf->data + k ,'\0', buf->size - k); - - if (c != NULL) /* if we don't have '\0'??? weird!!! */{ - /* move head pointer*/ - buf->head=c-buf->data+1; - - /* now write the first part of the message */ - strncpy(buf->data + buf->tail, msg, l - k - 1); - - /* ALWAYS terminate end of buffer w/ '\0' */ - buf->data[buf->size-1]='\0'; - - /* now write out the rest of the string to the beginning of the buffer */ - strcpy(buf->data, &msg[l-k-1]); - - /* we need to place the TAIL at the end of the message */ - buf->tail = k + 1; - }else{ - printf("Weird! Can't find the terminator token from the beginning??? \n"); - buf->head = buf->tail = 0; /* reset buffer, since it's probably corrupted */ - } - - } - sem_up(s_semid); -} -#endif -/* Note: There is also a function called "message()" in init.c */ -/* Print a message to the log file. */ -static void message (char *fmt, ...) __attribute__ ((format (printf, 1, 2))); -static void message (char *fmt, ...) -{ - int fd; - struct flock fl; - va_list arguments; - - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 1; - -#ifdef BB_FEATURE_IPC_SYSLOG - if ((circular_logging == TRUE) && (buf != NULL)){ - char b[1024]; - va_start (arguments, fmt); - vsprintf (b, fmt, arguments); - va_end (arguments); - circ_message(b); - - }else -#endif - if ((fd = device_open (logFilePath, - O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND | - O_NONBLOCK)) >= 0) { - fl.l_type = F_WRLCK; - fcntl (fd, F_SETLKW, &fl); - va_start (arguments, fmt); - vdprintf (fd, fmt, arguments); - va_end (arguments); - fl.l_type = F_UNLCK; - fcntl (fd, F_SETLKW, &fl); - close (fd); - } else { - /* Always send console messages to /dev/console so people will see them. */ - if ((fd = device_open (_PATH_CONSOLE, - O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) { - va_start (arguments, fmt); - vdprintf (fd, fmt, arguments); - va_end (arguments); - close (fd); - } else { - fprintf (stderr, "Bummer, can't print: "); - va_start (arguments, fmt); - vfprintf (stderr, fmt, arguments); - fflush (stderr); - va_end (arguments); - } - } -} - -static void logMessage (int pri, char *msg) -{ - time_t now; - char *timestamp; - static char res[20] = ""; - CODE *c_pri, *c_fac; - - if (pri != 0) { - for (c_fac = facilitynames; - c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++); - for (c_pri = prioritynames; - c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++); - if (c_fac->c_name == NULL || c_pri->c_name == NULL) - snprintf(res, sizeof(res), "<%d>", pri); - else - snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name); - } - - if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' || - msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') { - time(&now); - timestamp = ctime(&now) + 4; - timestamp[15] = '\0'; - } else { - timestamp = msg; - timestamp[15] = '\0'; - msg += 16; - } - - /* todo: supress duplicates */ - -#ifdef BB_FEATURE_REMOTE_LOG - /* send message to remote logger */ - if ( -1 != remotefd){ -static const int IOV_COUNT = 2; - struct iovec iov[IOV_COUNT]; - struct iovec *v = iov; - - memset(&res, 0, sizeof(res)); - snprintf(res, sizeof(res), "<%d>", pri); - v->iov_base = res ; - v->iov_len = strlen(res); - v++; - - v->iov_base = msg; - v->iov_len = strlen(msg); - - if ( -1 == writev(remotefd,iov, IOV_COUNT)){ - error_msg_and_die("syslogd: cannot write to remote file handle on" - "%s:%d",RemoteHost,RemotePort); - } - } - if (local_logging == TRUE) -#endif - /* now spew out the message to wherever it is supposed to go */ - message("%s %s %s %s\n", timestamp, LocalHostName, res, msg); - - -} - -static void quit_signal(int sig) -{ - logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting."); - unlink(lfile); -#ifdef BB_FEATURE_IPC_SYSLOG - ipcsyslog_cleanup(); -#endif - - exit(TRUE); -} - -static void domark(int sig) -{ - if (MarkInterval > 0) { - logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --"); - alarm(MarkInterval); - } -} - -/* This must be a #define, since when DODEBUG and BUFFERS_GO_IN_BSS are - * enabled, we otherwise get a "storage size isn't constant error. */ -#define BUFSIZE 1023 -static int serveConnection (int conn) -{ - RESERVE_BB_BUFFER(tmpbuf, BUFSIZE + 1); - int n_read; - char *p = tmpbuf; - - n_read = read (conn, tmpbuf, BUFSIZE ); - - while (p < tmpbuf + n_read) { - - int pri = (LOG_USER | LOG_NOTICE); - char line[ BUFSIZE + 1 ]; - unsigned char c; - - char *q = line; - - tmpbuf[ n_read - 1 ] = '\0'; - - while (p && (c = *p) && q < &line[ sizeof (line) - 1 ]) { - if (c == '<') { - /* Parse the magic priority number. */ - pri = 0; - while (isdigit (*(++p))) { - pri = 10 * pri + (*p - '0'); - } - if (pri & ~(LOG_FACMASK | LOG_PRIMASK)){ - pri = (LOG_USER | LOG_NOTICE); - } - } else if (c == '\n') { - *q++ = ' '; - } else if (iscntrl (c) && (c < 0177)) { - *q++ = '^'; - *q++ = c ^ 0100; - } else { - *q++ = c; - } - p++; - } - *q = '\0'; - p++; - /* Now log it */ - logMessage (pri, line); - } - RELEASE_BB_BUFFER (tmpbuf); - return n_read; -} - - -#ifdef BB_FEATURE_REMOTE_LOG -static void init_RemoteLog (void){ - - struct sockaddr_in remoteaddr; - struct hostent *hostinfo; - int len = sizeof(remoteaddr); - - memset(&remoteaddr, 0, len); - - remotefd = socket(AF_INET, SOCK_DGRAM, 0); - - if (remotefd < 0) { - error_msg_and_die("syslogd: cannot create socket"); - } - - hostinfo = xgethostbyname(RemoteHost); - - remoteaddr.sin_family = AF_INET; - remoteaddr.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; - remoteaddr.sin_port = htons(RemotePort); - - /* - Since we are using UDP sockets, connect just sets the default host and port - for future operations - */ - if ( 0 != (connect(remotefd, (struct sockaddr *) &remoteaddr, len))){ - error_msg_and_die("syslogd: cannot connect to remote host %s:%d", RemoteHost, RemotePort); - } - -} -#endif - -static void doSyslogd (void) __attribute__ ((noreturn)); -static void doSyslogd (void) -{ - struct sockaddr_un sunx; - socklen_t addrLength; - - - int sock_fd; - fd_set fds; - - /* Set up signal handlers. */ - signal (SIGINT, quit_signal); - signal (SIGTERM, quit_signal); - signal (SIGQUIT, quit_signal); - signal (SIGHUP, SIG_IGN); - signal (SIGCHLD, SIG_IGN); -#ifdef SIGCLD - signal (SIGCLD, SIG_IGN); -#endif - signal (SIGALRM, domark); - alarm (MarkInterval); - - /* Create the syslog file so realpath() can work. */ - if (realpath (_PATH_LOG, lfile) != NULL) - unlink (lfile); - - memset (&sunx, 0, sizeof (sunx)); - sunx.sun_family = AF_UNIX; - strncpy (sunx.sun_path, lfile, sizeof (sunx.sun_path)); - if ((sock_fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) - perror_msg_and_die ("Couldn't get file descriptor for socket " _PATH_LOG); - - addrLength = sizeof (sunx.sun_family) + strlen (sunx.sun_path); - if ((bind (sock_fd, (struct sockaddr *) &sunx, addrLength)) || (listen (sock_fd, 5))) - perror_msg_and_die ("Could not connect to socket " _PATH_LOG); - - if (chmod (lfile, 0666) < 0) - perror_msg_and_die ("Could not set permission on " _PATH_LOG); - - FD_ZERO (&fds); - FD_SET (sock_fd, &fds); - -#ifdef BB_FEATURE_IPC_SYSLOG - if (circular_logging == TRUE ){ - ipcsyslog_init(); - } -#endif - - #ifdef BB_FEATURE_REMOTE_LOG - if (doRemoteLog == TRUE){ - init_RemoteLog(); - } - #endif - - logMessage (LOG_SYSLOG | LOG_INFO, "syslogd started: " BB_BANNER); - - for (;;) { - - fd_set readfds; - int n_ready; - int fd; - - memcpy (&readfds, &fds, sizeof (fds)); - - if ((n_ready = select (FD_SETSIZE, &readfds, NULL, NULL, NULL)) < 0) { - if (errno == EINTR) continue; /* alarm may have happened. */ - perror_msg_and_die ("select error"); - } - - for (fd = 0; (n_ready > 0) && (fd < FD_SETSIZE); fd++) { - if (FD_ISSET (fd, &readfds)) { - - --n_ready; - - if (fd == sock_fd) { - int conn; - - //printf("New Connection request.\n"); - if ((conn = accept (sock_fd, (struct sockaddr *) &sunx, &addrLength)) < 0) { - perror_msg_and_die ("accept error"); - } - - FD_SET(conn, &fds); - //printf("conn: %i, set_size: %i\n",conn,FD_SETSIZE); - } else { - //printf("Serving connection: %i\n",fd); - if ( serveConnection(fd) <= 0 ) { - close (fd); - FD_CLR(fd, &fds); - } - } /* fd == sock_fd */ - }/* FD_ISSET() */ - }/* for */ - } /* for main loop */ -} - -extern int syslogd_main(int argc, char **argv) -{ - int opt; - int doFork = TRUE; - - char *p; - - /* do normal option parsing */ - while ((opt = getopt(argc, argv, "m:nO:R:LC")) > 0) { - switch (opt) { - case 'm': - MarkInterval = atoi(optarg) * 60; - break; - case 'n': - doFork = FALSE; - break; - case 'O': - logFilePath = strdup(optarg); - break; -#ifdef BB_FEATURE_REMOTE_LOG - case 'R': - RemoteHost = strdup(optarg); - if ( (p = strchr(RemoteHost, ':'))){ - RemotePort = atoi(p+1); - *p = '\0'; - } - doRemoteLog = TRUE; - break; - case 'L': - local_logging = TRUE; - break; -#endif -#ifdef BB_FEATURE_IPC_SYSLOG - case 'C': - circular_logging = TRUE; - break; -#endif - default: - show_usage(); - } - } - -#ifdef BB_FEATURE_REMOTE_LOG - /* If they have not specified remote logging, then log locally */ - if (doRemoteLog == FALSE) - local_logging = TRUE; -#endif - - - /* Store away localhost's name before the fork */ - gethostname(LocalHostName, sizeof(LocalHostName)); - if ((p = strchr(LocalHostName, '.'))) { - *p++ = '\0'; - } - - umask(0); - - if (doFork == TRUE) { - if (daemon(0, 1) < 0) - perror_msg_and_die("daemon"); - } - doSyslogd(); - - return EXIT_SUCCESS; -} - -/* -Local Variables -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/tail.c b/busybox/tail.c deleted file mode 100644 index 90cc2a6ef..000000000 --- a/busybox/tail.c +++ /dev/null @@ -1,251 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini tail implementation for busybox - * - * - * 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 - * - */ - - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -static const struct suffix_mult tail_suffixes[] = { - { "b", 512 }, - { "k", 1024 }, - { "m", 1048576 }, - { NULL, 0 } -}; - -static const int BYTES = 0; -static const int LINES = 1; - -static char *tailbuf; -static int taillen; -static int newline; - -static void tailbuf_append(char *buf, int len) -{ - tailbuf = xrealloc(tailbuf, taillen + len); - memcpy(tailbuf + taillen, buf, len); - taillen += len; -} - -static void tailbuf_trunc() -{ - char *s; - s = memchr(tailbuf, '\n', taillen); - memmove(tailbuf, s + 1, taillen - ((s + 1) - tailbuf)); - taillen -= (s + 1) - tailbuf; - newline = 0; -} - -int tail_main(int argc, char **argv) -{ - int from_top = 0, units = LINES, count = 10, sleep_period = 1; - int show_headers = 0, hide_headers = 0, follow = 0; - int *fds, nfiles = 0, status = EXIT_SUCCESS, nread, nwrite, seen = 0; - char *s, *start, *end, buf[BUFSIZ]; - int i, opt; - - while ((opt = getopt(argc, argv, "c:fhn:q:s:v")) > 0) { - switch (opt) { - case 'f': - follow = 1; - break; -#ifdef BB_FEATURE_FANCY_TAIL - case 'c': - units = BYTES; - /* FALLS THROUGH */ -#endif - case 'n': - count = parse_number(optarg, tail_suffixes); - if (count < 0) - count = -count; - if (optarg[0] == '+') - from_top = 1; - break; -#ifdef BB_FEATURE_FANCY_TAIL - case 'q': - hide_headers = 1; - break; - case 's': - sleep_period = parse_number(optarg, 0); - break; - case 'v': - show_headers = 1; - break; -#endif - default: - show_usage(); - } - } - - /* open all the files */ - fds = (int *)xmalloc(sizeof(int) * (argc - optind + 1)); - if (argc == optind) { - fds[nfiles++] = STDIN_FILENO; - argv[optind] = "standard input"; - } else { - for (i = optind; i < argc; i++) { - if (strcmp(argv[i], "-") == 0) { - fds[nfiles++] = STDIN_FILENO; - argv[i] = "standard input"; - } else if ((fds[nfiles++] = open(argv[i], O_RDONLY)) < 0) { - perror_msg("%s", argv[i]); - status = EXIT_FAILURE; - } - } - } - -#ifdef BB_FEATURE_FANCY_TAIL - /* tail the files */ - if (!from_top && units == BYTES) - tailbuf = xmalloc(count); -#endif - - for (i = 0; i < nfiles; i++) { - if (fds[i] == -1) - continue; - if (!count) { - lseek(fds[i], 0, SEEK_END); - continue; - } - seen = 0; - if (show_headers || (!hide_headers && nfiles > 1)) - printf("%s==> %s <==\n", i == 0 ? "" : "\n", argv[optind + i]); - while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) { - if (from_top) { -#ifdef BB_FEATURE_FANCY_TAIL - if (units == BYTES) { - if (count - 1 <= seen) - nwrite = nread; - else if (count - 1 <= seen + nread) - nwrite = nread + seen - (count - 1); - else - nwrite = 0; - seen += nread; - } else { -#else - { -#endif - if (count - 1 <= seen) - nwrite = nread; - else { - nwrite = 0; - for (s = memchr(buf, '\n', nread); s != NULL; - s = memchr(s+1, '\n', nread - (s + 1 - buf))) { - if (count - 1 <= ++seen) { - nwrite = nread - (s + 1 - buf); - break; - } - } - } - } - if (full_write(STDOUT_FILENO, buf + nread - nwrite, - nwrite) < 0) { - perror_msg("write"); - status = EXIT_FAILURE; - break; - } - } else { -#ifdef BB_FEATURE_FANCY_TAIL - if (units == BYTES) { - if (nread < count) { - memmove(tailbuf, tailbuf + nread, count - nread); - memcpy(tailbuf + count - nread, buf, nread); - } else { - memcpy(tailbuf, buf + nread - count, count); - } - seen += nread; - } else { -#else - { -#endif - for (start = buf, end = memchr(buf, '\n', nread); - end != NULL; start = end+1, - end = memchr(start, '\n', nread - (start - buf))) { - if (newline && count <= seen) - tailbuf_trunc(); - tailbuf_append(start, end - start + 1); - seen++; - newline = 1; - } - if (newline && count <= seen && nread - (start - buf) > 0) - tailbuf_trunc(); - tailbuf_append(start, nread - (start - buf)); - } - } - } - - if (nread < 0) { - perror_msg("read"); - status = EXIT_FAILURE; - } - -#ifdef BB_FEATURE_FANCY_TAIL - if (!from_top && units == BYTES) { - if (count < seen) - seen = count; - if (full_write(STDOUT_FILENO, tailbuf + count - seen, seen) < 0) { - perror_msg("write"); - status = EXIT_FAILURE; - } - } -#endif - - if (!from_top && units == LINES) { - if (full_write(STDOUT_FILENO, tailbuf, taillen) < 0) { - perror_msg("write"); - status = EXIT_FAILURE; - } - } - - taillen = 0; - } - - while (follow) { - sleep(sleep_period); - - for (i = 0; i < nfiles; i++) { - if (fds[i] == -1) - continue; - - if ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) { - if (show_headers || (!hide_headers && nfiles > 1)) - printf("\n==> %s <==\n", argv[optind + i]); - - do { - full_write(STDOUT_FILENO, buf, nread); - } while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0); - } - - if (nread < 0) { - perror_msg("read"); - status = EXIT_FAILURE; - } - } - } - - return status; -} diff --git a/busybox/tar.c b/busybox/tar.c deleted file mode 100644 index 389d7f02e..000000000 --- a/busybox/tar.c +++ /dev/null @@ -1,1150 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini tar implementation for busybox - * - * Note, that as of BusyBox-0.43, tar has been completely rewritten from the - * ground up. It still has remnents of the old code lying about, but it is - * very different now (i.e., cleaner, less global variables, etc.) - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * - * Based in part in the tar implementation in sash - * Copyright (c) 1999 by David I. Bell - * Permission is granted to use, distribute, or modify this source, - * provided that this copyright notice remains intact. - * Permission to distribute sash derived code under the GPL has been granted. - * - * Based in part on the tar implementation from busybox-0.28 - * Copyright (C) 1995 Bruce Perens - * This is free software under the GNU General Public License. - * - * 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 -#include -#include -#include -#include -#include "busybox.h" - -/* Tar file constants */ -#ifndef MAJOR -#define MAJOR(dev) (((dev)>>8)&0xff) -#define MINOR(dev) ((dev)&0xff) -#endif - -enum { NAME_SIZE = 100 }; /* because gcc won't let me use 'static const int' */ - -/* POSIX tar Header Block, from POSIX 1003.1-1990 */ -struct TarHeader -{ - /* byte offset */ - char name[NAME_SIZE]; /* 0-99 */ - char mode[8]; /* 100-107 */ - char uid[8]; /* 108-115 */ - char gid[8]; /* 116-123 */ - char size[12]; /* 124-135 */ - char mtime[12]; /* 136-147 */ - char chksum[8]; /* 148-155 */ - char typeflag; /* 156-156 */ - char linkname[NAME_SIZE]; /* 157-256 */ - char magic[6]; /* 257-262 */ - char version[2]; /* 263-264 */ - char uname[32]; /* 265-296 */ - char gname[32]; /* 297-328 */ - char devmajor[8]; /* 329-336 */ - char devminor[8]; /* 337-344 */ - char prefix[155]; /* 345-499 */ - char padding[12]; /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */ -}; -typedef struct TarHeader TarHeader; - - -/* A few useful constants */ -#define TAR_MAGIC "ustar" /* ustar and a null */ -#define TAR_VERSION " " /* Be compatable with GNU tar format */ -static const int TAR_MAGIC_LEN = 6; -static const int TAR_VERSION_LEN = 2; -static const int TAR_BLOCK_SIZE = 512; - -/* A nice enum with all the possible tar file content types */ -enum TarFileType -{ - REGTYPE = '0', /* regular file */ - REGTYPE0 = '\0', /* regular file (ancient bug compat)*/ - LNKTYPE = '1', /* hard link */ - SYMTYPE = '2', /* symbolic link */ - CHRTYPE = '3', /* character special */ - BLKTYPE = '4', /* block special */ - DIRTYPE = '5', /* directory */ - FIFOTYPE = '6', /* FIFO special */ - CONTTYPE = '7', /* reserved */ - GNULONGLINK = 'K', /* GNU long (>100 chars) link name */ - GNULONGNAME = 'L', /* GNU long (>100 chars) file name */ -}; -typedef enum TarFileType TarFileType; - -/* This struct ignores magic, non-numeric user name, - * non-numeric group name, and the checksum, since - * these are all ignored by BusyBox tar. */ -struct TarInfo -{ - int tarFd; /* An open file descriptor for reading from the tarball */ - char * name; /* File name */ - mode_t mode; /* Unix mode, including device bits. */ - uid_t uid; /* Numeric UID */ - gid_t gid; /* Numeric GID */ - size_t size; /* Size of file */ - time_t mtime; /* Last-modified time */ - enum TarFileType type; /* Regular, directory, link, etc. */ - char * linkname; /* Name for symbolic and hard links */ - long devmajor; /* Major number for special device */ - long devminor; /* Minor number for special device */ -}; -typedef struct TarInfo TarInfo; - -/* Local procedures to restore files from a tar file. */ -static int readTarFile(int tarFd, int extractFlag, int listFlag, - int tostdoutFlag, int verboseFlag, char** extractList, - char** excludeList); - -#ifdef BB_FEATURE_TAR_CREATE -/* Local procedures to save files into a tar file. */ -static int writeTarFile(const char* tarName, int verboseFlag, char **argv, - char** excludeList); -#endif - -#if defined BB_FEATURE_TAR_EXCLUDE -static struct option longopts[] = { - { "exclude", 1, NULL, 'e' }, - { NULL, 0, NULL, 0 } -}; -#endif - -extern int tar_main(int argc, char **argv) -{ - char** excludeList=NULL; - char** extractList=NULL; - const char *tarName="-"; - const char *cwd=NULL; -#if defined BB_FEATURE_TAR_EXCLUDE - int excludeListSize=0; - FILE *fileList; - char file[256]; -#endif -#if defined BB_FEATURE_TAR_GZIP - FILE *comp_file = NULL; - int unzipFlag = FALSE; -#endif - int listFlag = FALSE; - int extractFlag = FALSE; - int createFlag = FALSE; - int verboseFlag = FALSE; - int tostdoutFlag = FALSE; - int status = FALSE; - int opt; - pid_t pid; - - if (argc <= 1) - show_usage(); - - if (argv[1][0] != '-') { - char *tmp = xmalloc(strlen(argv[1]) + 2); - tmp[0] = '-'; - strcpy(tmp + 1, argv[1]); - argv[1] = tmp; - } - - while ( -#ifndef BB_FEATURE_TAR_EXCLUDE - (opt = getopt(argc, argv, "cxtzvOf:pC:")) -#else - (opt = getopt_long(argc, argv, "cxtzvOf:X:pC:", longopts, NULL)) -#endif - > 0) { - switch (opt) { - case 'c': - if (extractFlag == TRUE || listFlag == TRUE) - goto flagError; - createFlag = TRUE; - break; - case 'x': - if (listFlag == TRUE || createFlag == TRUE) - goto flagError; - extractFlag = TRUE; - break; - case 't': - if (extractFlag == TRUE || createFlag == TRUE) - goto flagError; - listFlag = TRUE; - break; -#ifdef BB_FEATURE_TAR_GZIP - case 'z': - unzipFlag = TRUE; - break; -#endif - case 'v': - verboseFlag = TRUE; - break; - case 'O': - tostdoutFlag = TRUE; - break; - case 'f': - if (*tarName != '-') - error_msg_and_die( "Only one 'f' option allowed"); - tarName = optarg; - break; -#if defined BB_FEATURE_TAR_EXCLUDE - case 'e': - excludeList=xrealloc( excludeList, - sizeof(char *) * (excludeListSize+2)); - excludeList[excludeListSize] = optarg; - /* Tack a NULL onto the end of the list */ - excludeList[++excludeListSize] = NULL; - case 'X': - fileList = xfopen(optarg, "r"); - while (fgets(file, sizeof(file), fileList) != NULL) { - excludeList = xrealloc(excludeList, - sizeof(char *) * (excludeListSize+2)); - chomp(file); - excludeList[excludeListSize] = xstrdup(file); - /* Tack a NULL onto the end of the list */ - excludeList[++excludeListSize] = NULL; - } - fclose(fileList); - break; -#endif - case 'p': - break; - case 'C': - cwd = xgetcwd((char *)cwd); - if (chdir(optarg)) { - printf("cd: %s: %s\n", optarg, strerror(errno)); - return EXIT_FAILURE; - } - break; - default: - show_usage(); - } - } - - /* - * Do the correct type of action supplying the rest of the - * command line arguments as the list of files to process. - */ - if (createFlag == TRUE) { -#ifndef BB_FEATURE_TAR_CREATE - error_msg_and_die( "This version of tar was not compiled with tar creation support."); -#else -#ifdef BB_FEATURE_TAR_GZIP - if (unzipFlag==TRUE) - error_msg_and_die("Creation of compressed not internally support by tar, pipe to busybox gunzip"); -#endif - status = writeTarFile(tarName, verboseFlag, argv + optind, excludeList); -#endif - } - if (listFlag == TRUE || extractFlag == TRUE) { - int tarFd; - if (argv[optind]) - extractList = argv + optind; - /* Open the tar file for reading. */ - if (!strcmp(tarName, "-")) - tarFd = fileno(stdin); - else - tarFd = open(tarName, O_RDONLY); - if (tarFd < 0) - perror_msg_and_die("Error opening '%s'", tarName); - -#ifdef BB_FEATURE_TAR_GZIP - /* unzip tarFd in a seperate process */ - if (unzipFlag == TRUE) { - comp_file = fdopen(tarFd, "r"); - - /* set the buffer size */ - setvbuf(comp_file, NULL, _IOFBF, 0x8000); - - if ((tarFd = fileno(gz_open(comp_file, &pid))) == EXIT_FAILURE) { - error_msg_and_die("Couldnt unzip file"); - } - } -#endif - status = readTarFile(tarFd, extractFlag, listFlag, tostdoutFlag, - verboseFlag, extractList, excludeList); - close(tarFd); -#ifdef BB_FEATURE_TAR_GZIP - if (unzipFlag == TRUE) { - gz_close(pid); - fclose(comp_file); - } -#endif - } - - if (cwd) - chdir(cwd); - if (status == TRUE) - return EXIT_SUCCESS; - else - return EXIT_FAILURE; - - flagError: - error_msg_and_die( "Exactly one of 'c', 'x' or 't' must be specified"); -} - -static void -fixUpPermissions(TarInfo *header) -{ - struct utimbuf t; - /* Now set permissions etc. for the new file */ - chown(header->name, header->uid, header->gid); - chmod(header->name, header->mode); - /* Reset the time */ - t.actime = time(0); - t.modtime = header->mtime; - utime(header->name, &t); -} - -static int -tarExtractRegularFile(TarInfo *header, int extractFlag, int tostdoutFlag) -{ - size_t writeSize; - size_t readSize; - size_t actualWriteSz; - char buffer[20 * TAR_BLOCK_SIZE]; - size_t size = header->size; - int outFd=fileno(stdout); - - /* Open the file to be written, if a file is supposed to be written */ - if (extractFlag==TRUE && tostdoutFlag==FALSE) { - /* Create the path to the file, just in case it isn't there... - * This should not screw up path permissions or anything. */ - char *buf, *dir; - buf = xstrdup (header->name); - dir = dirname (buf); - make_directory (dir, -1, FILEUTILS_RECUR); - free (buf); - if ((outFd=open(header->name, O_CREAT|O_TRUNC|O_WRONLY, - header->mode & ~S_IFMT)) < 0) { - error_msg(io_error, header->name, strerror(errno)); - return( FALSE); - } - } - - /* Write out the file, if we are supposed to be doing that */ - while ( size > 0 ) { - actualWriteSz=0; - if ( size > sizeof(buffer) ) - writeSize = readSize = sizeof(buffer); - else { - int mod = size % TAR_BLOCK_SIZE; - if ( mod != 0 ) - readSize = size + (TAR_BLOCK_SIZE - mod); - else - readSize = size; - writeSize = size; - } - if ( (readSize = full_read(header->tarFd, buffer, readSize)) <= 0 ) { - /* Tarball seems to have a problem */ - error_msg("Unexpected EOF in archive"); - return( FALSE); - } - if ( readSize < writeSize ) - writeSize = readSize; - - /* Write out the file, if we are supposed to be doing that */ - if (extractFlag==TRUE) { - - if ((actualWriteSz=full_write(outFd, buffer, writeSize)) != writeSize ) { - /* Output file seems to have a problem */ - error_msg(io_error, header->name, strerror(errno)); - return( FALSE); - } - } else { - actualWriteSz=writeSize; - } - - size -= actualWriteSz; - } - - /* Now we are done writing the file out, so try - * and fix up the permissions and whatnot */ - if (extractFlag==TRUE && tostdoutFlag==FALSE) { - close(outFd); - fixUpPermissions(header); - } - return( TRUE); -} - -static int -tarExtractDirectory(TarInfo *header, int extractFlag, int tostdoutFlag) -{ - if (extractFlag==FALSE || tostdoutFlag==TRUE) - return( TRUE); - - if (make_directory(header->name, header->mode, FILEUTILS_RECUR) < 0) - return( FALSE); - - fixUpPermissions(header); - return( TRUE); -} - -static int -tarExtractHardLink(TarInfo *header, int extractFlag, int tostdoutFlag) -{ - if (extractFlag==FALSE || tostdoutFlag==TRUE) - return( TRUE); - - if (link(header->linkname, header->name) < 0) { - perror_msg("%s: Cannot create hard link to '%s'", header->name, - header->linkname); - return( FALSE); - } - - /* Now set permissions etc. for the new directory */ - fixUpPermissions(header); - return( TRUE); -} - -static int -tarExtractSymLink(TarInfo *header, int extractFlag, int tostdoutFlag) -{ - if (extractFlag==FALSE || tostdoutFlag==TRUE) - return( TRUE); - -#ifdef S_ISLNK - if (symlink(header->linkname, header->name) < 0) { - perror_msg("%s: Cannot create symlink to '%s'", header->name, - header->linkname); - return( FALSE); - } - /* Try to change ownership of the symlink. - * If libs doesn't support that, don't bother. - * Changing the pointed-to-file is the Wrong Thing(tm). - */ -#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) - lchown(header->name, header->uid, header->gid); -#endif - - /* Do not change permissions or date on symlink, - * since it changes the pointed to file instead. duh. */ -#else - error_msg("%s: Cannot create symlink to '%s': %s", - header->name, header->linkname, - "symlinks not supported"); -#endif - return( TRUE); -} - -static int -tarExtractSpecial(TarInfo *header, int extractFlag, int tostdoutFlag) -{ - if (extractFlag==FALSE || tostdoutFlag==TRUE) - return( TRUE); - - if (S_ISCHR(header->mode) || S_ISBLK(header->mode) || S_ISSOCK(header->mode)) { - if (mknod(header->name, header->mode, makedev(header->devmajor, header->devminor)) < 0) { - perror_msg("%s: Cannot mknod", header->name); - return( FALSE); - } - } else if (S_ISFIFO(header->mode)) { - if (mkfifo(header->name, header->mode) < 0) { - perror_msg("%s: Cannot mkfifo", header->name); - return( FALSE); - } - } - - /* Now set permissions etc. for the new directory */ - fixUpPermissions(header); - return( TRUE); -} - -/* Parse the tar header and fill in the nice struct with the details */ -static int -readTarHeader(struct TarHeader *rawHeader, struct TarInfo *header) -{ - int i; - long chksum, sum=0; - unsigned char *s = (unsigned char *)rawHeader; - - header->name = rawHeader->name; - /* Check for and relativify any absolute paths */ - if ( *(header->name) == '/' ) { - static int alreadyWarned=FALSE; - - while (*(header->name) == '/') - header->name++; - - if (alreadyWarned == FALSE) { - error_msg("Removing leading '/' from member names"); - alreadyWarned = TRUE; - } - } - - header->mode = strtol(rawHeader->mode, NULL, 8); - header->uid = strtol(rawHeader->uid, NULL, 8); - header->gid = strtol(rawHeader->gid, NULL, 8); - header->size = strtol(rawHeader->size, NULL, 8); - header->mtime = strtol(rawHeader->mtime, NULL, 8); - chksum = strtol(rawHeader->chksum, NULL, 8); - header->type = rawHeader->typeflag; - header->linkname = rawHeader->linkname; - header->devmajor = strtol(rawHeader->devmajor, NULL, 8); - header->devminor = strtol(rawHeader->devminor, NULL, 8); - - /* Check the checksum */ - for (i = sizeof(*rawHeader); i-- != 0;) { - sum += *s++; - } - /* Remove the effects of the checksum field (replace - * with blanks for the purposes of the checksum) */ - s = rawHeader->chksum; - for (i = sizeof(rawHeader->chksum) ; i-- != 0;) { - sum -= *s++; - } - sum += ' ' * sizeof(rawHeader->chksum); - if (sum == chksum ) - return ( TRUE); - return( FALSE); -} - -static int exclude_file(char **excluded_files, const char *file) -{ - int i; - - if (excluded_files == NULL) - return 0; - - for (i = 0; excluded_files[i] != NULL; i++) { - if (excluded_files[i][0] == '/') { - if (fnmatch(excluded_files[i], file, - FNM_PATHNAME | FNM_LEADING_DIR) == 0) - return 1; - } else { - const char *p; - - for (p = file; p[0] != '\0'; p++) { - if ((p == file || p[-1] == '/') && p[0] != '/' && - fnmatch(excluded_files[i], p, - FNM_PATHNAME | FNM_LEADING_DIR) == 0) - return 1; - } - } - } - - return 0; -} - -static int extract_file(char **extract_files, const char *file) -{ - int i; - - if (extract_files == NULL) - return 1; - - for (i = 0; extract_files[i] != NULL; i++) { - if (fnmatch(extract_files[i], file, FNM_LEADING_DIR) == 0) - return 1; - } - - return 0; -} - -/* - * Read a tar file and extract or list the specified files within it. - * If the list is empty than all files are extracted or listed. - */ -static int readTarFile(int tarFd, int extractFlag, int listFlag, - int tostdoutFlag, int verboseFlag, char** extractList, - char** excludeList) -{ - int status; - int errorFlag=FALSE; - int skipNextHeaderFlag=FALSE; - TarHeader rawHeader; - TarInfo header; - - /* Read the tar file, and iterate over it one file at a time */ - while ( (status = full_read(tarFd, (char*)&rawHeader, TAR_BLOCK_SIZE)) == TAR_BLOCK_SIZE ) { - - /* Try to read the header */ - if ( readTarHeader(&rawHeader, &header) == FALSE ) { - if ( *(header.name) == '\0' ) { - goto endgame; - } else { - errorFlag=TRUE; - error_msg("Bad tar header, skipping"); - continue; - } - } - if ( *(header.name) == '\0' ) - continue; - header.tarFd = tarFd; - - /* Skip funky extra GNU headers that precede long files */ - if ( (header.type == GNULONGNAME) || (header.type == GNULONGLINK) ) { - skipNextHeaderFlag=TRUE; - if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) - errorFlag = TRUE; - continue; - } - if ( skipNextHeaderFlag == TRUE ) { - skipNextHeaderFlag=FALSE; - error_msg(name_longer_than_foo, NAME_SIZE); - if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) - errorFlag = TRUE; - continue; - } - -#if defined BB_FEATURE_TAR_EXCLUDE - if (exclude_file(excludeList, header.name)) { - /* There are not the droids you're looking for, move along */ - /* If it is a regular file, pretend to extract it with - * the extractFlag set to FALSE, so the junk in the tarball - * is properly skipped over */ - if ( header.type==REGTYPE || header.type==REGTYPE0 ) { - if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) - errorFlag = TRUE; - } - continue; - } -#endif - - if (!extract_file(extractList, header.name)) { - /* There are not the droids you're looking for, move along */ - /* If it is a regular file, pretend to extract it with - * the extractFlag set to FALSE, so the junk in the tarball - * is properly skipped over */ - if ( header.type==REGTYPE || header.type==REGTYPE0 ) { - if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) - errorFlag = TRUE; - } - continue; - } - - if (listFlag == TRUE) { - /* Special treatment if the list (-t) flag is on */ - if (verboseFlag == TRUE) { - int len, len1; - char buf[35]; - struct tm *tm = localtime (&(header.mtime)); - - len=printf("%s ", mode_string(header.mode)); - my_getpwuid(buf, header.uid); - if (! *buf) - len+=printf("%d", header.uid); - else - len+=printf("%s", buf); - my_getgrgid(buf, header.gid); - if (! *buf) - len+=printf("/%-d ", header.gid); - else - len+=printf("/%-s ", buf); - - if (header.type==CHRTYPE || header.type==BLKTYPE) { - len1=snprintf(buf, sizeof(buf), "%ld,%-ld ", - header.devmajor, header.devminor); - } else { - len1=snprintf(buf, sizeof(buf), "%lu ", (long)header.size); - } - /* Jump through some hoops to make the columns match up */ - for(;(len+len1)<31;len++) - printf(" "); - printf(buf); - - /* Use ISO 8610 time format */ - if (tm) { - printf ("%04d-%02d-%02d %02d:%02d:%02d ", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - } - } - printf("%s", header.name); - if (verboseFlag == TRUE) { - if (header.type==LNKTYPE) /* If this is a link, say so */ - printf(" link to %s", header.linkname); - else if (header.type==SYMTYPE) - printf(" -> %s", header.linkname); - } - printf("\n"); - } - - /* List contents if we are supposed to do that */ - if (verboseFlag == TRUE && extractFlag == TRUE) { - /* Now the normal listing */ - FILE *vbFd = stdout; - if (tostdoutFlag == TRUE) // If the archive goes to stdout, verbose to stderr - vbFd = stderr; - fprintf(vbFd, "%s\n", header.name); - } - - /* Remove files if we would overwrite them */ - if (extractFlag == TRUE && tostdoutFlag == FALSE) - unlink(header.name); - - /* If we got here, we can be certain we have a legitimate - * header to work with. So work with it. */ - switch ( header.type ) { - case REGTYPE: - case REGTYPE0: - /* If the name ends in a '/' then assume it is - * supposed to be a directory, and fall through */ - if (!last_char_is(header.name,'/')) { - if (tarExtractRegularFile(&header, extractFlag, tostdoutFlag)==FALSE) - errorFlag=TRUE; - break; - } - case DIRTYPE: - if (tarExtractDirectory( &header, extractFlag, tostdoutFlag)==FALSE) - errorFlag=TRUE; - break; - case LNKTYPE: - if (tarExtractHardLink( &header, extractFlag, tostdoutFlag)==FALSE) - errorFlag=TRUE; - break; - case SYMTYPE: - if (tarExtractSymLink( &header, extractFlag, tostdoutFlag)==FALSE) - errorFlag=TRUE; - break; - case CHRTYPE: - case BLKTYPE: - case FIFOTYPE: - if (tarExtractSpecial( &header, extractFlag, tostdoutFlag)==FALSE) - errorFlag=TRUE; - break; -#if 0 - /* Handled earlier */ - case GNULONGNAME: - case GNULONGLINK: - skipNextHeaderFlag=TRUE; - break; -#endif - default: - error_msg("Unknown file type '%c' in tar file", header.type); - close( tarFd); - return( FALSE); - } - } - close(tarFd); - if (status > 0) { - /* Bummer - we read a partial header */ - perror_msg("Error reading tar file"); - return ( FALSE); - } - else if (errorFlag==TRUE) { - error_msg( "Error exit delayed from previous errors"); - return( FALSE); - } else - return( status); - - /* Stuff to do when we are done */ -endgame: - close( tarFd); - if ( *(header.name) == '\0' ) { - if (errorFlag==TRUE) - error_msg( "Error exit delayed from previous errors"); - else - return( TRUE); - } - return( FALSE); -} - - -#ifdef BB_FEATURE_TAR_CREATE - -/* -** writeTarFile(), writeFileToTarball(), and writeTarHeader() are -** the only functions that deal with the HardLinkInfo structure. -** Even these functions use the xxxHardLinkInfo() functions. -*/ -typedef struct HardLinkInfo HardLinkInfo; -struct HardLinkInfo -{ - HardLinkInfo *next; /* Next entry in list */ - dev_t dev; /* Device number */ - ino_t ino; /* Inode number */ - short linkCount; /* (Hard) Link Count */ - char name[1]; /* Start of filename (must be last) */ -}; - -/* Some info to be carried along when creating a new tarball */ -struct TarBallInfo -{ - char* fileName; /* File name of the tarball */ - int tarFd; /* Open-for-write file descriptor - for the tarball */ - struct stat statBuf; /* Stat info for the tarball, letting - us know the inode and device that the - tarball lives, so we can avoid trying - to include the tarball into itself */ - int verboseFlag; /* Whether to print extra stuff or not */ - char** excludeList; /* List of files to not include */ - HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */ - HardLinkInfo *hlInfo; /* Hard Link Info for the current file */ -}; -typedef struct TarBallInfo TarBallInfo; - - -/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */ -static void -addHardLinkInfo (HardLinkInfo **hlInfoHeadPtr, dev_t dev, ino_t ino, - short linkCount, const char *name) -{ - /* Note: hlInfoHeadPtr can never be NULL! */ - HardLinkInfo *hlInfo; - - hlInfo = (HardLinkInfo *)xmalloc(sizeof(HardLinkInfo)+strlen(name)+1); - if (hlInfo) { - hlInfo->next = *hlInfoHeadPtr; - *hlInfoHeadPtr = hlInfo; - hlInfo->dev = dev; - hlInfo->ino = ino; - hlInfo->linkCount = linkCount; - strcpy(hlInfo->name, name); - } - return; -} - -static void -freeHardLinkInfo (HardLinkInfo **hlInfoHeadPtr) -{ - HardLinkInfo *hlInfo = NULL; - HardLinkInfo *hlInfoNext = NULL; - - if (hlInfoHeadPtr) { - hlInfo = *hlInfoHeadPtr; - while (hlInfo) { - hlInfoNext = hlInfo->next; - free(hlInfo); - hlInfo = hlInfoNext; - } - *hlInfoHeadPtr = NULL; - } - return; -} - -/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */ -static HardLinkInfo * -findHardLinkInfo (HardLinkInfo *hlInfo, dev_t dev, ino_t ino) -{ - while(hlInfo) { - if ((ino == hlInfo->ino) && (dev == hlInfo->dev)) - break; - hlInfo = hlInfo->next; - } - return(hlInfo); -} - -/* Put an octal string into the specified buffer. - * The number is zero and space padded and possibly null padded. - * Returns TRUE if successful. */ -static int putOctal (char *cp, int len, long value) -{ - int tempLength; - char tempBuffer[32]; - char *tempString = tempBuffer; - - /* Create a string of the specified length with an initial space, - * leading zeroes and the octal number, and a trailing null. */ - sprintf (tempString, "%0*lo", len - 1, value); - - /* If the string is too large, suppress the leading space. */ - tempLength = strlen (tempString) + 1; - if (tempLength > len) { - tempLength--; - tempString++; - } - - /* If the string is still too large, suppress the trailing null. */ - if (tempLength > len) - tempLength--; - - /* If the string is still too large, fail. */ - if (tempLength > len) - return FALSE; - - /* Copy the string to the field. */ - memcpy (cp, tempString, len); - - return TRUE; -} - -/* Write out a tar header for the specified file/directory/whatever */ -static int -writeTarHeader(struct TarBallInfo *tbInfo, const char *header_name, - const char *real_name, struct stat *statbuf) -{ - long chksum=0; - struct TarHeader header; - const unsigned char *cp = (const unsigned char *) &header; - ssize_t size = sizeof(struct TarHeader); - - memset( &header, 0, size); - - strncpy(header.name, header_name, sizeof(header.name)); - - putOctal(header.mode, sizeof(header.mode), statbuf->st_mode); - putOctal(header.uid, sizeof(header.uid), statbuf->st_uid); - putOctal(header.gid, sizeof(header.gid), statbuf->st_gid); - putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */ - putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime); - strncpy(header.magic, TAR_MAGIC TAR_VERSION, - TAR_MAGIC_LEN + TAR_VERSION_LEN ); - - /* Enter the user and group names (default to root if it fails) */ - my_getpwuid(header.uname, statbuf->st_uid); - if (! *header.uname) - strcpy(header.uname, "root"); - my_getgrgid(header.gname, statbuf->st_gid); - if (! *header.uname) - strcpy(header.uname, "root"); - - if (tbInfo->hlInfo) { - /* This is a hard link */ - header.typeflag = LNKTYPE; - strncpy(header.linkname, tbInfo->hlInfo->name, sizeof(header.linkname)); - } else if (S_ISLNK(statbuf->st_mode)) { - char *lpath = xreadlink(real_name); - if (!lpath) /* Already printed err msg inside xreadlink() */ - return ( FALSE); - header.typeflag = SYMTYPE; - strncpy(header.linkname, lpath, sizeof(header.linkname)); - free(lpath); - } else if (S_ISDIR(statbuf->st_mode)) { - header.typeflag = DIRTYPE; - strncat(header.name, "/", sizeof(header.name)); - } else if (S_ISCHR(statbuf->st_mode)) { - header.typeflag = CHRTYPE; - putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev)); - putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev)); - } else if (S_ISBLK(statbuf->st_mode)) { - header.typeflag = BLKTYPE; - putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev)); - putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev)); - } else if (S_ISFIFO(statbuf->st_mode)) { - header.typeflag = FIFOTYPE; - } else if (S_ISREG(statbuf->st_mode)) { - header.typeflag = REGTYPE; - putOctal(header.size, sizeof(header.size), statbuf->st_size); - } else { - error_msg("%s: Unknown file type", real_name); - return ( FALSE); - } - - /* Calculate and store the checksum (i.e., the sum of all of the bytes of - * the header). The checksum field must be filled with blanks for the - * calculation. The checksum field is formatted differently from the - * other fields: it has [6] digits, a null, then a space -- rather than - * digits, followed by a null like the other fields... */ - memset(header.chksum, ' ', sizeof(header.chksum)); - cp = (const unsigned char *) &header; - while (size-- > 0) - chksum += *cp++; - putOctal(header.chksum, 7, chksum); - - /* Now write the header out to disk */ - if ((size=full_write(tbInfo->tarFd, (char*)&header, sizeof(struct TarHeader))) < 0) { - error_msg(io_error, real_name, strerror(errno)); - return ( FALSE); - } - /* Pad the header up to the tar block size */ - for (; sizetarFd, "\0", 1); - } - /* Now do the verbose thing (or not) */ - if (tbInfo->verboseFlag==TRUE) { - FILE *vbFd = stdout; - if (tbInfo->tarFd == fileno(stdout)) // If the archive goes to stdout, verbose to stderr - vbFd = stderr; - fprintf(vbFd, "%s\n", header.name); - } - - return ( TRUE); -} - - -static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData) -{ - struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData; - const char *header_name; - - /* - ** Check to see if we are dealing with a hard link. - ** If so - - ** Treat the first occurance of a given dev/inode as a file while - ** treating any additional occurances as hard links. This is done - ** by adding the file information to the HardLinkInfo linked list. - */ - tbInfo->hlInfo = NULL; - if (statbuf->st_nlink > 1) { - tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf->st_dev, - statbuf->st_ino); - if (tbInfo->hlInfo == NULL) - addHardLinkInfo (&tbInfo->hlInfoHead, statbuf->st_dev, - statbuf->st_ino, statbuf->st_nlink, fileName); - } - - /* It is against the rules to archive a socket */ - if (S_ISSOCK(statbuf->st_mode)) { - error_msg("%s: socket ignored", fileName); - return( TRUE); - } - - /* It is a bad idea to store the archive we are in the process of creating, - * so check the device and inode to be sure that this particular file isn't - * the new tarball */ - if (tbInfo->statBuf.st_dev == statbuf->st_dev && - tbInfo->statBuf.st_ino == statbuf->st_ino) { - error_msg("%s: file is the archive; skipping", fileName); - return( TRUE); - } - - header_name = fileName; - while (header_name[0] == '/') { - static int alreadyWarned=FALSE; - if (alreadyWarned==FALSE) { - error_msg("Removing leading '/' from member names"); - alreadyWarned=TRUE; - } - header_name++; - } - - if (strlen(fileName) >= NAME_SIZE) { - error_msg(name_longer_than_foo, NAME_SIZE); - return ( TRUE); - } - - if (header_name[0] == '\0') - return TRUE; - -#if defined BB_FEATURE_TAR_EXCLUDE - if (exclude_file(tbInfo->excludeList, header_name)) { - return SKIP; - } -#endif - - if (writeTarHeader(tbInfo, header_name, fileName, statbuf)==FALSE) { - return( FALSE); - } - - /* Now, if the file is a regular file, copy it out to the tarball */ - if ((tbInfo->hlInfo == NULL) - && (S_ISREG(statbuf->st_mode))) { - int inputFileFd; - char buffer[BUFSIZ]; - ssize_t size=0, readSize=0; - - /* open the file we want to archive, and make sure all is well */ - if ((inputFileFd = open(fileName, O_RDONLY)) < 0) { - error_msg("%s: Cannot open: %s", fileName, strerror(errno)); - return( FALSE); - } - - /* write the file to the archive */ - while ( (size = full_read(inputFileFd, buffer, sizeof(buffer))) > 0 ) { - if (full_write(tbInfo->tarFd, buffer, size) != size ) { - /* Output file seems to have a problem */ - error_msg(io_error, fileName, strerror(errno)); - return( FALSE); - } - readSize+=size; - } - if (size == -1) { - error_msg(io_error, fileName, strerror(errno)); - return( FALSE); - } - /* Pad the file up to the tar block size */ - for (; (readSize%TAR_BLOCK_SIZE) != 0; readSize++) { - write(tbInfo->tarFd, "\0", 1); - } - close( inputFileFd); - } - - return( TRUE); -} - -static int writeTarFile(const char* tarName, int verboseFlag, char **argv, - char** excludeList) -{ - int tarFd=-1; - int errorFlag=FALSE; - ssize_t size; - struct TarBallInfo tbInfo; - tbInfo.verboseFlag = verboseFlag; - tbInfo.hlInfoHead = NULL; - - /* Make sure there is at least one file to tar up. */ - if (*argv == NULL) - error_msg_and_die("Cowardly refusing to create an empty archive"); - - /* Open the tar file for writing. */ - if (!strcmp(tarName, "-")) - tbInfo.tarFd = fileno(stdout); - else - tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (tbInfo.tarFd < 0) { - perror_msg( "Error opening '%s'", tarName); - freeHardLinkInfo(&tbInfo.hlInfoHead); - return ( FALSE); - } - tbInfo.excludeList=excludeList; - /* Store the stat info for the tarball's file, so - * can avoid including the tarball into itself.... */ - if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) - error_msg_and_die(io_error, tarName, strerror(errno)); - - /* Read the directory/files and iterate over them one at a time */ - while (*argv != NULL) { - if (recursive_action(*argv++, TRUE, FALSE, FALSE, - writeFileToTarball, writeFileToTarball, - (void*) &tbInfo) == FALSE) { - errorFlag = TRUE; - } - } - /* Write two empty blocks to the end of the archive */ - for (size=0; size<(2*TAR_BLOCK_SIZE); size++) { - write(tbInfo.tarFd, "\0", 1); - } - - /* To be pedantically correct, we would check if the tarball - * is smaller than 20 tar blocks, and pad it if it was smaller, - * but that isn't necessary for GNU tar interoperability, and - * so is considered a waste of space */ - - /* Hang up the tools, close up shop, head home */ - close(tarFd); - if (errorFlag == TRUE) { - error_msg("Error exit delayed from previous errors"); - freeHardLinkInfo(&tbInfo.hlInfoHead); - return(FALSE); - } - freeHardLinkInfo(&tbInfo.hlInfoHead); - return( TRUE); -} - - -#endif - diff --git a/busybox/tee.c b/busybox/tee.c deleted file mode 100644 index 439cf7dc5..000000000 --- a/busybox/tee.c +++ /dev/null @@ -1,68 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini tee implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include "busybox.h" -#include -#include - -int -tee_main(int argc, char **argv) -{ - char *mode = "w"; - int c, i, status = 0, nfiles = 0; - FILE **files; - - while ((c = getopt(argc, argv, "a")) != EOF) { - switch (c) { - case 'a': - mode = "a"; - break; - default: - show_usage(); - } - } - - files = (FILE **)xmalloc(sizeof(FILE *) * (argc - optind + 1)); - files[nfiles++] = stdout; - while (optind < argc) { - if ((files[nfiles++] = fopen(argv[optind++], mode)) == NULL) { - nfiles--; - perror_msg("%s", argv[optind-1]); - status = 1; - } - } - - while ((c = getchar()) != EOF) - for (i = 0; i < nfiles; i++) - putc(c, files[i]); - - return status; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/telnet.c b/busybox/telnet.c deleted file mode 100644 index ce82a0ee8..000000000 --- a/busybox/telnet.c +++ /dev/null @@ -1,711 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * telnet implementation for busybox - * - * Author: Tomi Ollila - * Copyright (C) 1994-2000 by Tomi Ollila - * - * Created: Thu Apr 7 13:29:41 1994 too - * Last modified: Fri Jun 9 14:34:24 2000 too - * - * 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 - * - * HISTORY - * Revision 3.1 1994/04/17 11:31:54 too - * initial revision - * Modified 2000/06/13 for inclusion into BusyBox by Erik Andersen - * - * Modified 2001/05/07 to add ability to pass TTYPE to remote host by Jim McQuillan - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#if 0 -static const int DOTRACE = 1; -#endif - -#ifdef DOTRACE -#include /* for inet_ntoa()... */ -#define TRACE(x, y) do { if (x) printf y; } while (0) -#else -#define TRACE(x, y) -#endif - -#if 0 -#define USE_POLL -#include -#else -#include -#endif - -#define DATABUFSIZE 128 -#define IACBUFSIZE 128 - -static const int CHM_TRY = 0; -static const int CHM_ON = 1; -static const int CHM_OFF = 2; - -static const int UF_ECHO = 0x01; -static const int UF_SGA = 0x02; - -enum { - TS_0 = 1, - TS_IAC = 2, - TS_OPT = 3, - TS_SUB1 = 4, - TS_SUB2 = 5, -}; - -#define WriteCS(fd, str) write(fd, str, sizeof str -1) - -typedef unsigned char byte; - -/* use globals to reduce size ??? */ /* test this hypothesis later */ -static struct Globalvars { - int netfd; /* console fd:s are 0 and 1 (and 2) */ - /* same buffer used both for network and console read/write */ - char buf[DATABUFSIZE]; /* allocating so static size is smaller */ - byte telstate; /* telnet negotiation state from network input */ - byte telwish; /* DO, DONT, WILL, WONT */ - byte charmode; - byte telflags; - byte gotsig; - /* buffer to handle telnet negotiations */ - char iacbuf[IACBUFSIZE]; - short iaclen; /* could even use byte */ - struct termios termios_def; - struct termios termios_raw; -} G; - -#define xUSE_GLOBALVAR_PTR /* xUSE... -> don't use :D (makes smaller code) */ - -#ifdef USE_GLOBALVAR_PTR -struct Globalvars * Gptr; -#define G (*Gptr) -#else -static struct Globalvars G; -#endif - -static inline void iacflush() -{ - write(G.netfd, G.iacbuf, G.iaclen); - G.iaclen = 0; -} - -/* Function prototypes */ -static int getport(char * p); -static struct in_addr getserver(char * p); -static int create_socket(); -static void setup_sockaddr_in(struct sockaddr_in * addr, int port); -static int remote_connect(struct in_addr addr, int port); -static void rawmode(); -static void cookmode(); -static void do_linemode(); -static void will_charmode(); -static void telopt(byte c); -static int subneg(byte c); -#if 0 -static int local_bind(int port); -#endif - -/* Some globals */ -static int one = 1; - -#ifdef BB_FEATURE_TELNET_TTYPE -static char *ttype; -#endif - -static void doexit(int ev) -{ - cookmode(); - exit(ev); -} - -static void conescape() -{ - char b; - - if (G.gotsig) /* came from line mode... go raw */ - rawmode(); - - WriteCS(1, "\r\nConsole escape. Commands are:\r\n\n" - " l go to line mode\r\n" - " c go to character mode\r\n" - " z suspend telnet\r\n" - " e exit telnet\r\n"); - - if (read(0, &b, 1) <= 0) - doexit(1); - - switch (b) - { - case 'l': - if (!G.gotsig) - { - do_linemode(); - goto rrturn; - } - break; - case 'c': - if (G.gotsig) - { - will_charmode(); - goto rrturn; - } - break; - case 'z': - cookmode(); - kill(0, SIGTSTP); - rawmode(); - break; - case 'e': - doexit(0); - } - - WriteCS(1, "continuing...\r\n"); - - if (G.gotsig) - cookmode(); - - rrturn: - G.gotsig = 0; - -} -static void handlenetoutput(int len) -{ - /* here we could do smart tricks how to handle 0xFF:s in output - * stream like writing twice every sequence of FF:s (thus doing - * many write()s. But I think interactive telnet application does - * not need to be 100% 8-bit clean, so changing every 0xff:s to - * 0x7f:s */ - - int i; - byte * p = G.buf; - - for (i = len; i > 0; i--, p++) - { - if (*p == 0x1d) - { - conescape(); - return; - } - if (*p == 0xff) - *p = 0x7f; - } - write(G.netfd, G.buf, len); -} - - -static void handlenetinput(int len) -{ - int i; - int cstart = 0; - - for (i = 0; i < len; i++) - { - byte c = G.buf[i]; - - if (G.telstate == 0) /* most of the time state == 0 */ - { - if (c == IAC) - { - cstart = i; - G.telstate = TS_IAC; - } - } - else - switch (G.telstate) - { - case TS_0: - if (c == IAC) - G.telstate = TS_IAC; - else - G.buf[cstart++] = c; - break; - - case TS_IAC: - if (c == IAC) /* IAC IAC -> 0xFF */ - { - G.buf[cstart++] = c; - G.telstate = TS_0; - break; - } - /* else */ - switch (c) - { - case SB: - G.telstate = TS_SUB1; - break; - case DO: - case DONT: - case WILL: - case WONT: - G.telwish = c; - G.telstate = TS_OPT; - break; - default: - G.telstate = TS_0; /* DATA MARK must be added later */ - } - break; - case TS_OPT: /* WILL, WONT, DO, DONT */ - telopt(c); - G.telstate = TS_0; - break; - case TS_SUB1: /* Subnegotiation */ - case TS_SUB2: /* Subnegotiation */ - if (subneg(c) == TRUE) - G.telstate = TS_0; - break; - } - } - if (G.telstate) - { - if (G.iaclen) iacflush(); - if (G.telstate == TS_0) G.telstate = 0; - - len = cstart; - } - - if (len) - write(1, G.buf, len); -} - - -/* ******************************* */ - -static inline void putiac(int c) -{ - G.iacbuf[G.iaclen++] = c; -} - - -static void putiac2(byte wwdd, byte c) -{ - if (G.iaclen + 3 > IACBUFSIZE) - iacflush(); - - putiac(IAC); - putiac(wwdd); - putiac(c); -} - -#if 0 -static void putiac1(byte c) -{ - if (G.iaclen + 2 > IACBUFSIZE) - iacflush(); - - putiac(IAC); - putiac(c); -} -#endif - -#ifdef BB_FEATURE_TELNET_TTYPE -static void putiac_subopt(byte c, char *str) -{ - int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 ) - - if (G.iaclen + len > IACBUFSIZE) - iacflush(); - - putiac(IAC); - putiac(SB); - putiac(c); - putiac(0); - - while(*str) - putiac(*str++); - - putiac(IAC); - putiac(SE); -} -#endif - -/* void putiacstring (subneg strings) */ - -/* ******************************* */ - -static char const escapecharis[] = "\r\nEscape character is "; - -static void setConMode() -{ - if (G.telflags & UF_ECHO) - { - if (G.charmode == CHM_TRY) { - G.charmode = CHM_ON; - printf("\r\nEntering character mode%s'^]'.\r\n", escapecharis); - rawmode(); - } - } - else - { - if (G.charmode != CHM_OFF) { - G.charmode = CHM_OFF; - printf("\r\nEntering line mode%s'^C'.\r\n", escapecharis); - cookmode(); - } - } -} - -/* ******************************* */ - -static void will_charmode() -{ - G.charmode = CHM_TRY; - G.telflags |= (UF_ECHO | UF_SGA); - setConMode(); - - putiac2(DO, TELOPT_ECHO); - putiac2(DO, TELOPT_SGA); - iacflush(); -} - -static void do_linemode() -{ - G.charmode = CHM_TRY; - G.telflags &= ~(UF_ECHO | UF_SGA); - setConMode(); - - putiac2(DONT, TELOPT_ECHO); - putiac2(DONT, TELOPT_SGA); - iacflush(); -} - -/* ******************************* */ - -static inline void to_notsup(char c) -{ - if (G.telwish == WILL) putiac2(DONT, c); - else if (G.telwish == DO) putiac2(WONT, c); -} - -static inline void to_echo() -{ - /* if server requests ECHO, don't agree */ - if (G.telwish == DO) { putiac2(WONT, TELOPT_ECHO); return; } - else if (G.telwish == DONT) return; - - if (G.telflags & UF_ECHO) - { - if (G.telwish == WILL) - return; - } - else - if (G.telwish == WONT) - return; - - if (G.charmode != CHM_OFF) - G.telflags ^= UF_ECHO; - - if (G.telflags & UF_ECHO) - putiac2(DO, TELOPT_ECHO); - else - putiac2(DONT, TELOPT_ECHO); - - setConMode(); - WriteCS(1, "\r\n"); /* sudden modec */ -} - -static inline void to_sga() -{ - /* daemon always sends will/wont, client do/dont */ - - if (G.telflags & UF_SGA) - { - if (G.telwish == WILL) - return; - } - else - if (G.telwish == WONT) - return; - - if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */ - putiac2(DO, TELOPT_SGA); - else - putiac2(DONT, TELOPT_SGA); - - return; -} - -#ifdef BB_FEATURE_TELNET_TTYPE -static inline void to_ttype() -{ - /* Tell server we will (or won't) do TTYPE */ - - if(ttype) - putiac2(WILL, TELOPT_TTYPE); - else - putiac2(WONT, TELOPT_TTYPE); - - return; -} -#endif - -static void telopt(byte c) -{ - switch (c) - { - case TELOPT_ECHO: to_echo(c); break; - case TELOPT_SGA: to_sga(c); break; -#ifdef BB_FEATURE_TELNET_TTYPE - case TELOPT_TTYPE: to_ttype(c); break; -#endif - default: to_notsup(c); break; - } -} - - -/* ******************************* */ - -/* subnegotiation -- ignore all (except TTYPE) */ - -static int subneg(byte c) -{ - switch (G.telstate) - { - case TS_SUB1: - if (c == IAC) - G.telstate = TS_SUB2; -#ifdef BB_FEATURE_TELNET_TTYPE - else - if (c == TELOPT_TTYPE) - putiac_subopt(TELOPT_TTYPE,ttype); -#endif - break; - case TS_SUB2: - if (c == SE) - return TRUE; - G.telstate = TS_SUB1; - /* break; */ - } - return FALSE; -} - -/* ******************************* */ - -static void fgotsig(int sig) -{ - G.gotsig = sig; -} - - -static void rawmode() -{ - tcsetattr(0, TCSADRAIN, &G.termios_raw); -} - -static void cookmode() -{ - tcsetattr(0, TCSADRAIN, &G.termios_def); -} - -extern int telnet_main(int argc, char** argv) -{ - struct in_addr host; - int port; - int len; -#ifdef USE_POLL - struct pollfd ufds[2]; -#else - fd_set readfds; - int maxfd; -#endif - -#ifdef BB_FEATURE_TELNET_TTYPE - ttype = getenv("TERM"); -#endif - - memset(&G, 0, sizeof G); - - if (tcgetattr(0, &G.termios_def) < 0) - exit(1); - - G.termios_raw = G.termios_def; - cfmakeraw(&G.termios_raw); - - if (argc < 2) show_usage(); - port = (argc > 2)? getport(argv[2]): 23; - - host = getserver(argv[1]); - - G.netfd = remote_connect(host, port); - - signal(SIGINT, fgotsig); - -#ifdef USE_POLL - ufds[0].fd = 0; ufds[1].fd = G.netfd; - ufds[0].events = ufds[1].events = POLLIN; -#else - FD_ZERO(&readfds); - FD_SET(0, &readfds); - FD_SET(G.netfd, &readfds); - maxfd = G.netfd + 1; -#endif - - while (1) - { -#ifndef USE_POLL - fd_set rfds = readfds; - - switch (select(maxfd, &rfds, NULL, NULL, NULL)) -#else - switch (poll(ufds, 2, -1)) -#endif - { - case 0: - /* timeout */ - case -1: - /* error, ignore and/or log something, bay go to loop */ - if (G.gotsig) - conescape(); - else - sleep(1); - break; - default: - -#ifdef USE_POLL - if (ufds[0].revents) /* well, should check POLLIN, but ... */ -#else - if (FD_ISSET(0, &rfds)) -#endif - { - len = read(0, G.buf, DATABUFSIZE); - - if (len <= 0) - doexit(0); - - TRACE(0, ("Read con: %d\n", len)); - - handlenetoutput(len); - } - -#ifdef USE_POLL - if (ufds[1].revents) /* well, should check POLLIN, but ... */ -#else - if (FD_ISSET(G.netfd, &rfds)) -#endif - { - len = read(G.netfd, G.buf, DATABUFSIZE); - - if (len <= 0) - { - WriteCS(1, "Connection closed by foreign host.\r\n"); - doexit(1); - } - TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len)); - - handlenetinput(len); - } - } - } -} - -static int getport(char * p) -{ - unsigned int port = atoi(p); - - if ((unsigned)(port - 1 ) > 65534) - { - error_msg_and_die("%s: bad port number", p); - } - return port; -} - -static struct in_addr getserver(char * host) -{ - struct in_addr addr; - - struct hostent * he; - he = xgethostbyname(host); - memcpy(&addr, he->h_addr, sizeof addr); - - TRACE(1, ("addr: %s\n", inet_ntoa(addr))); - - return addr; -} - -static int create_socket() -{ - return socket(AF_INET, SOCK_STREAM, 0); -} - -static void setup_sockaddr_in(struct sockaddr_in * addr, int port) -{ - memset(addr, 0, sizeof(struct sockaddr_in)); - addr->sin_family = AF_INET; - addr->sin_port = htons(port); -} - -#if 0 -static int local_bind(int port) -{ - struct sockaddr_in s_addr; - int s = create_socket(); - - setup_sockaddr_in(&s_addr, port); - - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one); - - if (bind(s, &s_addr, sizeof s_addr) < 0) - { - char * e = sys_errlist[errno]; - syserrorexit("bind"); - exit(1); - } - listen(s, 1); - - return s; -} -#endif - -static int remote_connect(struct in_addr addr, int port) -{ - struct sockaddr_in s_addr; - int s = create_socket(); - - setup_sockaddr_in(&s_addr, port); - s_addr.sin_addr = addr; - - setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one); - - if (connect(s, (struct sockaddr *)&s_addr, sizeof s_addr) < 0) - { - perror_msg_and_die("Unable to connect to remote host"); - } - return s; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ - diff --git a/busybox/test.c b/busybox/test.c deleted file mode 100644 index 9c66cbb87..000000000 --- a/busybox/test.c +++ /dev/null @@ -1,579 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * test implementation for busybox - * - * 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. - * - * 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 - * - * Original copyright notice states: - * "This program is in the Public Domain." - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -/* test(1) accepts the following grammar: - oexpr ::= aexpr | aexpr "-o" oexpr ; - aexpr ::= nexpr | nexpr "-a" aexpr ; - nexpr ::= primary | "!" primary - primary ::= unary-operator operand - | operand binary-operator operand - | operand - | "(" oexpr ")" - ; - 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"| - "-nt"|"-ot"|"-ef"; - operand ::= -*/ - -enum token { - 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 -}; - -enum token_types { - UNOP, - BINOP, - BUNOP, - BBINOP, - 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} -}; - -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(); -static int oexpr(); -static int aexpr(); -static int nexpr(); -static int binop(); -static int primary(); -static int filstat(); -static int getn(); -static int newerf(); -static int olderf(); -static int equalf(); -static void syntax(); -static int test_eaccess(); -static int is_a_group_member(); -static void initialize_group_array(); - -extern int -test_main(int argc, char** argv) -{ - int res; - - if (strcmp(applet_name, "[") == 0) { - if (strcmp(argv[--argc], "]")) - 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)); - - if (*t_wp != NULL && *++t_wp != NULL) - syntax(*t_wp, "unknown operand"); - - return( res); -} - -static void -syntax(op, msg) - char *op; - char *msg; -{ - if (op && *op) - error_msg_and_die("%s: %s", op, msg); - else - error_msg_and_die("%s", msg); -} - -static int -oexpr(n) - enum token n; -{ - int res; - - res = aexpr(n); - if (t_lex(*++t_wp) == BOR) - return oexpr(t_lex(*++t_wp)) || res; - t_wp--; - return res; -} - -static int -aexpr(n) - enum token n; -{ - int res; - - res = nexpr(n); - if (t_lex(*++t_wp) == BAND) - return aexpr(t_lex(*++t_wp)) && res; - t_wp--; - return res; -} - -static int -nexpr(n) - enum token n; /* token */ -{ - if (n == UNOT) - return !nexpr(t_lex(*++t_wp)); - return primary(n); -} - -static int -primary(n) - enum token n; -{ - int res; - - 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; - } - 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); - } - } - - if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) { - return binop(); - } - - return strlen(*t_wp) > 0; -} - -static int -binop() -{ - const char *opnd1, *opnd2; - struct t_op const *op; - - opnd1 = *t_wp; - (void) t_lex(*++t_wp); - op = t_wp_op; - - if ((opnd2 = *++t_wp) == (char *)0) - syntax(op->op_text, "argument expected"); - - 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); - } - /* NOTREACHED */ - return 1; -} - -static int -filstat(nm, mode) - char *nm; - enum token mode; -{ - struct stat s; - unsigned int i; - - if (mode == FILSYM) { -#ifdef S_IFLNK - if (lstat(nm, &s) == 0) { - i = S_IFLNK; - goto filetype; - } -#endif - return 0; - } - - 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: - 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: -#ifdef S_IFIFO - i = S_IFIFO; - goto filetype; -#else - return 0; -#endif - case FILSOCK: -#ifdef S_IFSOCK - i = S_IFSOCK; - goto filetype; -#else - 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: - return s.st_size > 0L; - case FILUID: - return s.st_uid == geteuid(); - case FILGID: - return s.st_gid == getegid(); - default: - return 1; - } - -filetype: - return ((s.st_mode & S_IFMT) == i); - -filebit: - return ((s.st_mode & i) != 0); -} - -static enum token -t_lex(s) - 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; - } - op++; - } - t_wp_op = (struct t_op *)0; - return OPERAND; -} - -/* atoi with error detection */ -static int -getn(s) - char *s; -{ - char *p; - long r; - - errno = 0; - r = strtol(s, &p, 10); - - if (errno != 0) - error_msg_and_die("%s: out of range", s); - - while (isspace(*p)) - p++; - - if (*p) - error_msg_and_die("%s: bad number", s); - - return (int) r; -} - -static int -newerf (f1, f2) -char *f1, *f2; -{ - struct stat b1, b2; - - return (stat (f1, &b1) == 0 && - stat (f2, &b2) == 0 && - b1.st_mtime > b2.st_mtime); -} - -static int -olderf (f1, f2) -char *f1, *f2; -{ - struct stat b1, b2; - - return (stat (f1, &b1) == 0 && - stat (f2, &b2) == 0 && - b1.st_mtime < b2.st_mtime); -} - -static int -equalf (f1, f2) -char *f1, *f2; -{ - struct stat b1, b2; - - return (stat (f1, &b1) == 0 && - stat (f2, &b2) == 0 && - b1.st_dev == b2.st_dev && - b1.st_ino == b2.st_ino); -} - -/* 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 (path, mode) -char *path; -int mode; -{ - struct stat st; - unsigned int euid = geteuid(); - - if (stat (path, &st) < 0) - return (-1); - - if (euid == 0) { - /* Root can read or write any file. */ - if (mode != X_OK) - return (0); - - /* 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); - } - - 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 void -initialize_group_array () -{ - ngroups = getgroups(0, NULL); - group_array = xrealloc(group_array, ngroups * sizeof(gid_t)); - getgroups(ngroups, group_array); -} - -/* Return non-zero if GID is one that we have in our groups list. */ -static int -is_a_group_member (gid) -gid_t gid; -{ - register 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); -} diff --git a/busybox/tests/.cvsignore b/busybox/tests/.cvsignore deleted file mode 100644 index 3645cf92f..000000000 --- a/busybox/tests/.cvsignore +++ /dev/null @@ -1,16 +0,0 @@ -cp -cp_*.bb -cp_*.gnu -cp_tests -date -df -du -ln -ln_*.bb -ln_*.gnu -ln_tests -mv -mv_*.bb -mv_*.gnu -mv_tests -syslog_test diff --git a/busybox/tests/Makefile b/busybox/tests/Makefile deleted file mode 100644 index 8ad304d86..000000000 --- a/busybox/tests/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -# busybox/tests/Makefile - Run through all defined tests. -# ------------------------ -# Copyright (C) 2000 Karl M. Hegbloom GPL - -all:: message_header - -message_header: - @echo - @echo BusyBox Test Suite. - @echo - (cd ..; tests/busybox.REGRESS.sh) - -clean:: - -distclean: clean - -.PHONY: all clean distclean message_header - -include $(wildcard *_tests.mk) - -BBL := $(shell pushd .. >/dev/null && \ - ${MAKE} busybox.links >/dev/null && \ - popd >/dev/null && \ - cat ../busybox.links | \ - sed -e 's,.*/\(.*\)$$,\1,') - -../busybox: - cd .. && ${MAKE} busybox - -${BBL}: ../busybox - rm -f $@ - ln ../busybox $@ - -syslog_test: syslog_test.c diff --git a/busybox/tests/cp_tests.mk b/busybox/tests/cp_tests.mk deleted file mode 100644 index b96c5cea6..000000000 --- a/busybox/tests/cp_tests.mk +++ /dev/null @@ -1,360 +0,0 @@ -# cp_tests.mk - Set of test cases for busybox cp -# ------------- -# Copyright (C) 2000 Karl M. Hegbloom GPL -# - -# GNU `cp' -GCP = /bin/cp -# BusyBox `cp' -BCP = $(shell pwd)/cp - -all:: cp_tests -clean:: cp_clean - -cp_clean: - - rm -rf cp_tests cp_*.{gnu,bb} cp - -# check_cp_dir_to_dir_wo_a removed from this list; see below -cp_tests: cp_clean cp check_exists check_simple_cp check_cp_symlnk \ - check_cp_symlink_w_a check_cp_files_to_dir check_cp_files_to_dir_w_d \ - check_cp_files_to_dir_w_p check_cp_files_to_dir_w_p_and_d \ - check_cp_dir_to_dir_w_a \ - check_cp_dir_to_dir_w_a_take_two - -check_exists: - @echo; - @echo "No output from diff means busybox cp is functioning properly."; - @echo "Some tests might show timestamp differences that are Ok."; - - @echo; - @echo Verify that busybox cp exists; - @echo ------------------------------; - [ -x ${BCP} ] || exit 0 - - @echo; - mkdir cp_tests; - -check_simple_cp: - @echo Copy a file to a copy of the file; - @echo ------------------------------; - cd cp_tests; \ - echo A file > afile; \ - ls -l afile > ../cp_afile_afilecopy.gnu; \ - ${GCP} afile afilecopy; \ - ls -l afile afilecopy >> ../cp_afile_afilecopy.gnu; - - @echo; - rm -rf cp_tests/*; - - @echo; - cd cp_tests; \ - echo A file > afile; \ - ls -l afile > ../cp_afile_afilecopy.bb; \ - ${BCP} afile afilecopy; \ - ls -l afile afilecopy >> ../cp_afile_afilecopy.bb; - - @echo; - @echo Might show timestamp differences. - -diff -u cp_afile_afilecopy.gnu cp_afile_afilecopy.bb; - - @echo; - rm -rf cp_tests/*; - -check_cp_symlnk: - @echo; echo Copy a file pointed to by a symlink; - @echo ------------------------------; - cd cp_tests; \ - mkdir here there; \ - echo A file > afile; \ - cd here; \ - ln -s ../afile .; \ - - @echo; - cd cp_tests; \ - ls -lR . > ../cp_symlink.gnu; \ - ${GCP} here/afile there; \ - ls -lR . >> ../cp_symlink.gnu; - - @echo; - rm -rf cp_tests/there/*; - - sleep 1; - - @echo; - cd cp_tests; \ - ls -lR . > ../cp_symlink.bb; \ - ${BCP} here/afile there; \ - ls -lR . >> ../cp_symlink.bb; - - @echo; - @echo Will show timestamp difference. - -diff -u cp_symlink.gnu cp_symlink.bb; - - @echo; - rm -rf cp_tests/* - -check_cp_symlink_w_a: - @echo; echo Copy a symlink, useing the -a switch.; - @echo ------------------------------; - cd cp_tests; \ - echo A file > afile; \ - mkdir here there; \ - cd here; \ - ln -s ../afile . - - cd cp_tests; \ - ls -lR . > ../cp_a_symlink.gnu; \ - ${GCP} -a here/afile there; \ - ls -lR . >> ../cp_a_symlink.gnu; - - @echo; - rm -rf cp_tests/there/*; - - sleep 1; - - @echo; - cd cp_tests; \ - echo A file > afile; \ - ls -lR . > ../cp_a_symlink.bb; \ - ${BCP} -a here/afile there; \ - ls -lR . >> ../cp_a_symlink.bb; - - @echo; - diff -u cp_a_symlink.gnu cp_a_symlink.bb; - - @echo; - rm -rf cp_tests/*; - - -check_cp_files_to_dir: - # Copy a set of files to a directory. - @echo; echo Copy a set of files to a directory.; - @echo ------------------------------; - cd cp_tests; \ - echo A file number one > afile1; \ - echo A file number two, blah. > afile2; \ - ln -s afile1 symlink1; \ - mkdir there; - - cd cp_tests; \ - ${GCP} afile1 afile2 symlink1 there/; \ - ls -lR > ../cp_files_dir.gnu; - - @echo; - rm -rf cp_tests/there/*; - - @echo; - cd cp_tests; \ - ${BCP} afile1 afile2 symlink1 there/; \ - ls -lR > ../cp_files_dir.bb; - - @echo; - diff -u cp_files_dir.gnu cp_files_dir.bb; - - @echo; - rm -rf cp_tests/*; - -check_cp_files_to_dir_w_d: - # Copy a set of files to a directory with the -d switch. - @echo; echo Copy a set of files to a directory with the -d switch.; - @echo ------------------------------; - cd cp_tests; \ - echo A file number one > afile1; \ - echo A file number two, blah. > afile2; \ - ln -s afile1 symlink1; \ - mkdir there1; \ - ${GCP} -d afile1 afile2 symlink1 there1/; \ - ls -lR > ../cp_d_files_dir.gnu; - - @echo; - rm -rf cp_tests/{afile{1,2},symlink1,there1}; - - @echo; - cd cp_tests; \ - echo A file number one > afile1; \ - echo A file number two, blah. > afile2; \ - ln -s afile1 symlink1; \ - mkdir there1; \ - ${BCP} -d afile1 afile2 symlink1 there1/; \ - ls -lR > ../cp_d_files_dir.bb; - - @echo; - diff -u cp_d_files_dir.gnu cp_d_files_dir.bb; - - @echo; - rm -rf cp_tests/{afile{1,2},symlink1,there1}; - -check_cp_files_to_dir_w_p: - # Copy a set of files to a directory with the -p switch. - @echo; echo Copy a set of files to a directory with the -p switch.; - @echo ------------------------------; - cd cp_tests; \ - echo A file number one > afile1; \ - echo A file number two, blah. > afile2; \ - touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \ - ln -s afile1 symlink1; \ - mkdir there1; \ - ${GCP} -p afile1 afile2 symlink1 there1/; \ - ls -lR > ../cp_p_files_dir.gnu; - - @echo; - rm -rf cp_tests/{afile{1,2},symlink1,there1}; - - @echo; - cd cp_tests; \ - echo A file number one > afile1; \ - echo A file number two, blah. > afile2; \ - touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \ - ln -s afile1 symlink1; \ - mkdir there1; \ - ${BCP} -p afile1 afile2 symlink1 there1/; \ - ls -lR > ../cp_p_files_dir.bb; - - @echo; - diff -u cp_p_files_dir.gnu cp_p_files_dir.bb; - - @echo; - rm -rf cp_tests/{afile{1,2},symlink1,there1}; - - -check_cp_files_to_dir_w_p_and_d: - @echo; echo Copy a set of files to a directory with -p and -d switches. - @echo ------------------------------; - cd cp_tests; \ - echo A file number one > afile1; \ - echo A file number two, blah. > afile2; \ - touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \ - ln -s afile1 symlink1; \ - mkdir there1; \ - ${GCP} -p -d afile1 afile2 symlink1 there1/; \ - ls -lR > ../cp_pd_files_dir.gnu; - - @echo; - rm -rf cp_tests/{afile{1,2},symlink1,there1}; - - @echo; - cd cp_tests; \ - echo A file number one > afile1; \ - echo A file number two, blah. > afile2; \ - touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \ - ln -s afile1 symlink1; \ - mkdir there1; \ - ${BCP} -p -d afile1 afile2 symlink1 there1/; \ - ls -lR > ../cp_pd_files_dir.bb; - - @echo; - diff -u cp_pd_files_dir.gnu cp_pd_files_dir.bb; - - @echo; - rm -rf cp_tests/{afile{1,2},symlink1,there1}; - -# This test doesn't work any more; gnu cp now _does_ copy a directory -# to a subdirectory of itself. What's worse, that "feature" has no -# (documented) way to be disabled with command line switches. -# It's not obvious that busybox cp should mimic this behavior. -# For now, this test is removed from the cp_tests list, above. -check_cp_dir_to_dir_wo_a: - # Copy a directory to another directory, without the -a switch. - @echo; echo Copy a directory to another directory, without the -a switch. - @echo ------------------------------; - @echo There should be an error message about cannot cp a dir to a subdir of itself. - cd cp_tests; \ - touch a b c; \ - mkdir adir; \ - ls -lR . > ../cp_a_star_adir.gnu; \ - ${GCP} -a * adir; \ - ls -lR . >> ../cp_a_star_adir.gnu; - - @echo - @echo There should be an error message about cannot cp a dir to a subdir of itself. - cd cp_tests; \ - rm -rf adir; \ - mkdir adir; \ - ls -lR . > ../cp_a_star_adir.bb; \ - ${BCP} -a * adir; \ - ls -lR . >> ../cp_a_star_adir.bb; - - @echo; - diff -u cp_a_star_adir.gnu cp_a_star_adir.bb; - - # Done - @echo; - rm -rf cp_tests; - @echo; echo Done. - - -check_cp_dir_to_dir_w_a: - @echo; echo Copy a directory into another directory with the -a switch. - @echo ------------------------------; - cd cp_tests; \ - mkdir dir{a,b}; \ - echo A file > dira/afile; \ - echo A file in dirb > dirb/afileindirb; \ - ln -s dira/afile dira/alinktoafile; \ - mkdir dira/subdir1; \ - echo Another file > dira/subdir1/anotherfile; \ - ls -lR . > ../cp_a_dira_dirb.gnu; \ - ${GCP} -a dira dirb; \ - ls -lR . >> ../cp_a_dira_dirb.gnu; - - @echo; - rm -rf cp_tests/dir{a,b}; - - @echo; - cd cp_tests; \ - mkdir dir{a,b}; \ - echo A file > dira/afile; \ - echo A file in dirb > dirb/afileindirb; \ - ln -s dira/afile dira/alinktoafile; \ - mkdir dira/subdir1; \ - echo Another file > dira/subdir1/anotherfile; \ - ls -lR . > ../cp_a_dira_dirb.bb; \ - ${BCP} -a dira dirb; \ - ls -lR . >> ../cp_a_dira_dirb.bb; - - @echo; - diff -u cp_a_dira_dirb.gnu cp_a_dira_dirb.bb; - - @echo; - rm -rf cp_tests/dir{a,b}; - - -check_cp_dir_to_dir_w_a_take_two: - @echo; echo Copy a directory into another directory with the -a switch; - @echo ------------------------------; - mkdir -p cp_tests/gnu; \ - mkdir -p cp_tests/bb; \ - cd cp_tests; \ - mkdir here there; \ - echo A file > here/afile; \ - mkdir here/adir; \ - touch here/adir/afileinadir; \ - ln -s $$(pwd) here/alink; - - @echo; - cd cp_tests/gnu; \ - ls -lR . > ../../cp_a_dir_dir.gnu; \ - ${GCP} -a here/ there/; \ - ls -lR . >> ../../cp_a_dir_dir.gnu; - - @echo; - rm -rf cp_tests/there/*; - - sleep 1; - - @echo; - cd cp_tests/bb; \ - ls -lR . > ../../cp_a_dir_dir.bb; \ - ${BCP} -a here/ there/; \ - ls -lR . >> ../../cp_a_dir_dir.bb; - - @echo; - echo "Erik 1" - diff -u cp_a_dir_dir.gnu cp_a_dir_dir.bb; - echo "Erik 2" - - @echo; - echo "Erik 3" - rm -rf cp_tests/*; - - diff --git a/busybox/tests/ln_tests.mk b/busybox/tests/ln_tests.mk deleted file mode 100644 index 3110f8199..000000000 --- a/busybox/tests/ln_tests.mk +++ /dev/null @@ -1,71 +0,0 @@ -# ln_tests.mk - Set of tests for busybox ln -# ------------- -# Copyright (C) 2000 Karl M. Hegbloom GPL -# - -# GNU `ln' -GLN = /bin/ln -# BusyBox `ln' -BLN = $(shell pwd)/ln - -all:: ln_tests -clean:: ln_clean - -ln_clean: - rm -rf ln_tests ln_*.{gnu,bb} ln - -ln_tests: ln_clean ln - @echo; - @echo "No output from diff means busybox ln is functioning properly."; - - @echo; - ${BLN} || true; - - @echo; - mkdir ln_tests; - - @echo; - cd ln_tests; \ - echo A file > afile; \ - ls -l afile > ../ln_afile_newname.gnu; \ - ${GLN} afile newname; \ - ls -l afile newname >> ../ln_afile_newname.gnu; - - @echo; - rm -f ln_tests/{afile,newname}; - - @echo; - cd ln_tests; \ - echo A file > afile; \ - ls -l afile > ../ln_afile_newname.bb; \ - ${BLN} afile newname; \ - ls -l afile newname >> ../ln_afile_newname.bb; - - @echo; - diff -u ln_afile_newname.gnu ln_afile_newname.bb - - @echo; - rm -f ln_tests/{afile,newname}; - - @echo; - cd ln_tests; \ - echo A file > afile; \ - ls -l afile > ../ln_s_afile_newname.gnu; \ - ${GLN} -s afile newname; \ - ls -l afile newname >> ../ln_s_afile_newname.gnu; - - @echo; - rm -f ln_tests/{afile,newname}; - - @echo; - cd ln_tests; \ - echo A file > afile; \ - ls -l afile > ../ln_s_afile_newname.bb; \ - ${BLN} -s afile newname; \ - ls -l afile newname >> ../ln_s_afile_newname.bb; - - @echo; - diff -u ln_s_afile_newname.gnu ln_s_afile_newname.bb - - @echo; - rm -f ln_tests/{afile,newname}; diff --git a/busybox/tests/multibuild.pl b/busybox/tests/multibuild.pl deleted file mode 100755 index 94930bd95..000000000 --- a/busybox/tests/multibuild.pl +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/perl - -# multibuild.pl -# Tests BusyBox-0.48 (at least) to see if each applet builds -# properly on its own. The most likely problems this will -# flush out are those involving preprocessor instructions in -# utility.c. -# -# TODO: some time it might be nice to list absolute and -# differential object sizes for each option... -# - -$logfile = "multibuild.log"; - -# How to handle all the BB_FEATURE_FOO lines -if ($ARGV[0] eq "-all" ) { shift(@ARGV); $choice="all"; } -if ($ARGV[0] eq "-none") { shift(@ARGV); $choice="none"; } -# neither means, leave that part of Config.h alone - -# Support building from pristine source -$make_opt = "-f $ARGV[0]/Makefile BB_SRC_DIR=$ARGV[0]" if ($ARGV[0] ne ""); - -# Move the config file to a safe place --e "Config.h.orig" || 0==system("mv -f Config.h Config.h.orig") || die; - -# Clear previous log file, if any -unlink($logfile); - -# Parse the config file -open(C,") { - if ($in_trailer) { - if (!$in_olympus) { - s/^\/\/#/#/ if ($choice eq "all" && !/USE_DEVPS_PATCH/); - s/^#/\/\/#/ if ($choice eq "none"); - } - $in_olympus=1 if /End of Features List/; - $trailer .= $_; - } else { - $in_trailer=1 if /End of Applications List/; - if (/^\/*#define BB_([A-Z0-9_]*)/) { - push @apps, $1; - } - } -} -close C; - -# Do the real work ... -$failed_tests=0; -for $a (@apps) { - # print "Testing build of applet $a ...\n"; - open (O, ">Config.h") || die; - print O "#define BB_$a\n", $trailer; - close O; - system("echo -e '\n***\n$a\n***' >>$logfile"); - # With a fast computer and 1-second resolution on file timestamps, this - # process pushes beyond the limits of what unix make can understand. - # That's why need to weed out obsolete files before restarting make. - $result{$a} = system("rm -f *.o applet_source_list; make $make_opt busybox >>$logfile 2>&1"); - $flag = $result{$a} ? "FAILED!!!" : "ok"; - printf("Applet %-20s: %s\n", $a, $flag); - $total_tests++; - $failed_tests++ if $flag eq "FAILED!!!"; - # pause long enough to let user stop us with a ^C - select(undef, undef, undef, 0.03); -} - -# Clean up our mess -system("mv -f Config.h.orig Config.h"); - -print "$total_tests applets tested, $failed_tests failures\n"; -print "See $logfile for details.\n"; - diff --git a/busybox/tests/multifeat.pl b/busybox/tests/multifeat.pl deleted file mode 100755 index adcb30bbd..000000000 --- a/busybox/tests/multifeat.pl +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/perl -# -# multifeat.pl -# -# Turns on all applets, then tests turning on one feature at a time through -# iterative compilations. Tests if any features depend on each other in any -# weird ways or such-like problems. -# -# Hacked by Mark Whitley, but based *heavily* on multibuild.pl which was -# written by Larry Doolittle. - -$logfile = "multifeat.log"; - -# How to handle all the BB_APPLET lines -# (most thorough testing occurs when you call it with the -all switch) -if ($ARGV[0] eq "-all" ) { shift(@ARGV); $choice="all"; } -if ($ARGV[0] eq "-none") { shift(@ARGV); $choice="none"; } -# neither means, leave that part of Config.h alone - -# Support building from pristine source -$make_opt = "-f $ARGV[0]/Makefile BB_SRC_DIR=$ARGV[0]" if ($ARGV[0] ne ""); - -# Move the config file to a safe place --e "Config.h.orig" || 0==system("mv -f Config.h Config.h.orig") || die; - -# Clear previous log file, if any -unlink($logfile); - -# Parse the config file -open(C,") { - if ($in_applist) { - s/^\/\/#/#/ if ($choice eq "all"); - s/^#/\/\/#/ if ($choice eq "none"); - $header .= $_; - if (/End of Applications List/) { - $in_applist=0; - $in_features=1 - } - } - elsif ($in_features) { - if (/^\/*#define BB_FEATURE_([A-Z0-9_]*)/) { - push @features, $1; - } - if (/End of Features List/) { - $in_features=0; - $in_olympus=1 - } - } elsif ($in_olympus) { - $trailer .= $_; - } -} -close C; - -# Do the real work ... -$failed_tests=0; -for $f (@features) { - # print "Testing build with feature $f ...\n"; - open (O, ">Config.h") || die; - print O $header, "#define BB_FEATURE_$f\n", $trailer; - close O; - system("echo -e '\n***\n$f\n***' >>$logfile"); - # With a fast computer and 1-second resolution on file timestamps, this - # process pushes beyond the limits of what unix make can understand. - # That's why need to weed out obsolete files before restarting make. - $result{$f} = system("rm -f *.o applet_source_list; make $make_opt busybox >>$logfile 2>&1"); - $flag = $result{$f} ? "FAILED!!!" : "ok"; - printf("Feature %-20s: %s\n", $f, $flag); - $total_tests++; - $failed_tests++ if $flag eq "FAILED!!!"; - # pause long enough to let user stop us with a ^C - select(undef, undef, undef, 0.03); -} - -# Clean up our mess -system("mv -f Config.h.orig Config.h"); - -print "$total_tests applets tested, $failed_tests failures\n"; -print "See $logfile for details.\n"; - diff --git a/busybox/tests/mv_tests.mk b/busybox/tests/mv_tests.mk deleted file mode 100644 index f03e08a73..000000000 --- a/busybox/tests/mv_tests.mk +++ /dev/null @@ -1,167 +0,0 @@ -# mv_tests.mk - Set of tests cases for busybox mv -# ------------- -# Copyright (C) 2000 Karl M. Hegbloom GPL -# - -# GNU `mv' -GMV = /bin/mv -# BusyBox `mv' -BMV = $(shell pwd)/mv - -all:: mv_tests -clean:: mv_clean - -mv_clean: - rm -rf mv_tests mv_*.{gnu,bb} mv - -mv_tests: mv_clean mv - @echo; - @echo "No output from diff means busybox mv is functioning properly."; - @echo; - @echo "No such file or directory is good; it means the old file got removed."; - @echo; - ${BMV} || true; - - @echo; - mkdir mv_tests; - - @echo; - cd mv_tests; \ - echo A file > afile; \ - ls -l afile > ../mv_afile_newname.gnu; \ - ${GMV} afile newname; \ - ls -l newname >> ../mv_afile_newname.gnu; - -ls -l mv_tests/afile; - - @echo; - rm -f mv_tests/{afile,newname}; - - @echo; - cd mv_tests; \ - echo A file > afile; \ - ls -l afile > ../mv_afile_newname.bb; \ - ${BMV} afile newname; \ - ls -l newname >> ../mv_afile_newname.bb; - -ls -l mv_tests/afile; - - @echo; - diff -u mv_afile_newname.gnu mv_afile_newname.bb; - - @echo; - rm -f mv_tests/{afile,newname}; - - @echo; echo ------------------------------; - cd mv_tests; \ - echo A file > afile; \ - ln -s afile symlink; \ - ls -l afile symlink > ../mv_symlink_newname.gnu; \ - ${GMV} symlink newname; \ - ls -l afile newname >> ../mv_symlink_newname.gnu; - -ls -l mv_tests/symlink; - - @echo; - rm -f mv_tests/{afile,newname}; - - @echo; - cd mv_tests; \ - echo A file > afile; \ - ln -s afile symlink; \ - ls -l afile symlink > ../mv_symlink_newname.bb;\ - ${BMV} symlink newname; \ - ls -l afile newname >> ../mv_symlink_newname.bb; - -ls -l mv_tests/symlink; - - @echo; - diff -u mv_symlink_newname.gnu mv_symlink_newname.bb; - - @echo; - rm -rf mv_tests/*; - - @echo; echo ------------------------------; - cd mv_tests; \ - echo A file > afile; \ - ln -s afile symlink; \ - mkdir newdir; \ - ls -lR > ../mv_file_symlink_dir.gnu; \ - ${GMV} symlink afile newdir; \ - ls -lR >> ../mv_file_symlink_dir.gnu; - -ls -l mv_tests/{symlink,afile}; - - @echo; - rm -rf mv_tests/* - - @echo; echo ------------------------------; - cd mv_tests; \ - echo A file > afile; \ - ln -s afile symlink; \ - mkdir newdir; \ - ls -lR > ../mv_file_symlink_dir.bb; \ - ${BMV} symlink afile newdir; \ - ls -lR >> ../mv_file_symlink_dir.bb; - -ls -l mv_tests/{symlink,afile}; - - @echo; - diff -u mv_file_symlink_dir.gnu mv_file_symlink_dir.bb; - - @echo; - rm -rf mv_tests/*; - - @echo; echo ------------------------------; - cd mv_tests; \ - mkdir dir{a,b}; \ - echo A file > dira/afile; \ - echo A file in dirb > dirb/afileindirb; \ - ln -s dira/afile dira/alinktoafile; \ - mkdir dira/subdir1; \ - echo Another file > dira/subdir1/anotherfile; \ - ls -lR . > ../mv_dira_dirb.gnu; \ - ${GMV} dira dirb; \ - ls -lR . >> ../mv_dira_dirb.gnu; - - # false; - @echo; - rm -rf mv_tests/dir{a,b}; - - @echo; - cd mv_tests; \ - mkdir dir{a,b}; \ - echo A file > dira/afile; \ - echo A file in dirb > dirb/afileindirb; \ - ln -s dira/afile dira/alinktoafile; \ - mkdir dira/subdir1; \ - echo Another file > dira/subdir1/anotherfile; \ - ls -lR . > ../mv_dira_dirb.bb; \ - ${BMV} dira dirb; \ - ls -lR . >> ../mv_dira_dirb.bb; - - @echo; - diff -u mv_dira_dirb.gnu mv_dira_dirb.bb; - - # false; - @echo; - rm -rf mv_tests/dir{a,b}; - - @echo; echo ------------------------------; - @echo There should be an error message about cannot mv a dir to a subdir of itself. - cd mv_tests; \ - mkdir adir; \ - touch -r . a b c adir; \ - ls -lR . > ../mv_a_star_adir.gnu; \ - ${GMV} * adir; \ - ls -lR . >> ../mv_a_star_adir.gnu; - - @echo - @echo There should be an error message about cannot mv a dir to a subdir of itself. - cd mv_tests; \ - rm -rf a b c adir; \ - mkdir adir; \ - touch -r . a b c adir; \ - ls -lR . > ../mv_a_star_adir.bb; \ - ${BMV} * adir; \ - ls -lR . >> ../mv_a_star_adir.bb; - - @echo; - diff -u mv_a_star_adir.gnu mv_a_star_adir.bb; - - @echo; - rm -rf mv_test/*; diff --git a/busybox/tests/sh.testcases b/busybox/tests/sh.testcases deleted file mode 100644 index e2a75873e..000000000 --- a/busybox/tests/sh.testcases +++ /dev/null @@ -1,89 +0,0 @@ -# try running this with bash, ksh, ash, and hush. - -# simple quoting rules. -echo a b -echo "a b" -echo a "" b -echo a '' b -echo hello? -echo "hello?" -echo t* hello -echo t\* hello - -# quick and painless exit for lash -if false; then true; exit; fi - -# fairly simple command substitution -echo `echo -e foo\\\necho bar` - -echo THIS IS A TEST >foo -cat $(echo FOO | tr 'A-Z' 'a-z') -cat foo | tr 'A-Z' 'a-z' -cat $(echo FOO | tr 'A-Z' 'a-z') | tr 'A-Z' 'a-z' - -cat foo | if true; then tr 'A-Z' 'a-z'; else echo bar1; fi -cat foo | if false; then tr 'A-Z' 'a-z'; else echo bar2; fi -if true; then tr 'A-Z' 'a-z'; else echo bar3; fi foo 2>&1 -cat foo -cat doesnt_exist >foo 2>&1 -tr 'a-z' 'A-Z' $TMP -ls fish - -# ash, lash, and hush do not create fish; bash and ksh do. -# Thanks to Tapani Tarvainen for this stress test. -unset TMP -rm -f fish -TMP=fish >$TMP -ls fish - -# The following example shows that hush's parser is -# not _really_ Bourne compatible -echo "echo Hello World" >"a=b" -unset a -chmod a+x "a=b" -PATH=$PATH:. -"a=b" -echo $a - -# assuming the shell wasn't too buggy, clean up the mess -rm -f a=b fish foo diff --git a/busybox/tests/syslog_test.c b/busybox/tests/syslog_test.c deleted file mode 100644 index fb4c691b1..000000000 --- a/busybox/tests/syslog_test.c +++ /dev/null @@ -1,19 +0,0 @@ -#include - -int do_log(char* msg, int delay) -{ - openlog("testlog", LOG_PID, LOG_DAEMON); - while(1) { - syslog(LOG_ERR, "%s: testing one, two, three\n", msg); - sleep(delay); - } - closelog(); - return(0); -}; - -int main(void) -{ - if (fork()==0) - do_log("A", 2); - do_log("B", 3); -} diff --git a/busybox/tests/testcases b/busybox/tests/testcases deleted file mode 100644 index 2aad9b651..000000000 --- a/busybox/tests/testcases +++ /dev/null @@ -1,404 +0,0 @@ -# testcases -# -# This file should be filled with test cases to test applets that: -# -# - can somehow produce output (we can't test sync or sleep) -# - have a GNU (or other) counterpart -# - are not interactive (don't require a ^C or anything) -# - don't require extensive setup or cleanup (a litte setup is fine) -# - don't have huge and possibly damaging effects (fsck, swapoff) -# -# If possible, a test case should be made that tests each option the applet -# supports. When a new option is added, a new test case should be written for -# it. When somebody reports a bug with a testcase, that testcase should be -# added here as well. -# -# Some other guidelines to follow: -# -# - please try to keep applets alphabetized, it will make life easier -# - use the file tester.sh or testcases when you need to do a non-destructive -# test on a file (i.e., cat, md5sum) -# - try to make the applet you're testing the first thing on the line (this -# not always possible) -# - (???) if you have to create a temporary file, call it TMPFILE -# - pipe symbols that represent real pipes need a space in front of them -# (so the test script can find them and add the "../busybox" after it). -# - pipe symbols that are not used for pipes need to be shell-escaped, -# with a double \. See the expr test cases. - - -# ar - -# basename -basename `pwd` - -# cat -cat tester.sh -echo hello there | cat tester.sh - - -# chmod -# chown -# chgrp -# chroot -# chvt - can't be tested here -# clear - can't be tested here -# cmp -# cp - -# cut -echo "1234" | cut -c1 -echo "1234" | cut -c 1 -echo "1234567890" | cut -c2-7 -echo "1234567890" | cut -c 2-7 -echo "f1 f2" | cut -f2 -echo "f1 f2" | cut -f 2 -echo "f1 f2 f3 f4 f5" | cut -f2-4 -echo "f1 f2 f3 f4 f5" | cut -f 2-4 - -# date -date -date -R -date -u -date +%d/%m/%y - -# dc - needs an input file - -# dd -# BUG: record count line goes to stdout instead of stderr -dd if=/dev/urandom of=O bs=1k count=1 ; ls -l O ; rm O - -# deallocvt - -# df -# XXX: minor formatting differences -df -df . -df -k -df -h -df -m - -# dirname -dirname `pwd` - -# dmesg (XXX: change the silly cmd business in the source) -dmesg -dmesg -n 8 -dmesg -s 512 -# I really don't want to do this next one -#dmesg -c - -# dos2unix - needs an input file -# dpkg -# dpkg_deb - -# du -# BUG: rounding behavior differs from GNU du -du -du -s -du -l -du -k -du -h -du -m - -# dumpkmap - no counterprt? -# dutmp - no counterprt? - -# echo -echo "foo bar baz" -echo -n "no newline" - - -# expr -expr 1 \\| 1 -expr 1 \\| 0 -expr 0 \\| 1 -expr 0 \\| 0 - -expr 1 \\& 1 -expr 1 \\& 0 -expr 0 \\& 1 -expr 0 \\& 0 - -expr 0 \\< 1 -expr 1 \\< 0 - -expr 1 \\> 0 -expr 0 \\> 1 - -expr 0 \\<= 1 -expr 1 \\<= 0 -expr 1 \\<= 1 - -expr 1 \\>= 0 -expr 0 \\>= 1 -expr 1 \\>= 1 - -expr 1 + 2 -expr 2 - 1 -expr 2 \\* 3 -expr 12 / 2 -expr 12 % 5 - -# somebody else can do all the string stuff - - -# fbset - can't be tested here -# fdflush -# find -find . - -# free -# XXX: minor formatting differences -free - -# freeramdisk -# fsck.minix - won't test -# getopt - -# grep -grep -l strdup ../*.c -grep -c strdup ../*.c -grep -lc strdup ../*.c -grep -cv strdup ../*.c -grep -i null ../grep.c -grep -e strdup -e regcomp -e atexit ../grep.c - -# gunzip - -# gzip -# XXX: compressed output differs from gzip-1.2.4, but decompresses fine -echo testing 1 2 3 >tmpfile1; gzip tmpfile1; echo tmpfile*; md5sum tmpfile1.gz; rm tmpfile1.gz -echo testing 1 2 3 | gzip >tmpfile1.gz; md5sum tmpfile1.gz; rm tmpfile1.gz - - -# halt - won't test, dangerous - -# head -head tester.sh -head -n 2 tester.sh - -# hostid -hostid - -# hostname -# XXX: minor formatting differences -hostname -hostname -s -hostname -i -hostname -d -# not going to do this next one -#hostname -F - -# id -# BUG: Busybox id doesn't print supplemental groups -id -id -u -id -g -id -ur -id -un - - -# ifconfig -# requires BB_FEATURE_IFCONFIG_STATUS -ifconfig -#ifconfig -a -#ifconfig eth0 -#ifconfig lo - -# init - won't test -# insmod - won't test - -# kill -#kill -l -# not going to do any more - -# length -# ln - see ln_tests.mk -# loadacm -# loadfont -# loadkmap -# logger -# logname - -# ls -# XXX: minor formatting differences -ls ../e* -ls -l ../e* -ls -s ../e* -ls -h ../e* -ls -1 ../e* - -# lsmod -lsmod - -# makedevs - -# md5sum -md5sum tester.sh - -# mkdir -mkdir D ; ls -ld D ; rmdir D - -# mkfifo -# -# we will test making one. actually testing pushing data through it requires -# more interaction than we can manage here. -# (these lines turn up an existing ls bug) -mkfifo F ; ls -l F ; rm F -mkfifo -m 0600 F ; ls -l F ; rm F - -# mkfs.minix - won't test -# mknod -# mkswap - won't test -# mktemp -# more - can't test: interactive - -# mount -# BUG: proc line starts with /proc instead of proc -mount -# not going to test mount with any args, can't be done safely or sanely - -# mt -# mv - see mv_tests.mk -# nc -# nfsmount -# nslookup -# ping -ping -c 3 yahoo.com -# pivot_root -# poweroff - won't test -# printf -# ps - there's lotsa differences between busybox ps and any other ps - -# pwd -pwd - -# rdate - won't test - -# readlink -ln -sf tester.sh L ; readlink L ; rm -f L - -# reboot - won't test -# renice - won't test -# reset - can't test: no output - -# rm -touch F ; rm F - -# rmdir -# rmmod - won't test: dangerous - -# route -# XXX: doesn't DNS resolve -route - -# rpm2cpio - -# sed - we can do some one-liners here, some testing is a little -# difficult to do in just this space (like a,i,c cmds). - -# test ^$ matching -echo foo | sed -ne '/^$/p' -echo -e "foo\\n\\nbar" | sed -ne '/^$/p' - -sed -e '/test$/d' testcases -sed -e '/^echo/d' testcases -sed -e '/test/s/dangerous/PELIGROSO/' testcases -sed -ne '1,/getopt/p' ../pwd.c -sed -e '/getopt/r ../pwd.c' ../sed.c - - -# setkeycodes - -# sh - note that we cannot test the shell interactively here -sh -c "echo a b c" -sh -c ">" -sh -c "a" -sh sh.testcases - - -# sleep - can't test: produces no output - -# sort -sort tester.sh -sort -n tester.sh -sort -r tester.sh - -# stty -# swapon - won't test: dangerous -# swapoff - won't test: dangerous -# sync - can't test: no output -# syslogd - won't test: too involved - -# tail -tail tester.sh -tail -n 2 tester.sh - -# tar - -# tee -echo "please tee me!" | tee A B C ; cat A B C -echo "please tee me!" | tee A B C ; echo "tee me too!" | tee -a A B C ; cat A B C ; rm A B C - -# telnet - can't test: interactive - -# test -# tftp - -# touch -touch tmpfile1; ls tmpfile1; rm -f tmpfile1 -touch -c tmpfile1; ls tmpfile1; rm -f tmpfile1 - -# tr -# BUG: Busybox tr range handling minix style [a-z] instead of GNU # style a-z -echo "cbaab" | tr abc zyx -echo "TESTING A B C" | tr [A-Z] [a-z] -# not GNU compatible -echo fdhrnzvfu bffvsentr | tr [a-z] [n-z][a-m] -echo abc[] | tr a[b AXB -echo testing | tr -d aeiou - -# true -true ; echo $? - -# false -false ; echo $? - -# tty -# umount -# uname -# uniq -# unix2dos -# update - -# uptime -# BUG: doesn't print number of users -uptime - -# usleep -# uudecode -# uuencode -# watchdog - -# wc -wc tester.sh -wc -c tester.sh -wc -w tester.sh -wc -l tester.sh -wc -L tester.sh - -# wget - -# which -which ls - -# whoami -whoami - -# xargs -# XXX: Busygox xargs divides filenames with '\n' instead of ' ' -ls -1 ../e* | xargs -ls -1 ../e* | xargs md5sum - -# yes - can't test: interactive (needs ^C) - diff --git a/busybox/tests/tester.sh b/busybox/tests/tester.sh deleted file mode 100755 index a767c6c7f..000000000 --- a/busybox/tests/tester.sh +++ /dev/null @@ -1,158 +0,0 @@ -#!/bin/bash -# -# tester.sh - reads testcases from file and tests busybox applets vs GNU -# counterparts -# -# This should be run from within the tests/ directory. Before you run it, you -# should compile up a busybox that has all applets and all features turned on. - -# set up defaults (can be changed with cmd-line options) -BUSYBOX=../busybox -TESTCASES=testcases -LOGFILE=tester.log -BB_OUT=bb.out -GNU_OUT=gnu.out -SETUP="" -CLEANUP="" -KEEPTMPFILES="no" -DEBUG=2 - - -#while getopts 'p:t:l:b:g:s:c:kd:' opt -while getopts 'p:t:l:s:c:kd:' opt -do - case $opt in - p) BUSYBOX=$OPTARG; ;; - t) TESTCASES=$OPTARG; ;; - l) LOGFILE=$OPTARG; ;; -# b) BB_OUT=$OPTARG; ;; -# g) GNU_OUT=$OPTARG; ;; - s) SETUP=$OPTARG; ;; - c) CLEANUP=$OPTARG; ;; - k) KEEPTMPFILES="yes"; ;; - d) DEBUG=$OPTARG; ;; - *) - echo "usage: $0 [-ptlbgsc]" - echo " -p PATH path to busybox executable (default=$BUSYBOX)" - echo " -t FILE run testcases in FILE (default=$TESTCASES)" - echo " -l FILE log test results in FILE (default=$LOGFILE)" -# echo " -b FILE store temporary busybox output in FILE" -# echo " -g FILE store temporary GNU output in FILE" - echo " -s FILE (setup) run commands in FILE before testcases" - echo " -c FILE (cleanup) run commands in FILE after testcases" - echo " -k keep temporary output files (don't delete them)" - echo " -d NUM set level of debugging output" - echo " 0 = no output" - echo " 1 = output failures / whoops lines only" - echo " 2 = (default) output setup / cleanup msgs and testcase lines" - echo " 3+= other debug noise (internal stuff)" - exit 1 - ;; - esac -done -#shift `expr $OPTIND - 1` - - -# maybe print some debug output -if [ $DEBUG -ge 3 ] -then - echo "BUSYBOX=$BUSYBOX" - echo "TESTCASES=$TESTCASES" - echo "LOGFILE=$LOGFILE" - echo "BB_OUT=$BB_OUT" - echo "GNU_OUT=$GNU_OUT" - echo "SETUP=$SETUP" - echo "CLEANUP=$CLEANUP" - echo "DEBUG=$DEBUG" -fi - - -# do sanity checks -if [ ! -e $BUSYBOX ] -then - echo "Busybox executable: $BUSYBOX not found!" - exit 1 -fi - -if [ ! -e $TESTCASES ] -then - echo "Testcases file: $TESTCASES not found!" - exit 1 -fi - - -# do normal setup -[ -e $LOGFILE ] && rm $LOGFILE -unalias -a # gets rid of aliases that might create different output - - -# do extra setup (if any) -if [ ! -z "$SETUP" ] -then - [ $DEBUG -ge 2 ] && echo "running setup commands in $SETUP" - source $SETUP -fi - - -# go through each line in the testcase file -cat $TESTCASES | while read line -do - #echo $line - # only process non-blank lines and non-comment lines - if [ "$line" ] - then - if [ `echo "$line" | cut -c1` != "#" ] - then - - # test if the applet was compiled into busybox - # (this only tests the applet at the beginning of the line) - #applet=`echo $line | cut -d' ' -f1` - applet=`echo $line | sed 's/\(^[^ ;]*\)[ ;].*/\1/'` - $BUSYBOX 2>&1 | grep -qw $applet - if [ $? -eq 1 ] - then - echo "WHOOPS: $applet not compiled into busybox" | tee -a $LOGFILE - else - - # execute line using gnu / system programs - [ $DEBUG -ge 2 ] && echo "testing: $line" | tee -a $LOGFILE - sh -c "$line" > $GNU_OUT - - # change line to include "busybox" before every statement - line="$BUSYBOX $line" - # is this a bash-2-ism? - # line=${line//;/; $BUSYBOX } - # line=${line//|/| $BUSYBOX } - # assume $BUSYBOX has no commas - line=`echo "$line" | sed -e 's,;,; '$BUSYBOX, \ - -e 's, |, | '$BUSYBOX,` - - # execute line using busybox programs - [ $DEBUG -ge 2 ] && echo "testing: $line" | tee -a $LOGFILE - sh -c "$line" > $BB_OUT - - # see if they match - diff -q $BB_OUT $GNU_OUT > /dev/null - if [ $? -eq 1 ] - then - [ $DEBUG -ge 1 ] && echo "FAILED: $line" | tee -a $LOGFILE - diff -u $BB_OUT $GNU_OUT >> $LOGFILE - fi - fi - fi - fi -done - -[ $DEBUG -gt 0 ] && echo "Finished. Results are in $LOGFILE" - - -# do normal cleanup -[ "$KEEPTMPFILES" = "no" ] && rm -f $BB_OUT $GNU_OUT - - -# do extra cleanup (if any) -if [ ! -z "$CLEANUP" ] -then - [ $DEBUG -ge 2 ] && echo "running cleanup commands in $CLEANUP" - source $CLEANUP -fi diff --git a/busybox/tests/tst-syslogd.c b/busybox/tests/tst-syslogd.c deleted file mode 100644 index bae10afdf..000000000 --- a/busybox/tests/tst-syslogd.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * tst-syslogd.c - tests concurrent threads calling syslog - * - * build with: gcc -Wall tst-syslogd.c -lpthread - */ - -#include -#include -#include -#include - -void *log_func(void *arg) -{ - int i; - int thrid = (int)arg; - - openlog(NULL, LOG_PERROR | LOG_PID, LOG_USER); - for (i = 0; i < 10; i++) { - syslog(LOG_DEBUG, "thread %i iter %i\n", thrid, i); - sleep(thrid); /* this mixes things up a bit */ - } - closelog(); - - return NULL; -} - -int main(int argc, char **argv) -{ - pthread_t thr1, thr2, thr3; - int id1 = 1; - int id2 = 2; - int id3 = 3; - - pthread_create(&thr1, NULL, log_func, (void *)id1); - pthread_create(&thr2, NULL, log_func, (void *)id2); - pthread_create(&thr3, NULL, log_func, (void *)id3); - - pthread_join(thr1, NULL); - pthread_join(thr2, NULL); - pthread_join(thr3, NULL); - - return 0; -} - diff --git a/busybox/tftp.c b/busybox/tftp.c deleted file mode 100644 index 999b5d706..000000000 --- a/busybox/tftp.c +++ /dev/null @@ -1,383 +0,0 @@ -/* ------------------------------------------------------------------------- */ -/* tftp.c */ -/* */ -/* A simple tftp client for busybox. */ -/* Tries to follow RFC1350. */ -/* Only "octet" mode and 512-byte data blocks are supported. */ -/* */ -/* Copyright (C) 2001 Magnus Damm */ -/* */ -/* Parts of the code based on: */ -/* */ -/* atftp: Copyright (C) 2000 Jean-Pierre Lefebvre */ -/* and Remi Lefebvre */ -/* */ -/* utftp: Copyright (C) 1999 Uwe Ohse */ -/* */ -/* 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 -#include -#include - -#include "busybox.h" - -//#define BB_FEATURE_TFTP_DEBUG - -static const char *tftp_error_msg[] = { - "Undefined error", - "File not found", - "Access violation", - "Disk full or allocation error", - "Illegal TFTP operation", - "Unknown transfer ID", - "File already exists", - "No such user" -}; - -const int tftp_cmd_get = 1; -const int tftp_cmd_put = 2; - -static inline int tftp(const int cmd, const struct hostent *host, - const char *serverfile, int localfd, const int port, int tftp_bufsize) -{ - const int cmd_get = cmd & tftp_cmd_get; - const int cmd_put = cmd & tftp_cmd_put; - const int bb_tftp_num_retries = 5; - - struct sockaddr_in sa; - struct sockaddr_in from; - struct timeval tv; - socklen_t fromlen; - fd_set rfds; - char *cp; - unsigned short tmp; - int socketfd; - int len; - int opcode = 0; - int finished = 0; - int timeout = bb_tftp_num_retries; - int block_nr = 1; - RESERVE_BB_BUFFER(buf, tftp_bufsize + 4); // Why 4 ? - - tftp_bufsize += 4; - - if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { - perror_msg("socket"); - return EXIT_FAILURE; - } - - len = sizeof(sa); - - memset(&sa, 0, len); - bind(socketfd, (struct sockaddr *)&sa, len); - - sa.sin_family = host->h_addrtype; - sa.sin_port = htons(port); - memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr, - sizeof(sa.sin_addr)); - - /* build opcode */ - - if (cmd_get) { - opcode = 1; // read request = 1 - } - - if (cmd_put) { - opcode = 2; // write request = 2 - } - - while (1) { - - - /* build packet of type "opcode" */ - - - cp = buf; - - *((unsigned short *) cp) = htons(opcode); - - cp += 2; - - /* add filename and mode */ - - if ((cmd_get && (opcode == 1)) || // read request = 1 - (cmd_put && (opcode == 2))) { // write request = 2 - - /* what is this trying to do ? */ - while (cp != &buf[tftp_bufsize - 1]) { - if ((*cp = *serverfile++) == '\0') - break; - cp++; - } - /* and this ? */ - if ((*cp != '\0') || (&buf[tftp_bufsize - 1] - cp) < 7) { - error_msg("too long server-filename"); - break; - } - - memcpy(cp + 1, "octet", 6); - cp += 7; - } - - /* add ack and data */ - - if ((cmd_get && (opcode == 4)) || // acknowledgement = 4 - (cmd_put && (opcode == 3))) { // data packet == 3 - - *((unsigned short *) cp) = htons(block_nr); - - cp += 2; - - block_nr++; - - if (cmd_put && (opcode == 3)) { // data packet == 3 - len = read(localfd, cp, tftp_bufsize - 4); - - if (len < 0) { - perror_msg("read"); - break; - } - - if (len != (tftp_bufsize - 4)) { - finished++; - } - - cp += len; - } else if (finished) { - break; - } - } - - - /* send packet */ - - - do { - - len = cp - buf; - -#ifdef BB_FEATURE_TFTP_DEBUG - printf("sending %u bytes\n", len); - for (cp = buf; cp < &buf[len]; cp++) - printf("%02x ", *cp); - printf("\n"); -#endif - if (sendto(socketfd, buf, len, 0, - (struct sockaddr *) &sa, sizeof(sa)) < 0) { - perror_msg("send"); - len = -1; - break; - } - - - /* receive packet */ - - - memset(&from, 0, sizeof(from)); - fromlen = sizeof(from); - - tv.tv_sec = 5; // BB_TFPT_TIMEOUT = 5 - tv.tv_usec = 0; - - FD_ZERO(&rfds); - FD_SET(socketfd, &rfds); - - switch (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) { - case 1: - len = recvfrom(socketfd, buf, tftp_bufsize, 0, - (struct sockaddr *) &from, &fromlen); - - if (len < 0) { - perror_msg("recvfrom"); - break; - } - - timeout = 0; - - if (sa.sin_port == htons(port)) { - sa.sin_port = from.sin_port; - } - if (sa.sin_port == from.sin_port) { - break; - } - - /* fall-through for bad packets! */ - /* discard the packet - treat as timeout */ - timeout = bb_tftp_num_retries; - - case 0: - error_msg("timeout"); - - if (timeout == 0) { - len = -1; - error_msg("last timeout"); - } else { - timeout--; - } - break; - - default: - perror_msg("select"); - len = -1; - } - - } while (timeout && (len >= 0)); - - if (len < 0) { - break; - } - - /* process received packet */ - - - opcode = ntohs(*((unsigned short *) buf)); - tmp = ntohs(*((unsigned short *) &buf[2])); - -#ifdef BB_FEATURE_TFTP_DEBUG - printf("received %d bytes: %04x %04x\n", len, opcode, tmp); -#endif - - if (cmd_get && (opcode == 3)) { // data packet == 3 - - if (tmp == block_nr) { - len = write(localfd, &buf[4], len - 4); - - if (len < 0) { - perror_msg("write"); - break; - } - - if (len != (tftp_bufsize - 4)) { - finished++; - } - - opcode = 4; // acknowledgement = 4 - continue; - } - } - - if (cmd_put && (opcode == 4)) { // acknowledgement = 4 - - if (tmp == (block_nr - 1)) { - if (finished) { - break; - } - - opcode = 3; // data packet == 3 - continue; - } - } - - if (opcode == 5) { // error code == 5 - char *msg = NULL; - - if (buf[4] != '\0') { - msg = &buf[4]; - buf[tftp_bufsize - 1] = '\0'; - } else if (tmp < (sizeof(tftp_error_msg) / sizeof(char *))) { - msg = (char *) tftp_error_msg[tmp]; - } - - if (msg) { - error_msg("server says: %s", msg); - } - - break; - } - } - - close(socketfd); - - return finished ? EXIT_SUCCESS : EXIT_FAILURE; -} - -int tftp_main(int argc, char **argv) -{ - struct hostent *host = NULL; - char *localfile = NULL; - char *remotefile = NULL; - int port = 69; - int cmd = 0; - int fd = -1; - int flags = 0; - int opt; - int result; - int blocksize = 512; - - while ((opt = getopt(argc, argv, "b:gpl:r:")) != -1) { - switch (opt) { - case 'b': - blocksize = atoi(optarg); - break; -#ifdef BB_FEATURE_TFTP_GET - case 'g': - cmd = tftp_cmd_get; - flags = O_WRONLY | O_CREAT; - break; -#endif -#ifdef BB_FEATURE_TFTP_PUT - case 'p': - cmd = tftp_cmd_put; - flags = O_RDONLY; - break; -#endif - case 'l': - localfile = xstrdup(optarg); - break; - case 'r': - remotefile = xstrdup(optarg); - break; - } - } - - if ((cmd == 0) || (optind == argc)) { - show_usage(); - } - - fd = open(localfile, flags, 0644); - if (fd < 0) { - perror_msg_and_die("local file"); - } - - host = xgethostbyname(argv[optind]); - - if (optind + 2 == argc) { - port = atoi(argv[optind + 1]); - } - -#ifdef BB_FEATURE_TFTP_DEBUG - printf("using server \"%s\", serverfile \"%s\"," - "localfile \"%s\".\n", - inet_ntoa(*((struct in_addr *) host->h_addr)), - remotefile, localfile); -#endif - - result = tftp(cmd, host, remotefile, fd, port, blocksize); - close(fd); - - return(result); -} \ No newline at end of file diff --git a/busybox/touch.c b/busybox/touch.c deleted file mode 100644 index 1718da71e..000000000 --- a/busybox/touch.c +++ /dev/null @@ -1,75 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini touch implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -extern int touch_main(int argc, char **argv) -{ - int fd; - int create = TRUE; - - /* Parse options */ - while (--argc > 0 && **(++argv) == '-') { - while (*(++(*argv))) { - switch (**argv) { - case 'c': - create = FALSE; - break; - default: - show_usage(); - } - } - } - - if (argc < 1) { - show_usage(); - } - - while (argc > 0) { - fd = open(*argv, (create == FALSE) ? O_RDWR : O_RDWR | O_CREAT, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); - if (fd < 0) { - if (create == FALSE && errno == ENOENT) - return EXIT_SUCCESS; - else { - perror_msg_and_die("%s", *argv); - } - } - close(fd); - if (utime(*argv, NULL)) { - perror_msg_and_die("%s", *argv); - } - argc--; - argv++; - } - - return EXIT_SUCCESS; -} diff --git a/busybox/tr.c b/busybox/tr.c deleted file mode 100644 index 5b7b8d091..000000000 --- a/busybox/tr.c +++ /dev/null @@ -1,248 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini tr implementation for busybox - * - * Copyright (c) Michiel Huisjes - * - * This version of tr is adapted from Minix tr and was modified - * by Erik Andersen to be used in busybox. - * - * 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 - * - * Original copyright notice is retained at the end of this file. - */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -/* This must be a #define, since when DODEBUG 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() -{ - 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) - error_msg("%s", 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) - error_msg_and_die("%s", write_error); - out_index = 0; - } - } - - /* NOTREACHED */ -} - -static void map(register unsigned char *string1, unsigned int string1_len, - register unsigned char *string2, unsigned int string2_len) -{ - unsigned char last = '0'; - unsigned int i, j; - - for (j = 0, i = 0; i < string1_len; i++) { - if (string2_len <= j) - pvector[string1[i]] = last; - else - pvector[string1[i]] = last = string2[j++]; - } -} - -/* supported constructs: - * Ranges, e.g., [0-9] ==> 0123456789 - * Escapes, e.g., \a ==> Control-G - */ -static unsigned int expand(const char *arg, register unsigned char *buffer) -{ - unsigned char *buffer_start = buffer; - int i, ac; - - while (*arg) { - if (*arg == '\\') { - arg++; - *buffer++ = process_escape_sequence(&arg); - } else if (*(arg+1) == '-') { - ac = *(arg+2); - if(ac == 0) { - *buffer++ = *arg++; - continue; - } - i = *arg; - while (i <= ac) - *buffer++ = i++; - arg += 3; /* Skip the assumed a-z */ - } else if (*arg == '[') { - arg++; - i = *arg++; - if (*arg++ != '-') { - *buffer++ = '['; - arg -= 2; - continue; - } - ac = *arg++; - while (i <= ac) - *buffer++ = i++; - arg++; /* Skip the assumed ']' */ - } else - *buffer++ = *arg++; - } - - return (buffer - buffer_start); -} - -static int complement(unsigned char *buffer, int buffer_len) -{ - register short i, j, ix; - char conv[ASCII + 2]; - - 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; - } - memcpy(buffer, conv, ix); - return ix; -} - -extern int tr_main(int argc, char **argv) -{ - register unsigned char *ptr; - int output_length=0, input_length; - int idx = 1; - int i; - RESERVE_BB_BUFFER(output, BUFSIZ); - RESERVE_BB_BUFFER(input, BUFSIZ); - RESERVE_BB_UBUFFER(vector, ASCII+1); - RESERVE_BB_BUFFER(invec, ASCII+1); - RESERVE_BB_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: - show_usage(); - } - } - idx++; - } - for (i = 0; i <= ASCII; i++) { - vector[i] = i; - invec[i] = outvec[i] = FALSE; - } - - 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') - 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; - } - convert(); - return (0); -} - -/* - * 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. - * - */ - diff --git a/busybox/traceroute.c b/busybox/traceroute.c deleted file mode 100644 index a3abd0a00..000000000 --- a/busybox/traceroute.c +++ /dev/null @@ -1,652 +0,0 @@ -/*- - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Van Jacobson. - * - * Special for busybox ported by Vladimir Oleynik 2001 - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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. - */ - -/* - * traceroute host - trace the route ip packets follow going to "host". - * Notes - * ----- - * This program must be run by root or be setuid. (I suggest that - * you *don't* make it setuid -- casual use could result in a lot - * of unnecessary traffic on our poor, congested nets.) - * - * I stole the idea for this program from Steve Deering. Since - * the first release, I've learned that had I attended the right - * IETF working group meetings, I also could have stolen it from Guy - * Almes or Matt Mathis. I don't know (or care) who came up with - * the idea first. I envy the originators' perspicacity and I'm - * glad they didn't keep the idea a secret. - * - * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or - * enhancements to the original distribution. - * - * I've hacked up a round-trip-route version of this that works by - * sending a loose-source-routed udp datagram through the destination - * back to yourself. Unfortunately, SO many gateways botch source - * routing, the thing is almost worthless. Maybe one day... - * - * -- Van Jacobson (van@helios.ee.lbl.gov) - * Tue Dec 20 03:50:13 PST 1988 - */ - -#undef BB_FEATURE_TRACEROUTE_VERBOSE -//#define BB_FEATURE_TRACEROUTE_VERBOSE -#undef BB_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - /* It turns out that libc5 doesn't have proper icmp support - * built into it header files, so we have to supplement it */ -#if __GNU_LIBRARY__ < 5 -static const int ICMP_MINLEN = 8; /* abs minimum */ - -struct icmp_ra_addr -{ - u_int32_t ira_addr; - u_int32_t ira_preference; -}; - - -struct icmp -{ - u_int8_t icmp_type; /* type of message, see below */ - u_int8_t icmp_code; /* type sub code */ - u_int16_t icmp_cksum; /* ones complement checksum of struct */ - union - { - u_char ih_pptr; /* ICMP_PARAMPROB */ - struct in_addr ih_gwaddr; /* gateway address */ - struct ih_idseq /* echo datagram */ - { - u_int16_t icd_id; - u_int16_t icd_seq; - } ih_idseq; - u_int32_t ih_void; - - /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ - struct ih_pmtu - { - u_int16_t ipm_void; - u_int16_t ipm_nextmtu; - } ih_pmtu; - - struct ih_rtradv - { - u_int8_t irt_num_addrs; - u_int8_t irt_wpa; - u_int16_t irt_lifetime; - } ih_rtradv; - } icmp_hun; -#define icmp_pptr icmp_hun.ih_pptr -#define icmp_gwaddr icmp_hun.ih_gwaddr -#define icmp_id icmp_hun.ih_idseq.icd_id -#define icmp_seq icmp_hun.ih_idseq.icd_seq -#define icmp_void icmp_hun.ih_void -#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void -#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu -#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs -#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa -#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime - union - { - struct - { - u_int32_t its_otime; - u_int32_t its_rtime; - u_int32_t its_ttime; - } id_ts; - struct - { - struct ip idi_ip; - /* options and then 64 bits of data */ - } id_ip; - struct icmp_ra_addr id_radv; - u_int32_t id_mask; - u_int8_t id_data[1]; - } icmp_dun; -#define icmp_otime icmp_dun.id_ts.its_otime -#define icmp_rtime icmp_dun.id_ts.its_rtime -#define icmp_ttime icmp_dun.id_ts.its_ttime -#define icmp_ip icmp_dun.id_ip.idi_ip -#define icmp_radv icmp_dun.id_radv -#define icmp_mask icmp_dun.id_mask -#define icmp_data icmp_dun.id_data -}; - -#define ICMP_MINLEN 8 /* abs minimum */ -#define ICMP_UNREACH 3 /* dest unreachable, codes: */ -#define ICMP_TIMXCEED 11 /* time exceeded, code: */ -#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ -#define ICMP_UNREACH_NET 0 /* bad net */ -#define ICMP_UNREACH_HOST 1 /* bad host */ -#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ -#define ICMP_UNREACH_PORT 3 /* bad port */ -#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ -#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ -#endif - - -#define MAXPACKET 65535 /* max ip packet size */ -#ifndef MAXHOSTNAMELEN -#define MAXHOSTNAMELEN 64 -#endif - -/* - * format of a (udp) probe packet. - */ -struct opacket { - struct ip ip; - struct udphdr udp; - u_char seq; /* sequence number of this packet */ - u_char ttl; /* ttl packet left with */ - struct timeval tv; /* time packet left */ -}; - -/* - * Definitions for internet protocol version 4. - * Per RFC 791, September 1981. - */ -#define IPVERSION 4 - - -#include "busybox.h" - -static u_char packet[512]; /* last inbound (icmp) packet */ -static struct opacket *outpacket; /* last output (udp) packet */ - -static int s; /* receive (icmp) socket file descriptor */ -static int sndsock; /* send (udp) socket file descriptor */ - -static struct sockaddr whereto; /* Who to try to reach */ -static int datalen; /* How much data */ - -static char *hostname; - -static int max_ttl = 30; -static u_short ident; -static u_short port = 32768+666; /* start udp dest port # for probe packets */ - -#ifdef BB_FEATURE_TRACEROUTE_VERBOSE -static int verbose; -#endif -static int waittime = 5; /* time to wait for response (in seconds) */ -static int nflag; /* print addresses numerically */ - -/* - * Construct an Internet address representation. - * If the nflag has been supplied, give - * numeric value, otherwise try for symbolic name. - */ -static inline void -inetname(struct sockaddr_in *from) -{ - char *cp; - struct hostent *hp; - static char domain[MAXHOSTNAMELEN + 1]; - static int first = 1; - const char *ina; - - if (first && !nflag) { - first = 0; - if (gethostname(domain, MAXHOSTNAMELEN) == 0 && - (cp = strchr(domain, '.'))) - (void) strcpy(domain, cp + 1); - else - domain[0] = 0; - } - cp = 0; - if (!nflag && from->sin_addr.s_addr != INADDR_ANY) { - hp = gethostbyaddr((char *)&(from->sin_addr), sizeof (from->sin_addr), AF_INET); - if (hp) { - if ((cp = strchr(hp->h_name, '.')) && - !strcmp(cp + 1, domain)) - *cp = 0; - cp = (char *)hp->h_name; - } - } - ina = inet_ntoa(from->sin_addr); - if (nflag) - printf(" %s", ina); - else - printf(" %s (%s)", (cp ? cp : ina), ina); -} - -static inline void -print(u_char *buf, int cc, struct sockaddr_in *from) -{ - struct ip *ip; - int hlen; - - ip = (struct ip *) buf; - hlen = ip->ip_hl << 2; - cc -= hlen; - - inetname(from); -#ifdef BB_FEATURE_TRACEROUTE_VERBOSE - if (verbose) - printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); -#endif -} - -static inline double -deltaT(struct timeval *t1p, struct timeval *t2p) -{ - double dt; - - dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + - (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; - return (dt); -} - -static inline int -wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer) -{ - fd_set fds; - static struct timeval wait; - int cc = 0; - int fromlen = sizeof (*from); - - FD_ZERO(&fds); - FD_SET(sock, &fds); - if (reset_timer) { - /* - * traceroute could hang if someone else has a ping - * running and our ICMP reply gets dropped but we don't - * realize it because we keep waking up to handle those - * other ICMP packets that keep coming in. To fix this, - * "reset_timer" will only be true if the last packet that - * came in was for us or if this is the first time we're - * waiting for a reply since sending out a probe. Note - * that this takes advantage of the select() feature on - * Linux where the remaining timeout is written to the - * struct timeval area. - */ - wait.tv_sec = waittime; - wait.tv_usec = 0; - } - - if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0) - cc=recvfrom(s, (char *)packet, sizeof(packet), 0, - (struct sockaddr *)from, &fromlen); - - return(cc); -} - -#ifdef BB_FEATURE_TRACEROUTE_VERBOSE -/* - * Convert an ICMP "type" field to a printable string. - */ -static inline const char * -pr_type(t) - u_char t; -{ - static const char * const ttab[] = { - "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", - "Source Quench", "Redirect", "ICMP 6", "ICMP 7", - "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", - "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", - "Info Reply" - }; - - if(t > 16) - return("OUT-OF-RANGE"); - - return(ttab[t]); -} -#endif - -static inline int -packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq) -{ - struct icmp *icp; - u_char type, code; - int hlen; - struct ip *ip; - - ip = (struct ip *) buf; - hlen = ip->ip_hl << 2; - if (cc < hlen + ICMP_MINLEN) { -#ifdef BB_FEATURE_TRACEROUTE_VERBOSE - if (verbose) - printf("packet too short (%d bytes) from %s\n", cc, - inet_ntoa(from->sin_addr)); -#endif - return (0); - } - cc -= hlen; - icp = (struct icmp *)(buf + hlen); - type = icp->icmp_type; code = icp->icmp_code; - if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || - type == ICMP_UNREACH) { - struct ip *hip; - struct udphdr *up; - - hip = &icp->icmp_ip; - hlen = hip->ip_hl << 2; - up = (struct udphdr *)((u_char *)hip + hlen); - if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP && - up->source == htons(ident) && - up->dest == htons(port+seq)) - return (type == ICMP_TIMXCEED? -1 : code+1); - } -#ifdef BB_FEATURE_TRACEROUTE_VERBOSE - if (verbose) { - int i; - u_long *lp = (u_long *)&icp->icmp_ip; - - printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n", - cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst), - type, pr_type(type), icp->icmp_code); - for (i = 4; i < cc ; i += sizeof(long)) - printf("%2d: x%8.8lx\n", i, *lp++); - } -#endif - return(0); -} - -static void /* not inline */ -send_probe(int seq, int ttl) -{ - struct opacket *op = outpacket; - struct ip *ip = &op->ip; - struct udphdr *up = &op->udp; - int i; - struct timezone tz; - - ip->ip_off = 0; - ip->ip_hl = sizeof(*ip) >> 2; - ip->ip_p = IPPROTO_UDP; - ip->ip_len = datalen; - ip->ip_ttl = ttl; - ip->ip_v = IPVERSION; - ip->ip_id = htons(ident+seq); - - up->source = htons(ident); - up->dest = htons(port+seq); - up->len = htons((u_short)(datalen - sizeof(struct ip))); - up->check = 0; - - op->seq = seq; - op->ttl = ttl; - (void) gettimeofday(&op->tv, &tz); - - i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto, - sizeof(struct sockaddr)); - if (i < 0 || i != datalen) { - if (i<0) - perror("sendto"); - printf("traceroute: wrote %s %d chars, ret=%d\n", hostname, - datalen, i); - (void) fflush(stdout); - } -} - - -int -#ifndef BB_TRACEROUTE -main(argc, argv) -#else -traceroute_main(argc, argv) -#endif - int argc; - char *argv[]; -{ - extern char *optarg; - extern int optind; - struct hostent *hp; - struct sockaddr_in from, *to; - int ch, i, on, probe, seq, tos, ttl; - - int options = 0; /* socket options */ - char *source = 0; - int nprobes = 3; - - on = 1; - seq = tos = 0; - to = (struct sockaddr_in *)&whereto; - while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF) - switch(ch) { - case 'd': -#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG - options |= SO_DEBUG; -#endif - break; - case 'm': - max_ttl = atoi(optarg); - if (max_ttl <= 1) - error_msg_and_die("max ttl must be >1."); - break; - case 'n': - nflag++; - break; - case 'p': - port = atoi(optarg); - if (port < 1) - error_msg_and_die("port must be >0."); - break; - case 'q': - nprobes = atoi(optarg); - if (nprobes < 1) - error_msg_and_die("nprobes must be >0."); - break; - case 'r': - options |= SO_DONTROUTE; - break; - case 's': - /* - * set the ip source address of the outbound - * probe (e.g., on a multi-homed host). - */ - source = optarg; - break; - case 't': - tos = atoi(optarg); - if (tos < 0 || tos > 255) - error_msg_and_die("tos must be 0 to 255."); - break; - case 'v': -#ifdef BB_FEATURE_TRACEROUTE_VERBOSE - verbose++; -#endif - break; - case 'w': - waittime = atoi(optarg); - if (waittime <= 1) - error_msg_and_die("wait must be >1 sec."); - break; - default: - show_usage(); - } - argc -= optind; - argv += optind; - - if (argc < 1) - show_usage(); - - setlinebuf (stdout); - - memset(&whereto, 0, sizeof(struct sockaddr)); - hp = xgethostbyname(*argv); - to->sin_family = hp->h_addrtype; - memcpy(&to->sin_addr, hp->h_addr, hp->h_length); - hostname = (char *)hp->h_name; - if (*++argv) - datalen = atoi(*argv); - if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) - error_msg_and_die("packet size must be 0 <= s < %d.", - MAXPACKET - sizeof(struct opacket)); - datalen += sizeof(struct opacket); - outpacket = (struct opacket *)xmalloc((unsigned)datalen); - memset(outpacket, 0, datalen); - outpacket->ip.ip_dst = to->sin_addr; - outpacket->ip.ip_tos = tos; - outpacket->ip.ip_v = IPVERSION; - outpacket->ip.ip_id = 0; - - ident = (getpid() & 0xffff) | 0x8000; - - if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) - perror_msg_and_die(can_not_create_raw_socket); - - s = create_icmp_socket(); - -#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG - if (options & SO_DEBUG) - (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, - (char *)&on, sizeof(on)); -#endif - if (options & SO_DONTROUTE) - (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, - (char *)&on, sizeof(on)); -#ifdef SO_SNDBUF - if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, - sizeof(datalen)) < 0) - perror_msg_and_die("SO_SNDBUF"); -#endif SO_SNDBUF -#ifdef IP_HDRINCL - if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, - sizeof(on)) < 0) - perror_msg_and_die("IP_HDRINCL"); -#endif IP_HDRINCL -#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG - if (options & SO_DEBUG) - (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, - (char *)&on, sizeof(on)); -#endif - if (options & SO_DONTROUTE) - (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, - (char *)&on, sizeof(on)); - - if (source) { - memset(&from, 0, sizeof(struct sockaddr)); - from.sin_family = AF_INET; - from.sin_addr.s_addr = inet_addr(source); - if (from.sin_addr.s_addr == -1) - error_msg_and_die("unknown host %s", source); - outpacket->ip.ip_src = from.sin_addr; -#ifndef IP_HDRINCL - if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) - perror_msg_and_die("bind"); -#endif IP_HDRINCL - } - - fprintf(stderr, "traceroute to %s (%s)", hostname, - inet_ntoa(to->sin_addr)); - if (source) - fprintf(stderr, " from %s", source); - fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen); - - for (ttl = 1; ttl <= max_ttl; ++ttl) { - u_long lastaddr = 0; - int got_there = 0; - int unreachable = 0; - - printf("%2d ", ttl); - for (probe = 0; probe < nprobes; ++probe) { - int cc, reset_timer; - struct timeval t1, t2; - struct timezone tz; - struct ip *ip; - - (void) gettimeofday(&t1, &tz); - send_probe(++seq, ttl); - reset_timer = 1; - while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) { - (void) gettimeofday(&t2, &tz); - if ((i = packet_ok(packet, cc, &from, seq))) { - reset_timer = 1; - if (from.sin_addr.s_addr != lastaddr) { - print(packet, cc, &from); - lastaddr = from.sin_addr.s_addr; - } - printf(" %g ms", deltaT(&t1, &t2)); - switch(i - 1) { - case ICMP_UNREACH_PORT: - ip = (struct ip *)packet; - if (ip->ip_ttl <= 1) - printf(" !"); - ++got_there; - break; - case ICMP_UNREACH_NET: - ++unreachable; - printf(" !N"); - break; - case ICMP_UNREACH_HOST: - ++unreachable; - printf(" !H"); - break; - case ICMP_UNREACH_PROTOCOL: - ++got_there; - printf(" !P"); - break; - case ICMP_UNREACH_NEEDFRAG: - ++unreachable; - printf(" !F"); - break; - case ICMP_UNREACH_SRCFAIL: - ++unreachable; - printf(" !S"); - break; - } - break; - } else - reset_timer = 0; - } - if (cc == 0) - printf(" *"); - (void) fflush(stdout); - } - putchar('\n'); - if (got_there || unreachable >= nprobes-1) - exit(0); - } - - return 0; -} diff --git a/busybox/true_false.c b/busybox/true_false.c deleted file mode 100644 index 76183431c..000000000 --- a/busybox/true_false.c +++ /dev/null @@ -1,39 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini true/false implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -/* getopt not needed */ - -#include -#include "busybox.h" - - -extern int true_main(int argc, char **argv) -{ - return EXIT_SUCCESS; -} - -extern int false_main(int argc, char **argv) -{ - return EXIT_FAILURE; -} diff --git a/busybox/tty.c b/busybox/tty.c deleted file mode 100644 index 4510c2996..000000000 --- a/busybox/tty.c +++ /dev/null @@ -1,44 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini tty implementation for busybox - * - * 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 - * - */ - -#include -#include -#include -#include -#include "busybox.h" - -extern int tty_main(int argc, char **argv) -{ - char *tty; - - if (argc > 1) { - if (argv[1][0] != '-' || argv[1][1] != 's') - show_usage(); - } else { - tty = ttyname(0); - if (tty) - puts(tty); - else - puts("not a tty"); - } - return(isatty(0) ? EXIT_SUCCESS : EXIT_FAILURE); -} diff --git a/busybox/umount.c b/busybox/umount.c deleted file mode 100644 index 74638d21c..000000000 --- a/busybox/umount.c +++ /dev/null @@ -1,298 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini umount implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -/* Teach libc5 about realpath -- it includes it but the - * prototype is missing... */ -#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1) -extern char *realpath(const char *path, char *resolved_path); -#endif - -static const int MNT_FORCE = 1; -static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */ -static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS. */ -static const int MS_RDONLY = 1; /* Mount read-only. */ - -extern int mount (__const char *__special_file, __const char *__dir, - __const char *__fstype, unsigned long int __rwflag, - __const void *__data); -extern int umount (__const char *__special_file); -extern int umount2 (__const char *__special_file, int __flags); - -struct _mtab_entry_t { - char *device; - char *mountpt; - struct _mtab_entry_t *next; -}; - -static struct _mtab_entry_t *mtab_cache = NULL; - - - -#if defined BB_FEATURE_MOUNT_FORCE -static int doForce = FALSE; -#endif -#if defined BB_FEATURE_MOUNT_LOOP -static int freeLoop = TRUE; -#endif -#if defined BB_FEATURE_MTAB_SUPPORT -static int useMtab = TRUE; -#endif -static int umountAll = FALSE; -static int doRemount = FALSE; -extern const char mtab_file[]; /* Defined in utility.c */ - - - -/* These functions are here because the getmntent functions do not appear - * to be re-entrant, which leads to all sorts of problems when we try to - * use them recursively - randolph - * - * TODO: Perhaps switch to using Glibc's getmntent_r - * -Erik - */ -static void mtab_read(void) -{ - struct _mtab_entry_t *entry = NULL; - struct mntent *e; - FILE *fp; - - if (mtab_cache != NULL) - return; - - if ((fp = setmntent(mtab_file, "r")) == NULL) { - error_msg("Cannot open %s", mtab_file); - return; - } - while ((e = getmntent(fp))) { - entry = xmalloc(sizeof(struct _mtab_entry_t)); - entry->device = strdup(e->mnt_fsname); - entry->mountpt = strdup(e->mnt_dir); - entry->next = mtab_cache; - mtab_cache = entry; - } - endmntent(fp); -} - -static char *mtab_getinfo(const char *match, const char which) -{ - struct _mtab_entry_t *cur = mtab_cache; - - while (cur) { - if (strcmp(cur->mountpt, match) == 0 || - strcmp(cur->device, match) == 0) { - if (which == MTAB_GETMOUNTPT) { - return cur->mountpt; - } else { -#if !defined BB_FEATURE_MTAB_SUPPORT - if (strcmp(cur->device, "/dev/root") == 0) { - /* Adjusts device to be the real root device, - * or leaves device alone if it can't find it */ - cur->device = find_real_root_device_name(cur->device); - } -#endif - return cur->device; - } - } - cur = cur->next; - } - return NULL; -} - -static char *mtab_next(void **iter) -{ - char *mp; - - if (iter == NULL || *iter == NULL) - return NULL; - mp = ((struct _mtab_entry_t *) (*iter))->mountpt; - *iter = (void *) ((struct _mtab_entry_t *) (*iter))->next; - return mp; -} - -static char *mtab_first(void **iter) -{ - struct _mtab_entry_t *mtab_iter; - - if (!iter) - return NULL; - mtab_iter = mtab_cache; - *iter = (void *) mtab_iter; - return mtab_next(iter); -} - -/* Don't bother to clean up, since exit() does that - * automagically, so we can save a few bytes */ -#ifdef BB_FEATURE_CLEAN_UP -static void mtab_free(void) -{ - struct _mtab_entry_t *this, *next; - - this = mtab_cache; - while (this) { - next = this->next; - if (this->device) - free(this->device); - if (this->mountpt) - free(this->mountpt); - free(this); - this = next; - } -} -#endif - -static int do_umount(const char *name) -{ - int status; - char *blockDevice = mtab_getinfo(name, MTAB_GETDEVICE); - - if (blockDevice && strcmp(blockDevice, name) == 0) - name = mtab_getinfo(blockDevice, MTAB_GETMOUNTPT); - - status = umount(name); - -#if defined BB_FEATURE_MOUNT_LOOP - if (freeLoop == TRUE && blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9)) - /* this was a loop device, delete it */ - del_loop(blockDevice); -#endif -#if defined BB_FEATURE_MOUNT_FORCE - if (status != 0 && doForce == TRUE) { - status = umount2(blockDevice, MNT_FORCE); - if (status != 0) { - error_msg_and_die("forced umount of %s failed!", blockDevice); - } - } -#endif - if (status != 0 && doRemount == TRUE && errno == EBUSY) { - status = mount(blockDevice, name, NULL, - MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL); - if (status == 0) { - error_msg("%s busy - remounted read-only", blockDevice); - } else { - error_msg("Cannot remount %s read-only", blockDevice); - } - } - if (status == 0) { -#if defined BB_FEATURE_MTAB_SUPPORT - if (useMtab == TRUE) - erase_mtab(name); -#endif - return (TRUE); - } - return (FALSE); -} - -static int umount_all(void) -{ - int status = TRUE; - char *mountpt; - void *iter; - - for (mountpt = mtab_first(&iter); mountpt; mountpt = mtab_next(&iter)) { - /* Never umount /proc on a umount -a */ - if (strstr(mountpt, "proc")!= NULL) - continue; - if (!do_umount(mountpt)) { - /* Don't bother retrying the umount on busy devices */ - if (errno == EBUSY) { - perror_msg("%s", mountpt); - status = FALSE; - continue; - } - if (!do_umount(mountpt)) { - printf("Couldn't umount %s on %s: %s\n", - mountpt, mtab_getinfo(mountpt, MTAB_GETDEVICE), - strerror(errno)); - status = FALSE; - } - } - } - return (status); -} - -extern int umount_main(int argc, char **argv) -{ - char path[PATH_MAX]; - - if (argc < 2) { - show_usage(); - } -#ifdef BB_FEATURE_CLEAN_UP - atexit(mtab_free); -#endif - - /* Parse any options */ - while (--argc > 0 && **(++argv) == '-') { - while (*++(*argv)) - switch (**argv) { - case 'a': - umountAll = TRUE; - break; -#if defined BB_FEATURE_MOUNT_LOOP - case 'l': - freeLoop = FALSE; - break; -#endif -#ifdef BB_FEATURE_MTAB_SUPPORT - case 'n': - useMtab = FALSE; - break; -#endif -#ifdef BB_FEATURE_MOUNT_FORCE - case 'f': - doForce = TRUE; - break; -#endif - case 'r': - doRemount = TRUE; - break; - case 'v': - break; /* ignore -v */ - default: - show_usage(); - } - } - - mtab_read(); - if (umountAll == TRUE) { - if (umount_all() == TRUE) - return EXIT_SUCCESS; - else - return EXIT_FAILURE; - } - if (realpath(*argv, path) == NULL) - perror_msg_and_die("%s", path); - if (do_umount(path) == TRUE) - return EXIT_SUCCESS; - perror_msg_and_die("%s", *argv); -} - diff --git a/busybox/uname.c b/busybox/uname.c deleted file mode 100644 index f7e2291a8..000000000 --- a/busybox/uname.c +++ /dev/null @@ -1,156 +0,0 @@ -/* 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. */ - -/* 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 */ - -/* Busyboxed by Erik Andersen */ - -#include -#include -#include -#include -#include - -#if defined (HAVE_SYSINFO) && defined (HAVE_SYS_SYSTEMINFO_H) -# include -#endif -#include "busybox.h" - -static void print_element(unsigned int mask, char *element); - -/* Values that are bitwise or'd into `toprint'. */ -/* Operating system name. */ -static const int PRINT_SYSNAME = 1; - -/* Node name on a communications network. */ -static const int PRINT_NODENAME = 2; - -/* Operating system release. */ -static const int PRINT_RELEASE = 4; - -/* Operating system version. */ -static const int PRINT_VERSION = 8; - -/* Machine hardware name. */ -static const int PRINT_MACHINE = 16; - - /* Host processor type. */ -static const int PRINT_PROCESSOR = 32; - -/* Mask indicating which elements of the name to print. */ -static unsigned char toprint; - - -int uname_main(int argc, char **argv) -{ - struct utsname name; - char processor[256]; - -#if defined(__sparc__) && defined(__linux__) - char *fake_sparc = getenv("FAKE_SPARC"); -#endif - - toprint = 0; - - /* Parse any options */ - //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv); - while (--argc > 0 && **(++argv) == '-') { - while (*(++(*argv))) { - switch (**argv) { - case 's': - toprint |= PRINT_SYSNAME; - break; - case 'n': - toprint |= PRINT_NODENAME; - break; - case 'r': - toprint |= PRINT_RELEASE; - break; - case 'v': - toprint |= PRINT_VERSION; - break; - case 'm': - toprint |= PRINT_MACHINE; - break; - case 'p': - toprint |= PRINT_PROCESSOR; - break; - case 'a': - toprint = (PRINT_SYSNAME | PRINT_NODENAME | PRINT_RELEASE | - PRINT_PROCESSOR | PRINT_VERSION | - PRINT_MACHINE); - break; - default: - show_usage(); - } - } - } - - if (toprint == 0) - toprint = PRINT_SYSNAME; - - if (uname(&name) == -1) - perror_msg("cannot get system name"); - -#if defined (HAVE_SYSINFO) && defined (SI_ARCHITECTURE) - if (sysinfo(SI_ARCHITECTURE, processor, sizeof(processor)) == -1) - perror_msg("cannot get processor type"); -} - -#else - strcpy(processor, "unknown"); -#endif - -#if defined(__sparc__) && defined(__linux__) - if (fake_sparc != NULL - && (fake_sparc[0] == 'y' - || fake_sparc[0] == 'Y')) strcpy(name.machine, "sparc"); -#endif - - print_element(PRINT_SYSNAME, name.sysname); - print_element(PRINT_NODENAME, name.nodename); - print_element(PRINT_RELEASE, name.release); - print_element(PRINT_VERSION, name.version); - print_element(PRINT_MACHINE, name.machine); - print_element(PRINT_PROCESSOR, processor); - - return EXIT_SUCCESS; -} - -/* If the name element set in MASK is selected for printing in `toprint', - print ELEMENT; then print a space unless it is the last element to - be printed, in which case print a newline. */ - -static void print_element(unsigned int mask, char *element) -{ - if (toprint & mask) { - toprint &= ~mask; - printf("%s%c", element, toprint ? ' ' : '\n'); - } -} diff --git a/busybox/uniq.c b/busybox/uniq.c deleted file mode 100644 index 53e3c64f2..000000000 --- a/busybox/uniq.c +++ /dev/null @@ -1,89 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini uniq implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by John Beppu - * Rewritten 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 - * - */ - -#include -#include -#include -#include -#include -#include "busybox.h" - -static int print_count; -static int print_uniq = 1; -static int print_duplicates = 1; - -static void print_line(char *line, int count, FILE *fp) -{ - if ((print_duplicates && count > 1) || (print_uniq && count == 1)) { - if (print_count) - fprintf(fp, "%7d\t%s", count, line); - else - fputs(line, fp); - } -} - -int uniq_main(int argc, char **argv) -{ - FILE *in = stdin, *out = stdout; - char *lastline = NULL, *input; - int opt, count = 0; - - /* parse argv[] */ - while ((opt = getopt(argc, argv, "cdu")) > 0) { - switch (opt) { - case 'c': - print_count = 1; - break; - case 'd': - print_duplicates = 1; - print_uniq = 0; - break; - case 'u': - print_duplicates = 0; - print_uniq = 1; - break; - } - } - - if (argv[optind] != NULL) { - in = xfopen(argv[optind], "r"); - if (argv[optind+1] != NULL) - out = xfopen(argv[optind+1], "w"); - } - - while ((input = get_line_from_file(in)) != NULL) { - if (lastline == NULL || strcmp(input, lastline) != 0) { - print_line(lastline, count, out); - free(lastline); - lastline = input; - count = 0; - } - count++; - } - print_line(lastline, count, out); - free(lastline); - - return EXIT_SUCCESS; -} diff --git a/busybox/update.c b/busybox/update.c deleted file mode 100644 index 27a04ddee..000000000 --- a/busybox/update.c +++ /dev/null @@ -1,112 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini update implementation for busybox; much pasted from update-2.11 - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * Copyright (c) 1996, 1997, 1999 Torsten Poulin. - * Copyright (c) 2000 by Karl M. Hegbloom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* - * Note: This program is only necessary if you are running a 2.0.x (or - * earlier) kernel. 2.2.x and higher flush filesystem buffers automatically. - */ - -#include -#include -#include /* for getopt() */ -#include - -#if __GNU_LIBRARY__ > 5 - #include -#else - extern int bdflush (int func, long int data); -#endif - -#include "busybox.h" - -static unsigned int sync_duration = 30; -static unsigned int flush_duration = 5; -static int use_sync = 0; - -extern int update_main(int argc, char **argv) -{ - int pid; - int opt; - - while ((opt = getopt(argc, argv, "Ss:f:")) > 0) { - switch (opt) { - case 'S': - use_sync = 1; - break; - case 's': - sync_duration = atoi(optarg); - break; - case 'f': - flush_duration = atoi(optarg); - break; - default: - show_usage(); - } - } - - if (daemon(0, 1) < 0) - perror_msg_and_die("daemon"); - -#ifdef OPEN_MAX - for (pid = 0; pid < OPEN_MAX; pid++) close(pid); -#else - /* glibc 2.1.92 requires using sysconf(_SC_OPEN_MAX) */ - for (pid = 0; pid < sysconf(_SC_OPEN_MAX); pid++) close(pid); -#endif - - /* This is no longer necessary since 1.3.5x, but it will harmlessly - * exit if that is the case. - */ - - /* set the program name that will show up in a 'ps' listing */ - argv[0] = "bdflush (update)"; - argv[1] = NULL; - argv[2] = NULL; - for (;;) { - if (use_sync) { - sleep(sync_duration); - sync(); - } else { - sleep(flush_duration); - if (bdflush(1, 0) < 0) { - openlog("update", LOG_CONS, LOG_DAEMON); - syslog(LOG_INFO, - "This kernel does not need update(8). Exiting."); - closelog(); - return EXIT_SUCCESS; - } - } - } - - return EXIT_SUCCESS; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/uptime.c b/busybox/uptime.c deleted file mode 100644 index 6758d959e..000000000 --- a/busybox/uptime.c +++ /dev/null @@ -1,77 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini uptime implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -/* This version of uptime doesn't display the number of users on the system, - * since busybox init doesn't mess with utmp. For folks using utmp that are - * just dying to have # of users reported, feel free to write it as some type - * of BB_FEATURE_UTMP_SUPPORT #define - */ - -/* getopt not needed */ - - -#include -#include -#include -#include -#include "busybox.h" - -static const int FSHIFT = 16; /* nr of bits of precision */ -#define FIXED_1 (1<> FSHIFT) -#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) - - -extern int uptime_main(int argc, char **argv) -{ - int updays, uphours, upminutes; - struct sysinfo info; - struct tm *current_time; - time_t current_secs; - - time(¤t_secs); - current_time = localtime(¤t_secs); - - sysinfo(&info); - - printf(" %2d:%02d%s up ", - current_time->tm_hour%12 ? current_time->tm_hour%12 : 12, - current_time->tm_min, current_time->tm_hour > 11 ? "pm" : "am"); - updays = (int) info.uptime / (60*60*24); - if (updays) - printf("%d day%s, ", updays, (updays != 1) ? "s" : ""); - upminutes = (int) info.uptime / 60; - uphours = (upminutes / 60) % 24; - upminutes %= 60; - if(uphours) - printf("%2d:%02d, ", uphours, upminutes); - else - printf("%d min, ", upminutes); - - printf("load average: %ld.%02ld, %ld.%02ld, %ld.%02ld\n", - LOAD_INT(info.loads[0]), LOAD_FRAC(info.loads[0]), - LOAD_INT(info.loads[1]), LOAD_FRAC(info.loads[1]), - LOAD_INT(info.loads[2]), LOAD_FRAC(info.loads[2])); - - return EXIT_SUCCESS; -} diff --git a/busybox/usage.c b/busybox/usage.c deleted file mode 100644 index dfea1f96b..000000000 --- a/busybox/usage.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "busybox.h" - -const char usage_messages[] = - -#define MAKE_USAGE -#include "usage.h" - -#include "applets.h" - -; diff --git a/busybox/usage.h b/busybox/usage.h deleted file mode 100644 index 4d38c43bb..000000000 --- a/busybox/usage.h +++ /dev/null @@ -1,1826 +0,0 @@ -#define adjtimex_trivial_usage \ - "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]" -#define adjtimex_full_usage \ - "Reads and optionally sets system timebase parameters.\n" \ - "See adjtimex(2).\n\n" \ - "Options:\n" \ - "\t-q\t\tquiet mode - do not print\n" \ - "\t-o offset\ttime offset, microseconds\n" \ - "\t-f frequency\tfrequency adjust, integer kernel units (65536 is 1ppm)\n" \ - "\t\t\t(positive values make the system clock run fast)\n" \ - "\t-t tick\t\tmicroseconds per tick, usually 10000\n" \ - "\t-p timeconstant\n" - -#define ar_trivial_usage \ - "-[ov][ptx] ARCHIVE FILES" -#define ar_full_usage \ - "Extract or list FILES from an ar archive.\n\n" \ - "Options:\n" \ - "\t-o\t\tpreserve original dates\n" \ - "\t-p\t\textract to stdout\n" \ - "\t-t\t\tlist\n" \ - "\t-x\t\textract\n" \ - "\t-v\t\tverbosely list files processed\n" - -#define basename_trivial_usage \ - "FILE [SUFFIX]" -#define basename_full_usage \ - "Strips directory path and suffixes from FILE.\n" \ - "If specified, also removes any trailing SUFFIX." -#define basename_example_usage \ - "$ basename /usr/local/bin/foo\n" \ - "foo\n" \ - "$ basename /usr/local/bin/\n" \ - "bin\n" \ - "$ basename /foo/bar.txt .txt\n" \ - "bar" - -#define cat_trivial_usage \ - "[FILE]..." -#define cat_full_usage \ - "Concatenates FILE(s) and prints them to stdout." -#define cat_example_usage \ - "$ cat /proc/uptime\n" \ - "110716.72 17.67" - -#define chgrp_trivial_usage \ - "[OPTION]... GROUP FILE..." -#define chgrp_full_usage \ - "Change the group membership of each FILE to GROUP.\n" \ - "\nOptions:\n" \ - "\t-R\tChanges files and directories recursively." -#define chgrp_example_usage \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chgrp root /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 andersen root 0 Apr 12 18:25 /tmp/foo\n" - -#define chmod_trivial_usage \ - "[-R] MODE[,MODE]... FILE..." -#define chmod_full_usage \ - "Each MODE is one or more of the letters ugoa, one of the\n" \ - "symbols +-= and one or more of the letters rwxst.\n\n" \ - "Options:\n" \ - "\t-R\tChanges files and directories recursively." -#define chmod_example_usage \ - "$ ls -l /tmp/foo\n" \ - "-rw-rw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chmod u+x /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-rwxrw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo*\n" \ - "$ chmod 444 /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" - -#define chown_trivial_usage \ - "[ -Rh ]... OWNER[<.|:>[GROUP]] FILE..." -#define chown_full_usage \ - "Change the owner and/or group of each FILE to OWNER and/or GROUP.\n" \ - "\nOptions:\n" \ - "\t-R\tChanges files and directories recursively.\n" \ - "\t-h\tDo not dereference symbolic links." -#define chown_example_usage \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chown root /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 root andersen 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chown root.root /tmp/foo\n" \ - "ls -l /tmp/foo\n" \ - "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" - -#define chroot_trivial_usage \ - "NEWROOT [COMMAND...]" -#define chroot_full_usage \ - "Run COMMAND with root directory set to NEWROOT." -#define chroot_example_usage \ - "$ ls -l /bin/ls\n" \ - "lrwxrwxrwx 1 root root 12 Apr 13 00:46 /bin/ls -> /BusyBox\n" \ - "$ mount /dev/hdc1 /mnt -t minix\n" \ - "$ chroot /mnt\n" \ - "$ ls -l /bin/ls\n" \ - "-rwxr-xr-x 1 root root 40816 Feb 5 07:45 /bin/ls*\n" - -#define chvt_trivial_usage \ - "N" -#define chvt_full_usage \ - "Changes the foreground virtual terminal to /dev/ttyN" - -#define clear_trivial_usage \ - "" -#define clear_full_usage \ - "Clear screen." - -#define cmp_trivial_usage \ - "FILE1 [FILE2]" -#define cmp_full_usage \ - "\t-s\tquiet mode - do not print\n" \ - "Compare files." - -#define cp_trivial_usage \ - "[OPTION]... SOURCE DEST" -#define cp_full_usage \ - "Copies SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n" \ - "\n" \ - "\t-a\tSame as -dpR\n" \ - "\t-d\tPreserves links\n" \ - "\t-p\tPreserves file attributes if possible\n" \ - "\t-f\tforce (implied; ignored) - always set\n" \ - "\t-R\tCopies directories recursively" - -#define cpio_trivial_usage \ - "-[dimtuv][F cpiofile]" -#define cpio_full_usage \ - "Extract or list files from a cpio archive\n" \ - "Main operation mode:\n" \ - "\td\t\tmake leading directories\n" \ - "\ti\t\textract\n" \ - "\tm\t\tpreserve mtime\n" \ - "\tt\t\tlist\n" \ - "\tu\t\tunconditional overwrite\t" \ - "\tF\t\tinput from file\t" - -#define cut_trivial_usage \ - "[OPTION]... [FILE]..." -#define cut_full_usage \ - "Prints selected fields from each input FILE to standard output.\n\n" \ - "Options:\n" \ - "\t-b LIST\t\tOutput only bytes from LIST\n" \ - "\t-c LIST\t\tOutput only characters from LIST\n" \ - "\t-d CHAR\t\tUse CHAR instead of tab as the field delimiter\n" \ - "\t-s\t\tOutput only the lines containing delimiter\n" \ - "\t-f N\t\tPrint only these fields\n" \ - "\t-n\t\tIgnored" -#define cut_example_usage \ - "$ echo "Hello world" | cut -f 1 -d ' '\n" \ - "Hello\n" \ - "$ echo "Hello world" | cut -f 2 -d ' '\n" \ - "world\n" - -#define date_trivial_usage \ - "[OPTION]... [+FORMAT]" -#define date_full_usage \ - "Displays the current time in the given FORMAT, or sets the system date.\n" \ - "\nOptions:\n" \ - "\t-R\t\tOutputs RFC-822 compliant date string\n" \ - "\t-d STRING\tdisplay time described by STRING, not `now'\n" \ - "\t-s\t\tSets time described by STRING\n" \ - "\t-u\t\tPrints or sets Coordinated Universal Time" -#define date_example_usage \ - "$ date\n" \ - "Wed Apr 12 18:52:41 MDT 2000\n" - -#define dc_trivial_usage \ - "expression ..." -#define dc_full_usage \ - "This is a Tiny RPN calculator that understands the\n" \ - "following operations: +, -, /, *, and, or, not, eor.\n" \ - "i.e., 'dc 2 2 add' -> 4, and 'dc 8 8 \\* 2 2 + /' -> 16" -#define dc_example_usage \ - "$ dc 2 2 +\n" \ - "4\n" \ - "$ dc 8 8 \* 2 2 + /\n" \ - "16\n" \ - "$ dc 0 1 and\n" \ - "0\n" \ - "$ dc 0 1 or\n" \ - "1\n" \ - "$ echo 72 9 div 8 mul | dc\n" \ - "64\n" - -#define dd_trivial_usage \ - "[if=FILE] [of=FILE] [bs=N] [count=N] [skip=N]\n" \ - "\t [seek=N] [conv=notrunc|sync]" -#define dd_full_usage \ - "Copy a file, converting and formatting according to options\n\n" \ - "\tif=FILE\t\tread from FILE instead of stdin\n" \ - "\tof=FILE\t\twrite to FILE instead of stdout\n" \ - "\tbs=N\t\tread and write N bytes at a time\n" \ - "\tcount=N\t\tcopy only N input blocks\n" \ - "\tskip=N\t\tskip N input blocks\n" \ - "\tseek=N\t\tskip N output blocks\n" \ - "\tconv=notrunc\tdon't truncate output file\n" \ - "\tconv=sync\tpad blocks with zeros\n" \ - "\n" \ - "Numbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),\n" \ - "MD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)." -#define dd_example_usage \ - "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" \ - "4+0 records in\n" \ - "4+0 records out\n" - -#define deallocvt_trivial_usage \ - "N" -#define deallocvt_full_usage \ - "Deallocate unused virtual terminal /dev/ttyN" - - -#ifdef BB_FEATURE_HUMAN_READABLE - #define USAGE_HUMAN_READABLE(a) a - #define USAGE_NOT_HUMAN_READABLE(a) -#else - #define USAGE_HUMAN_READABLE(a) - #define USAGE_NOT_HUMAN_READABLE(a) a -#endif -#define df_trivial_usage \ - "[-" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILESYSTEM ...]" -#define df_full_usage \ - "Print the filesystem space used and space available.\n\n" \ - "Options:\n" \ - USAGE_HUMAN_READABLE( \ - "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \ - "\t-m\tprint sizes in megabytes\n" \ - "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \ - "\n\t-k\tprint sizes in kilobytes(compatibility)") -#define df_example_usage \ - "$ df\n" \ - "Filesystem 1k-blocks Used Available Use% Mounted on\n" \ - "/dev/sda3 8690864 8553540 137324 98% /\n" \ - "/dev/sda1 64216 36364 27852 57% /boot\n" \ - "$ df /dev/sda3\n" \ - "Filesystem 1k-blocks Used Available Use% Mounted on\n" \ - "/dev/sda3 8690864 8553540 137324 98% /\n" - -#define dirname_trivial_usage \ - "[FILENAME ...]" -#define dirname_full_usage \ - "Strips non-directory suffix from FILENAME" -#define dirname_example_usage \ - "$ dirname /tmp/foo\n" \ - "/tmp\n" \ - "$ dirname /tmp/foo/\n" \ - "/tmp\n" - -#define dmesg_trivial_usage \ - "[-c] [-n LEVEL] [-s SIZE]" -#define dmesg_full_usage \ - "Prints or controls the kernel ring buffer\n\n" \ - "Options:\n" \ - "\t-c\t\tClears the ring buffer's contents after printing\n" \ - "\t-n LEVEL\tSets console logging level\n" \ - "\t-s SIZE\t\tUse a buffer of size SIZE" - -#define dos2unix_trivial_usage \ - "[option] [FILE]" -#define dos2unix_full_usage \ - "Converts FILE from dos format to unix format. When no option\n" \ - "is given, the input is converted to the opposite output format.\n" \ - "When no file is given, uses stdin for input and stdout for output.\n\n" \ - "Options:\n" \ - "\t-u\toutput will be in UNIX format\n" \ - "\t-d\toutput will be in DOS format" - -#define dpkg_trivial_usage \ - "-i package_file\n" - "[-CPru] package_name" -#define dpkg_full_usage \ - "\t-i\tInstall the package\n" \ - "\t-C\tConfigure an unpackaged package\n" \ - "\t-P\tPurge all files of a package\n" \ - "\t-r\tRemove all but the configuration files for a package\n" \ - "\t-u\tUnpack a package, but dont configure it\n" - -#define dpkg_deb_trivial_usage \ - "[-cefItxX] FILE [argument]" -#define dpkg_deb_full_usage \ - "Perform actions on debian packages (.debs)\n\n" \ - "Options:\n" \ - "\t-c\tList contents of filesystem tree\n" \ - "\t-e\tExtract control files to [argument] directory\n" \ - "\t-f\tDisplay control field name starting with [argument]\n" \ - "\t-I\tDisplay the control filenamed [argument]\n" \ - "\t-t\tExtract filesystem tree to stdout in tar format\n" \ - "\t-x\tExtract packages filesystem tree to directory\n" \ - "\t-X\tVerbose extract" -#define dpkg_deb_example_usage \ - "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n" - -#define du_trivial_usage \ - "[-ls" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILE]..." -#define du_full_usage \ - "Summarizes disk space used for each FILE and/or directory.\n" \ - "Disk space is printed in units of 1024 bytes.\n\n" \ - "Options:\n" \ - "\t-l\tcount sizes many times if hard linked\n" \ - "\t-s\tdisplay only a total for each argument" \ - USAGE_HUMAN_READABLE( \ - "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \ - "\t-m\tprint sizes in megabytes\n" \ - "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \ - "\n\t-k\tprint sizes in kilobytes(compatibility)") -#define du_example_usage \ - "$ du\n" \ - "16 ./CVS\n" \ - "12 ./kernel-patches/CVS\n" \ - "80 ./kernel-patches\n" \ - "12 ./tests/CVS\n" \ - "36 ./tests\n" \ - "12 ./scripts/CVS\n" \ - "16 ./scripts\n" \ - "12 ./docs/CVS\n" \ - "104 ./docs\n" \ - "2417 .\n" - -#define dumpkmap_trivial_usage \ - "> keymap" -#define dumpkmap_full_usage \ - "Prints out a binary keyboard translation table to standard output." -#define dumpkmap_example_usage \ - "$ dumpkmap > keymap\n" - -#define dutmp_trivial_usage \ - "[FILE]" -#define dutmp_full_usage \ - "Dump utmp file format (pipe delimited) from FILE\n" \ - "or stdin to stdout. (i.e., 'dutmp /var/run/utmp')" -#define dutmp_example_usage \ - "$ dutmp /var/run/utmp\n" \ - "8|7||si|||0|0|0|955637625|760097|0\n" \ - "2|0|~|~~|reboot||0|0|0|955637625|782235|0\n" \ - "1|20020|~|~~|runlevel||0|0|0|955637625|800089|0\n" \ - "8|125||l4|||0|0|0|955637629|998367|0\n" \ - "6|245|tty1|1|LOGIN||0|0|0|955637630|998974|0\n" \ - "6|246|tty2|2|LOGIN||0|0|0|955637630|999498|0\n" \ - "7|336|pts/0|vt00andersen|andersen|:0.0|0|0|0|955637763|0|0\n" - -#define echo_trivial_usage \ - "[-neE] [ARG ...]" -#define echo_full_usage \ - "Prints the specified ARGs to stdout\n\n" \ - "Options:\n" \ - "\t-n\tsuppress trailing newline\n" \ - "\t-e\tinterpret backslash-escaped characters (i.e., \\t=tab)\n" \ - "\t-E\tdisable interpretation of backslash-escaped characters" -#define echo_example_usage \ - "$ echo "Erik is cool"\n" \ - "Erik is cool\n" \ - "$ echo -e "Erik\\nis\\ncool"\n" \ - "Erik\n" \ - "is\n" \ - "cool\n" \ - "$ echo "Erik\\nis\\ncool"\n" \ - "Erik\\nis\\ncool\n" - -#define env_trivial_usage \ - "[-iu] [-] [name=value]... [command]" -#define env_full_usage \ - "Prints the current environment or runs a program after setting\n" \ - "up the specified environment.\n\n" \ - "Options:\n" \ - "\t-, -i\tstart with an empty environment\n" \ - "\t-u\tremove variable from the environment\n" - -#define expr_trivial_usage \ - "EXPRESSION" -#define expr_full_usage \ - "Prints the value of EXPRESSION to standard output.\n\n" \ - "EXPRESSION may be:\n" \ - "\tARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n" \ - "\tARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n" \ - "\tARG1 < ARG2 ARG1 is less than ARG2\n" \ - "\tARG1 <= ARG2 ARG1 is less than or equal to ARG2\n" \ - "\tARG1 = ARG2 ARG1 is equal to ARG2\n" \ - "\tARG1 != ARG2 ARG1 is unequal to ARG2\n" \ - "\tARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n" \ - "\tARG1 > ARG2 ARG1 is greater than ARG2\n" \ - "\tARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n" \ - "\tARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n" \ - "\tARG1 * ARG2 arithmetic product of ARG1 and ARG2\n" \ - "\tARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n" \ - "\tARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n" \ - "\tSTRING : REGEXP anchored pattern match of REGEXP in STRING\n" \ - "\tmatch STRING REGEXP same as STRING : REGEXP\n" \ - "\tsubstr STRING POS LENGTH substring of STRING, POS counted from 1\n" \ - "\tindex STRING CHARS index in STRING where any CHARS is found,\n" \ - "\t or 0\n" \ - "\tlength STRING length of STRING\n" \ - "\tquote TOKEN interpret TOKEN as a string, even if\n" \ - "\t it is a keyword like `match' or an\n" \ - "\t operator like `/'\n" \ - "\t( EXPRESSION ) value of EXPRESSION\n\n" \ - "Beware that many operators need to be escaped or quoted for shells.\n" \ - "Comparisons are arithmetic if both ARGs are numbers, else\n" \ - "lexicographical. Pattern matches return the string matched between \n" \ - "\\( and \\) or null; if \\( and \\) are not used, they return the number \n" \ - "of characters matched or 0." - -#define false_trivial_usage \ - "" -#define false_full_usage \ - "Return an exit code of FALSE (1)." -#define false_example_usage \ - "$ false\n" \ - "$ echo $?\n" \ - "1\n" - -#define fbset_trivial_usage \ - "[options] [mode]" -#define fbset_full_usage \ - "Show and modify frame buffer settings" -#define fbset_example_usage \ - "$ fbset\n" \ - "mode "1024x768-76"\n" \ - "\t# D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz\n" \ - "\tgeometry 1024 768 1024 768 16\n" \ - "\ttimings 12714 128 32 16 4 128 4\n" \ - "\taccel false\n" \ - "\trgba 5/11,6/5,5/0,0/0\n" \ - "endmode\n" - -#define fdflush_trivial_usage \ - "DEVICE" -#define fdflush_full_usage \ - "Forces floppy disk drive to detect disk change" - -#ifdef BB_FEATURE_FIND_TYPE - #define USAGE_FIND_TYPE(a) a -#else - #define USAGE_FIND_TYPE(a) -#endif -#ifdef BB_FEATURE_FIND_PERM - #define USAGE_FIND_PERM(a) a -#else - #define USAGE_FIND_PERM(a) -#endif -#ifdef BB_FEATURE_FIND_MTIME - #define USAGE_FIND_MTIME(a) a -#else - #define USAGE_FIND_MTIME(a) -#endif - -#define find_trivial_usage \ - "[PATH...] [EXPRESSION]" -#define find_full_usage \ - "Search for files in a directory hierarchy. The default PATH is\n" \ - "the current directory; default EXPRESSION is '-print'\n" \ - "\nEXPRESSION may consist of:\n" \ - "\t-follow\t\tDereference symbolic links.\n" \ - "\t-name PATTERN\tFile name (leading directories removed) matches PATTERN.\n" \ - "\t-print\t\tPrint (default and assumed).\n" \ - USAGE_FIND_TYPE( \ - "\n\t-type X\t\tFiletype matches X (where X is one of: f,d,l,b,c,...)" \ -) USAGE_FIND_PERM( \ - "\n\t-perm PERMS\tPermissions match any of (+NNN); all of (-NNN);\n\t\t\tor exactly (NNN)" \ -) USAGE_FIND_MTIME( \ - "\n\t-mtime TIME\tModified time is greater than (+N); less than (-N);\n\t\t\tor exactly (N) days") -#define find_example_usage \ - "$ find / -name /etc/passwd\n" \ - "/etc/passwd\n" - -#define free_trivial_usage \ - "" -#define free_full_usage \ - "Displays the amount of free and used system memory" -#define free_example_usage \ - "$ free\n" \ - " total used free shared buffers\n" \ - " Mem: 257628 248724 8904 59644 93124\n" \ - " Swap: 128516 8404 120112\n" \ - "Total: 386144 257128 129016\n" \ - -#define freeramdisk_trivial_usage \ - "DEVICE" -#define freeramdisk_full_usage \ - "Frees all memory used by the specified ramdisk." -#define freeramdisk_example_usage \ - "$ freeramdisk /dev/ram2\n" - -#define fsck_minix_trivial_usage \ - "[-larvsmf] /dev/name" -#define fsck_minix_full_usage \ - "Performs a consistency check for MINIX filesystems.\n\n" \ - "Options:\n" \ - "\t-l\tLists all filenames\n" \ - "\t-r\tPerform interactive repairs\n" \ - "\t-a\tPerform automatic repairs\n" \ - "\t-v\tverbose\n" \ - "\t-s\tOutputs super-block information\n" \ - "\t-m\tActivates MINIX-like \"mode not cleared\" warnings\n" \ - "\t-f\tForce file system check." - -#define getopt_trivial_usage \ - "[OPTIONS]..." -#define getopt_full_usage \ - "Parse command options\n" \ - "\t-a, --alternative Allow long options starting with single -\n" \ - "\t-l, --longoptions=longopts Long options to be recognized\n" \ - "\t-n, --name=progname The name under which errors are reported\n" \ - "\t-o, --options=optstring Short options to be recognized\n" \ - "\t-q, --quiet Disable error reporting by getopt(3)\n" \ - "\t-Q, --quiet-output No normal output\n" \ - "\t-s, --shell=shell Set shell quoting conventions\n" \ - "\t-T, --test Test for getopt(1) version\n" \ - "\t-u, --unqote Do not quote the output" -#define getopt_example_usage \ - "$ cat getopt.test\n" \ - "#!/bin/sh\n" \ - "GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \\\n" \ - " -n 'example.busybox' -- "$@"`\n" \ - "if [ $? != 0 ] ; then exit 1 ; fi\n" \ - "eval set -- "$GETOPT"\n" \ - "while true ; do\n" \ - " case $1 in\n" \ - " -a|--a-long) echo \"Option a\" ; shift ;;\n" \ - " -b|--b-long) echo \"Option b, argument \`$2'\" ; shift 2 ;;\n" \ - " -c|--c-long)\n" \ - " case "$2" in\n" \ - " \"\") echo \"Option c, no argument\"; shift 2 ;;\n" \ - " *) echo \"Option c, argument \`$2'\" ; shift 2 ;;\n" \ - " esac ;;\n" \ - " --) shift ; break ;;\n" \ - " *) echo \"Internal error!\" ; exit 1 ;;\n" \ - " esac\n" \ - "done\n" - -#define grep_trivial_usage \ - "[-ihHnqvs] PATTERN [FILEs...]" -#define grep_full_usage \ - "Search for PATTERN in each FILE or standard input.\n\n" \ - "Options:\n" \ - "\t-H\tprefix output lines with filename where match was found\n" \ - "\t-h\tsuppress the prefixing filename on output\n" \ - "\t-i\tignore case distinctions\n" \ - "\t-l\tlist names of files that match\n" \ - "\t-n\tprint line number with output lines\n" \ - "\t-q\tbe quiet. Returns 0 if result was found, 1 otherwise\n" \ - "\t-v\tselect non-matching lines\n" \ - "\t-s\tsuppress file open/read error messages" -#define grep_example_usage \ - "$ grep root /etc/passwd\n" \ - "root:x:0:0:root:/root:/bin/bash\n" \ - "$ grep ^[rR]oo. /etc/passwd\n" \ - "root:x:0:0:root:/root:/bin/bash\n" - -#define gunzip_trivial_usage \ - "[OPTION]... FILE" -#define gunzip_full_usage \ - "Uncompress FILE (or standard input if FILE is '-').\n\n" \ - "Options:\n" \ - "\t-c\tWrite output to standard output\n" \ - "\t-t\tTest compressed file integrity" -#define gunzip_example_usage \ - "$ ls -la /tmp/BusyBox*\n" \ - "-rw-rw-r-- 1 andersen andersen 557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n" \ - "$ gunzip /tmp/BusyBox-0.43.tar.gz\n" \ - "$ ls -la /tmp/BusyBox*\n" \ - "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n" - -#define gzip_trivial_usage \ - "[OPTION]... FILE" -#define gzip_full_usage \ - "Compress FILE with maximum compression.\n" \ - "When FILE is '-', reads standard input. Implies -c.\n\n" \ - "Options:\n" \ - "\t-c\tWrite output to standard output instead of FILE.gz\n" \ - "\t-d\tdecompress" -#define gzip_example_usage \ - "$ ls -la /tmp/busybox*\n" \ - "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/busybox.tar\n" \ - "$ gzip /tmp/busybox.tar\n" \ - "$ ls -la /tmp/busybox*\n" \ - "-rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/busybox.tar.gz\n" - -#define halt_trivial_usage \ - "" -#define halt_full_usage \ - "Halt the system." - -#define head_trivial_usage \ - "[OPTION] [FILE]..." -#define head_full_usage \ - "Print first 10 lines of each FILE to standard output.\n" \ - "With more than one FILE, precede each with a header giving the\n" \ - "file name. With no FILE, or when FILE is -, read standard input.\n\n" \ - "Options:\n" \ - "\t-n NUM\t\tPrint first NUM lines instead of first 10" -#define head_example_usage \ - "$ head -n 2 /etc/passwd\n" \ - "root:x:0:0:root:/root:/bin/bash\n" \ - "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n" - -#define hostid_trivial_usage \ - "" -#define hostid_full_usage \ - "Print out a unique 32-bit identifier for the machine." - -#define hostname_trivial_usage \ - "[OPTION] {hostname | -F FILE}" -#define hostname_full_usage \ - "Get or set the hostname or DNS domain name. If a hostname is given\n" \ - "(or FILE with the -F parameter), the host name will be set.\n\n" \ - "Options:\n" \ - "\t-s\t\tShort\n" \ - "\t-i\t\tAddresses for the hostname\n" \ - "\t-d\t\tDNS domain name\n" \ - "\t-F, --file FILE\tUse the contents of FILE to specify the hostname" -#define hostname_example_usage \ - "$ hostname\n" \ - "sage \n" - -#define id_trivial_usage \ - "[OPTIONS]... [USERNAME]" -#define id_full_usage \ - "Print information for USERNAME or the current user\n\n" \ - "Options:\n" \ - "\t-g\tprints only the group ID\n" \ - "\t-u\tprints only the user ID\n" \ - "\t-n\tprint a name instead of a number (with for -ug)\n" \ - "\t-r\tprints the real user ID instead of the effective ID (with -ug)" -#define id_example_usage \ - "$ id\n" \ - "uid=1000(andersen) gid=1000(andersen)\n" - -#ifdef BB_FEATURE_IFCONFIG_SLIP - #define USAGE_SIOCSKEEPALIVE(a) a -#else - #define USAGE_SIOCSKEEPALIVE(a) -#endif -#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ - #define USAGE_IFCONFIG_MII(a) a -#else - #define USAGE_IFCONFIG_MII(a) -#endif -#ifdef BB_FEATURE_IFCONFIG_HW - #define USAGE_IFCONFIG_HW(a) a -#else - #define USAGE_IFCONFIG_HW(a) -#endif -#ifdef BB_FEATURE_IFCONFIG_STATUS - #define USAGE_IFCONFIG_OPT_A(a) a -#else - #define USAGE_IFCONFIG_OPT_A(a) -#endif - -#define ifconfig_trivial_usage \ - USAGE_IFCONFIG_OPT_A("[-a]") " [
]" -#define ifconfig_full_usage \ - "configure a network interface\n\n" \ - "Options:\n" \ - "\t[[-]broadcast [
]] [[-]pointopoint [
]]\n" \ - "\t[netmask
] [dstaddr
]\n" \ - USAGE_SIOCSKEEPALIVE("\t[outfill ] [keepalive ]\n") \ - "\t" USAGE_IFCONFIG_HW("[hw ether
] ") \ - "[metric ] [mtu ]\n" \ - "\t[[-]trailers] [[-]arp] [[-]allmulti]\n" \ - "\t[multicast] [[-]promisc] [txqueuelen ] [[-]dynamic]\n" \ - USAGE_IFCONFIG_MII("\t[mem_start ] [io_addr ] [irq ]\n") \ - "\t[up|down] ..." - -#define init_trivial_usage \ - "" -#define init_full_usage \ - "Init is the parent of all processes." -#define init_notes_usage \ -"This version of init is designed to be run only by the kernel.\n" \ -"\n" \ -"BusyBox init doesn't support multiple runlevels. The runlevels field of\n" \ -"the /etc/inittab file is completely ignored by BusyBox init. If you want \n" \ -"runlevels, use sysvinit.\n" \ -"\n" \ -"BusyBox init works just fine without an inittab. If no inittab is found, \n" \ -"it has the following default behavior:\n" \ -"\n" \ -" ::sysinit:/etc/init.d/rcS\n" \ -" ::askfirst:/bin/sh\n" \ -" ::ctrlaltdel:/sbin/reboot\n" \ -" ::shutdown:/sbin/swapoff -a\n" \ -" ::shutdown:/bin/umount -a -r\n" \ -"\n" \ -"if it detects that /dev/console is _not_ a serial console, it will also run:\n" \ -"\n" \ -" tty2::askfirst:/bin/sh\n" \ -" tty3::askfirst:/bin/sh\n" \ -" tty4::askfirst:/bin/sh\n" \ -"\n" \ -"If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" \ -"\n" \ -" :::\n" \ -"\n" \ -" : \n" \ -"\n" \ -" WARNING: This field has a non-traditional meaning for BusyBox init!\n" \ -" The id field is used by BusyBox init to specify the controlling tty for\n" \ -" the specified process to run on. The contents of this field are\n" \ -" appended to "/dev/" and used as-is. There is no need for this field to\n" \ -" be unique, although if it isn't you may have strange results. If this\n" \ -" field is left blank, the controlling tty is set to the console. Also\n" \ -" note that if BusyBox detects that a serial console is in use, then only\n" \ -" entries whose controlling tty is either the serial console or /dev/null\n" \ -" will be run. BusyBox init does nothing with utmp. We don't need no\n" \ -" stinkin' utmp.\n" \ -"\n" \ -" : \n" \ -"\n" \ -" The runlevels field is completely ignored.\n" \ -"\n" \ -" : \n" \ -"\n" \ -" Valid actions include: sysinit, respawn, askfirst, wait, \n" \ -" once, ctrlaltdel, and shutdown.\n" \ -"\n" \ -" The available actions can be classified into two groups: actions\n" \ -" that are run only once, and actions that are re-run when the specified\n" \ -" process exits.\n" \ -"\n" \ -" Run only-once actions:\n" \ -"\n" \ -" 'sysinit' is the first item run on boot. init waits until all\n" \ -" sysinit actions are completed before continuing. Following the\n" \ -" completion of all sysinit actions, all 'wait' actions are run.\n" \ -" 'wait' actions, like 'sysinit' actions, cause init to wait until\n" \ -" the specified task completes. 'once' actions are asynchronous,\n" \ -" therefore, init does not wait for them to complete. 'ctrlaltdel'\n" \ -" actions are run when the system detects that someone on the system\n" \ -" console has pressed the CTRL-ALT-DEL key combination. Typically one\n" \ -" wants to run 'reboot' at this point to cause the system to reboot.\n" \ -" Finally the 'shutdown' action specifies the actions to taken when\n" \ -" init is told to reboot. Unmounting filesystems and disabling swap\n" \ -" is a very good here\n" \ -"\n" \ -" Run repeatedly actions:\n" \ -"\n" \ -" 'respawn' actions are run after the 'once' actions. When a process\n" \ -" started with a 'respawn' action exits, init automatically restarts\n" \ -" it. Unlike sysvinit, BusyBox init does not stop processes from\n" \ -" respawning out of control. The 'askfirst' actions acts just like\n" \ -" respawn, except that before running the specified process it\n" \ -" displays the line "Please press Enter to activate this console."\n" \ -" and then waits for the user to press enter before starting the\n" \ -" specified process. \n" \ -"\n" \ -" Unrecognized actions (like initdefault) will cause init to emit an\n" \ -" error message, and then go along with its business. All actions are\n" \ -" run in the reverse order from how they appear in /etc/inittab.\n" \ -"\n" \ -" : \n" \ -"\n" \ -" Specifies the process to be executed and it's command line.\n" \ -"\n" \ -"Example /etc/inittab file:\n" \ -"\n" \ -" # This is run first except when booting in single-user mode.\n" \ -" #\n" \ -" ::sysinit:/etc/init.d/rcS\n" \ -" \n" \ -" # /bin/sh invocations on selected ttys\n" \ -" #\n" \ -" # Start an "askfirst" shell on the console (whatever that may be)\n" \ -" ::askfirst:-/bin/sh\n" \ -" # Start an "askfirst" shell on /dev/tty2-4\n" \ -" tty2::askfirst:-/bin/sh\n" \ -" tty3::askfirst:-/bin/sh\n" \ -" tty4::askfirst:-/bin/sh\n" \ -" \n" \ -" # /sbin/getty invocations for selected ttys\n" \ -" #\n" \ -" tty4::respawn:/sbin/getty 38400 tty5\n" \ -" tty5::respawn:/sbin/getty 38400 tty6\n" \ -" \n" \ -" \n" \ -" # Example of how to put a getty on a serial line (for a terminal)\n" \ -" #\n" \ -" #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" \ -" #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" \ -" #\n" \ -" # Example how to put a getty on a modem line.\n" \ -" #::respawn:/sbin/getty 57600 ttyS2\n" \ -" \n" \ -" # Stuff to do before rebooting\n" \ -" ::ctrlaltdel:/sbin/reboot\n" \ -" ::shutdown:/bin/umount -a -r\n" \ -" ::shutdown:/sbin/swapoff -a\n" - -#define insmod_trivial_usage \ - "[OPTION]... MODULE [symbol=value]..." -#define insmod_full_usage \ - "Loads the specified kernel modules into the kernel.\n\n" \ - "Options:\n" \ - "\t-f\tForce module to load into the wrong kernel version.\n" \ - "\t-k\tMake module autoclean-able.\n" \ - "\t-v\tverbose output\n" \ - "\t-L\tLock to prevent simultaneous loads of a module\n" \ - "\t-x\tdo not export externs" - -#define kill_trivial_usage \ - "[-signal] process-id [process-id ...]" -#define kill_full_usage \ - "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\ - "Options:\n" \ - "\t-l\tList all signal names and numbers." -#define kill_example_usage \ - "$ ps | grep apache\n" \ - "252 root root S [apache]\n" \ - "263 www-data www-data S [apache]\n" \ - "264 www-data www-data S [apache]\n" \ - "265 www-data www-data S [apache]\n" \ - "266 www-data www-data S [apache]\n" \ - "267 www-data www-data S [apache]\n" \ - "$ kill 252\n" - -#define killall_trivial_usage \ - "[-signal] process-name [process-name ...]" -#define killall_full_usage \ - "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\ - "Options:\n" \ - "\t-l\tList all signal names and numbers." -#define killall_example_usage \ - "$ killall apache\n" - -#define klogd_trivial_usage \ - "-n" -#define klogd_full_usage \ - "Kernel logger.\n"\ - "Options:\n"\ - "\t-n\tRun as a foreground process." - -#define length_trivial_usage \ - "STRING" -#define length_full_usage \ - "Prints out the length of the specified STRING." -#define length_example_usage \ - "$ length Hello\n" \ - "5\n" - -#define ln_trivial_usage \ - "[OPTION] TARGET... LINK_NAME|DIRECTORY" -#define ln_full_usage \ - "Create a link named LINK_NAME or DIRECTORY to the specified TARGET\n"\ - "\nYou may use '--' to indicate that all following arguments are non-options.\n\n" \ - "Options:\n" \ - "\t-s\tmake symbolic links instead of hard links\n" \ - "\t-f\tremove existing destination files\n" \ - "\t-n\tno dereference symlinks - treat like normal file" -#define ln_example_usage \ - "$ ln -s BusyBox /tmp/ls\n" \ - "$ ls -l /tmp/ls\n" \ - "lrwxrwxrwx 1 root root 7 Apr 12 18:39 ls -> BusyBox*\n" - -#define loadacm_trivial_usage \ - "< mapfile" -#define loadacm_full_usage \ - "Loads an acm from standard input." -#define loadacm_example_usage \ - "$ loadacm < /etc/i18n/acmname\n" - -#define loadfont_trivial_usage \ - "< font" -#define loadfont_full_usage \ - "Loads a console font from standard input." -#define loadfont_example_usage \ - "$ loadfont < /etc/i18n/fontname\n" - -#define loadkmap_trivial_usage \ - "< keymap" -#define loadkmap_full_usage \ - "Loads a binary keyboard translation table from standard input." -#define loadkmap_example_usage \ - "$ loadkmap < /etc/i18n/lang-keymap\n" - -#define logger_trivial_usage \ - "[OPTION]... [MESSAGE]" -#define logger_full_usage \ - "Write MESSAGE to the system log. If MESSAGE is omitted, log stdin.\n\n" \ - "Options:\n" \ - "\t-s\tLog to stderr as well as the system log.\n" \ - "\t-t\tLog using the specified tag (defaults to user name).\n" \ - "\t-p\tEnter the message with the specified priority.\n" \ - "\t\tThis may be numerical or a ``facility.level'' pair." -#define logger_example_usage \ - "$ logger "hello"\n" - -#define logname_trivial_usage \ - "" -#define logname_full_usage \ - "Print the name of the current user." -#define logname_example_usage \ - "$ logname\n" \ - "root\n" - -#define logread_trivial_usage \ - "" - -#define logread_full_usage \ - "Shows the messages from syslogd (using circular buffer)." - -#ifdef BB_FEATURE_LS_TIMESTAMPS - #define USAGE_LS_TIMESTAMPS(a) a -#else - #define USAGE_LS_TIMESTAMPS(a) -#endif -#ifdef BB_FEATURE_LS_FILETYPES - #define USAGE_LS_FILETYPES(a) a -#else - #define USAGE_LS_FILETYPES(a) -#endif -#ifdef BB_FEATURE_LS_FOLLOWLINKS - #define USAGE_LS_FOLLOWLINKS(a) a -#else - #define USAGE_LS_FOLLOWLINKS(a) -#endif -#ifdef BB_FEATURE_LS_RECURSIVE - #define USAGE_LS_RECURSIVE(a) a -#else - #define USAGE_LS_RECURSIVE(a) -#endif -#ifdef BB_FEATURE_LS_SORTFILES - #define USAGE_LS_SORTFILES(a) a -#else - #define USAGE_LS_SORTFILES(a) -#endif -#ifdef BB_FEATURE_AUTOWIDTH - #define USAGE_AUTOWIDTH(a) a -#else - #define USAGE_AUTOWIDTH(a) -#endif -#define ls_trivial_usage \ - "[-1Aa" USAGE_LS_TIMESTAMPS("c") "Cd" USAGE_LS_TIMESTAMPS("e") USAGE_LS_FILETYPES("F") "iln" USAGE_LS_FILETYPES("p") USAGE_LS_FOLLOWLINKS("L") USAGE_LS_RECURSIVE("R") USAGE_LS_SORTFILES("rS") "s" USAGE_AUTOWIDTH("T") USAGE_LS_TIMESTAMPS("tu") USAGE_LS_SORTFILES("v") USAGE_AUTOWIDTH("w") "x" USAGE_LS_SORTFILES("X") USAGE_HUMAN_READABLE("h") USAGE_NOT_HUMAN_READABLE("") "k] [filenames...]" -#define ls_full_usage \ - "List directory contents\n\n" \ - "Options:\n" \ - "\t-1\tlist files in a single column\n" \ - "\t-A\tdo not list implied . and ..\n" \ - "\t-a\tdo not hide entries starting with .\n" \ - "\t-C\tlist entries by columns\n" \ - USAGE_LS_TIMESTAMPS("\t-c\twith -l: show ctime\n") \ - "\t-d\tlist directory entries instead of contents\n" \ - USAGE_LS_TIMESTAMPS("\t-e\tlist both full date and full time\n") \ - USAGE_LS_FILETYPES("\t-F\tappend indicator (one of */=@|) to entries\n") \ - "\t-i\tlist the i-node for each file\n" \ - "\t-l\tuse a long listing format\n" \ - "\t-n\tlist numeric UIDs and GIDs instead of names\n" \ - USAGE_LS_FILETYPES("\t-p\tappend indicator (one of /=@|) to entries\n") \ - USAGE_LS_FOLLOWLINKS("\t-L\tlist entries pointed to by symbolic links\n") \ - USAGE_LS_RECURSIVE("\t-R\tlist subdirectories recursively\n") \ - USAGE_LS_SORTFILES("\t-r\tsort the listing in reverse order\n") \ - USAGE_LS_SORTFILES("\t-S\tsort the listing by file size\n") \ - "\t-s\tlist the size of each file, in blocks\n" \ - USAGE_AUTOWIDTH("\t-T NUM\tassume Tabstop every NUM columns\n") \ - USAGE_LS_TIMESTAMPS("\t-t\twith -l: show modification time\n") \ - USAGE_LS_TIMESTAMPS("\t-u\twith -l: show access time\n") \ - USAGE_LS_SORTFILES("\t-v\tsort the listing by version\n") \ - USAGE_AUTOWIDTH("\t-w NUM\tassume the terminal is NUM columns wide\n") \ - "\t-x\tlist entries by lines instead of by columns\n" \ - USAGE_LS_SORTFILES("\t-X\tsort the listing by extension\n") \ - USAGE_HUMAN_READABLE( \ - "\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \ - "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \ - "\t-k\tprint sizes in kilobytes(compatibility)") - -#define lsmod_trivial_usage \ - "" -#define lsmod_full_usage \ - "List the currently loaded kernel modules." - -#define makedevs_trivial_usage \ - "NAME TYPE MAJOR MINOR FIRST LAST [s]" -#define makedevs_full_usage \ - "Creates a range of block or character special files\n\n" \ - "TYPEs include:\n" \ - "\tb:\tMake a block (buffered) device.\n" \ - "\tc or u:\tMake a character (un-buffered) device.\n" \ - "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes.\n\n" \ - "FIRST specifies the number appended to NAME to create the first device.\n" \ - "LAST specifies the number of the last item that should be created.\n" \ - "If 's' is the last argument, the base device is created as well.\n\n" \ - "For example:\n" \ - "\tmakedevs /dev/ttyS c 4 66 2 63 -> ttyS2-ttyS63\n" \ - "\tmakedevs /dev/hda b 3 0 0 8 s -> hda,hda1-hda8" -#define makedevs_example_usage \ - "$ makedevs /dev/ttyS c 4 66 2 63\n" \ - "[creates ttyS2-ttyS63]\n" \ - "$ makedevs /dev/hda b 3 0 0 8 s\n" \ - "[creates hda,hda1-hda8]\n" - -#define md5sum_trivial_usage \ - "[OPTION] [FILE]...\n" \ - "or: md5sum [OPTION] -c [FILE]" -#define md5sum_full_usage \ - "Print or check MD5 checksums.\n\n" \ - "Options:\n" \ - "With no FILE, or when FILE is -, read standard input.\n\n" \ - "\t-b\tread files in binary mode\n" \ - "\t-c\tcheck MD5 sums against given list\n" \ - "\t-t\tread files in text mode (default)\n" \ - "\t-g\tread a string\n" \ - "\nThe following two options are useful only when verifying checksums:\n" \ - "\t-s\tdon't output anything, status code shows success\n" \ - "\t-w\twarn about improperly formated MD5 checksum lines" -#define md5sum_example_usage \ - "$ md5sum < busybox\n" \ - "6fd11e98b98a58f64ff3398d7b324003\n" \ - "$ md5sum busybox\n" \ - "6fd11e98b98a58f64ff3398d7b324003 busybox\n" \ - "$ md5sum -c -\n" \ - "6fd11e98b98a58f64ff3398d7b324003 busybox\n" \ - "busybox: OK\n" \ - "^D\n" - -#define mkdir_trivial_usage \ - "[OPTION] DIRECTORY..." -#define mkdir_full_usage \ - "Create the DIRECTORY(ies) if they do not already exist\n\n" \ - "Options:\n" \ - "\t-m\tset permission mode (as in chmod), not rwxrwxrwx - umask\n" \ - "\t-p\tno error if existing, make parent directories as needed" -#define mkdir_example_usage \ - "$ mkdir /tmp/foo\n" \ - "$ mkdir /tmp/foo\n" \ - "/tmp/foo: File exists\n" \ - "$ mkdir /tmp/foo/bar/baz\n" \ - "/tmp/foo/bar/baz: No such file or directory\n" \ - "$ mkdir -p /tmp/foo/bar/baz\n" - -#define mkfifo_trivial_usage \ - "[OPTIONS] name" -#define mkfifo_full_usage \ - "Creates a named pipe (identical to 'mknod name p')\n\n" \ - "Options:\n" \ - "\t-m\tcreate the pipe using the specified mode (default a=rw)" - -#define mkfs_minix_trivial_usage \ - "[-c | -l filename] [-nXX] [-iXX] /dev/name [blocks]" -#define mkfs_minix_full_usage \ - "Make a MINIX filesystem.\n\n" \ - "Options:\n" \ - "\t-c\t\tCheck the device for bad blocks\n" \ - "\t-n [14|30]\tSpecify the maximum length of filenames\n" \ - "\t-i INODES\tSpecify the number of inodes for the filesystem\n" \ - "\t-l FILENAME\tRead the bad blocks list from FILENAME\n" \ - "\t-v\t\tMake a Minix version 2 filesystem" - -#define mknod_trivial_usage \ - "[OPTIONS] NAME TYPE MAJOR MINOR" -#define mknod_full_usage \ - "Create a special file (block, character, or pipe).\n\n" \ - "Options:\n" \ - "\t-m\tcreate the special file using the specified mode (default a=rw)\n\n" \ - "TYPEs include:\n" \ - "\tb:\tMake a block (buffered) device.\n" \ - "\tc or u:\tMake a character (un-buffered) device.\n" \ - "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes." -#define mknod_example_usage \ - "$ mknod /dev/fd0 b 2 0 \n" \ - "$ mknod -m 644 /tmp/pipe p\n" - -#define mkswap_trivial_usage \ - "[-c] [-v0|-v1] device [block-count]" -#define mkswap_full_usage \ - "Prepare a disk partition to be used as a swap partition.\n\n" \ - "Options:\n" \ - "\t-c\t\tCheck for read-ability.\n" \ - "\t-v0\t\tMake version 0 swap [max 128 Megs].\n" \ - "\t-v1\t\tMake version 1 swap [big!] (default for kernels >\n\t\t\t2.1.117).\n" \ - "\tblock-count\tNumber of block to use (default is entire partition)." - -#define mktemp_trivial_usage \ - "[-q] TEMPLATE" -#define mktemp_full_usage \ - "Creates a temporary file with its name based on TEMPLATE.\n" \ - "TEMPLATE is any name with six `Xs' (i.e., /tmp/temp.XXXXXX)." -#define mktemp_example_usage \ - "$ mktemp /tmp/temp.XXXXXX\n" \ - "/tmp/temp.mWiLjM\n" \ - "$ ls -la /tmp/temp.mWiLjM\n" \ - "-rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM\n" - -#define modprobe_trivial_usage \ - "[FILE ...]" -#define modprobe_full_usage \ - "Used for hight level module loading and unloading." -#define modprobe_example_usage \ - "$ modprobe cdrom\n" - -#define more_trivial_usage \ - "[FILE ...]" -#define more_full_usage \ - "More is a filter for viewing FILE one screenful at a time." -#define more_example_usage \ - "$ dmesg | more\n" - -#ifdef BB_FEATURE_MOUNT_LOOP - #define USAGE_MOUNT_LOOP(a) a -#else - #define USAGE_MOUNT_LOOP(a) -#endif -#ifdef BB_FEATURE_MTAB_SUPPORT - #define USAGE_MTAB(a) a -#else - #define USAGE_MTAB(a) -#endif -#define mount_trivial_usage \ - "[flags] DEVICE NODE [-o options,more-options]" -#define mount_full_usage \ - "Mount a filesystem\n\n" \ - "Flags:\n" \ - "\t-a:\t\tMount all filesystems in fstab.\n" \ - USAGE_MTAB( \ - "\t-f:\t\t\"Fake\" Add entry to mount table but don't mount it.\n" \ - "\t-n:\t\tDon't write a mount table entry.\n" \ - ) \ - "\t-o option:\tOne of many filesystem options, listed below.\n" \ - "\t-r:\t\tMount the filesystem read-only.\n" \ - "\t-t fs-type:\tSpecify the filesystem type.\n" \ - "\t-w:\t\tMount for reading and writing (default).\n" \ - "\n" \ - "Options for use with the \"-o\" flag:\n" \ - "\tasync/sync:\tWrites are asynchronous / synchronous.\n" \ - "\tatime/noatime:\tEnable / disable updates to inode access times.\n" \ - "\tdev/nodev:\tAllow use of special device files / disallow them.\n" \ - "\texec/noexec:\tAllow use of executable files / disallow them.\n" \ - USAGE_MOUNT_LOOP( \ - "\tloop:\t\tMounts a file via loop device.\n" \ - ) \ - "\tsuid/nosuid:\tAllow set-user-id-root programs / disallow them.\n" \ - "\tremount:\tRe-mount a mounted filesystem, changing its flags.\n" \ - "\tro/rw:\t\tMount for read-only / read-write.\n" \ - "\tbind:\t\tUse the linux 2.4.x \"bind\" feature.\n" \ - "\nThere are EVEN MORE flags that are specific to each filesystem.\n" \ - "You'll have to see the written documentation for those filesystems." -#define mount_example_usage \ - "$ mount\n" \ - "/dev/hda3 on / type minix (rw)\n" \ - "proc on /proc type proc (rw)\n" \ - "devpts on /dev/pts type devpts (rw)\n" \ - "$ mount /dev/fd0 /mnt -t msdos -o ro\n" \ - "$ mount /tmp/diskimage /opt -t ext2 -o loop\n" - -#define mt_trivial_usage \ - "[-f device] opcode value" -#define mt_full_usage \ - "Control magnetic tape drive operation\n" \ - "\nAvailable Opcodes:\n\n" \ - "bsf bsfm bsr bss datacompression drvbuffer eof eom erase\n" \ - "fsf fsfm fsr fss load lock mkpart nop offline ras1 ras2\n" \ - "ras3 reset retension rew rewoffline seek setblk setdensity\n" \ - "setpart tell unload unlock weof wset" - -#define mv_trivial_usage \ - "SOURCE DEST\n" \ - "or: mv SOURCE... DIRECTORY" -#define mv_full_usage \ - "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY." -#define mv_example_usage \ - "$ mv /tmp/foo /bin/bar\n" - -#define nc_trivial_usage \ - "[IP] [port]" -#define nc_full_usage \ - "Netcat opens a pipe to IP:port" -#define nc_example_usage \ - "$ nc foobar.somedomain.com 25\n" \ - "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" \ - "help\n" \ - "214-Commands supported:\n" \ - "214- HELO EHLO MAIL RCPT DATA AUTH\n" \ - "214 NOOP QUIT RSET HELP\n" \ - "quit\n" \ - "221 foobar closing connection\n" - -#define nslookup_trivial_usage \ - "[HOST] [SERVER]" -#define nslookup_full_usage \ - "Queries the nameserver for the IP address of the given HOST\n" \ - "optionally using a specified DNS server" -#define nslookup_example_usage \ - "$ nslookup localhost\n" \ - "Server: default\n" \ - "Address: default\n" \ - "\n" \ - "Name: debian\n" \ - "Address: 127.0.0.1\n" - -#define pidof_trivial_usage \ - "process-name [process-name ...]" -#define pidof_full_usage \ - "Lists the PIDs of all processes with names that match the names on the command line" -#define pidof_example_usage \ - "$ pidof init\n" \ - "1\n" - -#ifndef BB_FEATURE_FANCY_PING -#define ping_trivial_usage "host" -#define ping_full_usage "Send ICMP ECHO_REQUEST packets to network hosts" -#else -#define ping_trivial_usage \ - "[OPTION]... host" -#define ping_full_usage \ - "Send ICMP ECHO_REQUEST packets to network hosts.\n\n" \ - "Options:\n" \ - "\t-c COUNT\tSend only COUNT pings.\n" \ - "\t-s SIZE\t\tSend SIZE data bytes in packets (default=56).\n" \ - "\t-q\t\tQuiet mode, only displays output at start\n" \ - "\t\t\tand when finished." -#endif -#define ping_example_usage \ - "$ ping localhost\n" \ - "PING slag (127.0.0.1): 56 data bytes\n" \ - "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" \ - "\n" \ - "--- debian ping statistics ---\n" \ - "1 packets transmitted, 1 packets received, 0% packet loss\n" \ - "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" - -#define pivot_root_trivial_usage \ - "NEW_ROOT PUT_OLD" -#define pivot_root_full_usage \ - "Move the current root file system to PUT_OLD and make NEW_ROOT\n" \ - "the new root file system." - -#define poweroff_trivial_usage \ - "" -#define poweroff_full_usage \ - "Halt the system and request that the kernel shut off the power." - -#define printf_trivial_usage \ - "FORMAT [ARGUMENT...]" -#define printf_full_usage \ - "Formats and prints ARGUMENT(s) according to FORMAT,\n" \ - "Where FORMAT controls the output exactly as in C printf." -#define printf_example_usage \ - "$ printf "Val=%d\\n" 5\n" \ - "Val=5\n" - -#define ps_trivial_usage \ - "" -#define ps_full_usage \ - "Report process status\n" \ - "\nThis version of ps accepts no options." -#define ps_example_usage \ - "$ ps\n" \ - " PID Uid Gid State Command\n" \ - " 1 root root S init\n" \ - " 2 root root S [kflushd]\n" \ - " 3 root root S [kupdate]\n" \ - " 4 root root S [kpiod]\n" \ - " 5 root root S [kswapd]\n" \ - " 742 andersen andersen S [bash]\n" \ - " 743 andersen andersen S -bash\n" \ - " 745 root root S [getty]\n" \ - " 2990 andersen andersen R ps\n" - -#define pwd_trivial_usage \ - "" -#define pwd_full_usage \ - "Print the full filename of the current working directory." -#define pwd_example_usage \ - "$ pwd\n" \ - "/root\n" - -#define rdate_trivial_usage \ - "[OPTION] HOST" -#define rdate_full_usage \ - "Get and possibly set the system date and time from a remote HOST.\n\n" \ - "Options:\n" \ - "\t-s\tSet the system date and time (default).\n" \ - "\t-p\tPrint the date and time." - -#define readlink_trivial_usage \ - "" -#define readlink_full_usage \ - "Read a symbolic link." - -#define reboot_trivial_usage \ - "" -#define reboot_full_usage \ - "Reboot the system." - -#define renice_trivial_usage \ - "priority pid [pid ...]" -#define renice_full_usage \ - "Changes priority of running processes. Allowed priorities range\n" \ - "from 20 (the process runs only when nothing else is running) to 0\n" \ - "(default priority) to -20 (almost nothing else ever gets to run)." - -#define reset_trivial_usage \ - "" -#define reset_full_usage \ - "Resets the screen." - -#define rm_trivial_usage \ - "[OPTION]... FILE..." -#define rm_full_usage \ - "Remove (unlink) the FILE(s). You may use '--' to\n" \ - "indicate that all following arguments are non-options.\n\n" \ - "Options:\n" \ - "\t-i\t\talways prompt before removing each destination" \ - "\t-f\t\tremove existing destinations, never prompt\n" \ - "\t-r or -R\tremove the contents of directories recursively" -#define rm_example_usage \ - "$ rm -rf /tmp/foo\n" - -#define rmdir_trivial_usage \ - "[OPTION]... DIRECTORY..." -#define rmdir_full_usage \ - "Remove the DIRECTORY(ies), if they are empty." -#define rmdir_example_usage \ - "# rmdir /tmp/foo\n" - -#define rmmod_trivial_usage \ - "[OPTION]... [MODULE]..." -#define rmmod_full_usage \ - "Unloads the specified kernel modules from the kernel.\n\n" \ - "Options:\n" \ - "\t-a\tTry to remove all unused kernel modules." -#define rmmod_example_usage \ - "$ rmmod tulip\n" - -#define route_trivial_usage \ - "[{add|del|flush}]" -#define route_full_usage \ - "Edit the kernel's routing tables" - -#define rpm2cpio_trivial_usage \ - "package.rpm" -#define rpm2cpio_full_usage \ - "Outputs a cpio archive of the rpm file." - -#define sed_trivial_usage \ - "[-nef] pattern [files...]" -#define sed_full_usage \ - "Options:\n" \ - "\t-n\t\tsuppress automatic printing of pattern space\n" \ - "\t-e script\tadd the script to the commands to be executed\n" \ - "\t-f scriptfile\tadd the contents of script-file to the commands to be executed\n" \ - "\n" \ - "If no -e or -f is given, the first non-option argument is taken as the\n" \ - "sed script to interpret. All remaining arguments are names of input\n" \ - "files; if no input files are specified, then the standard input is read." -#define sed_example_usage \ - "$ echo "foo" | sed -e 's/f[a-zA-Z]o/bar/g'\n" \ - "bar\n" - -#define setkeycodes_trivial_usage \ - "SCANCODE KEYCODE ..." -#define setkeycodes_full_usage \ - "Set entries into the kernel's scancode-to-keycode map,\n" \ - "allowing unusual keyboards to generate usable keycodes.\n\n" \ - "SCANCODE may be either xx or e0xx (hexadecimal),\n" \ - "and KEYCODE is given in decimal" -#define setkeycodes_example_usage \ - "$ setkeycodes e030 127\n" - -#define lash_trivial_usage \ - "[FILE]...\n" \ - "or: sh -c command [args]..." -#define lash_full_usage \ - "lash: The BusyBox LAme SHell (command interpreter)" -#define lash_notes_usage \ -"This command does not yet have proper documentation.\n" \ -"\n" \ -"Use lash just as you would use any other shell. It properly handles pipes,\n" \ -"redirects, job control, can be used as the shell for scripts, and has a\n" \ -"sufficient set of builtins to do what is needed. It does not (yet) support\n" \ -"Bourne Shell syntax. If you need things like "if-then-else", "while", and such\n" \ -"use ash or bash. If you just need a very simple and extremely small shell,\n" \ -"this will do the job." - -#define sleep_trivial_usage \ - "N" -#define sleep_full_usage \ - "Pause for N seconds." -#define sleep_example_usage \ - "$ sleep 2\n" \ - "[2 second delay results]\n" - - -#ifdef BB_FEATURE_SORT_UNIQUE - #define USAGE_SORT_UNIQUE(a) a -#else - #define USAGE_SORT_UNIQUE(a) -#endif -#ifdef BB_FEATURE_SORT_REVERSE - #define USAGE_SORT_REVERSE(a) a -#else - #define USAGE_SORT_REVERSE(a) -#endif -#define sort_trivial_usage \ - "[-n" USAGE_SORT_REVERSE("r") USAGE_SORT_UNIQUE("u") "] [FILE]..." -#define sort_full_usage \ - "Sorts lines of text in the specified files\n\n"\ - "Options:\n" \ - USAGE_SORT_UNIQUE("\t-u\tsuppress duplicate lines\n") \ - USAGE_SORT_REVERSE("\t-r\tsort in reverse order\n") \ - "\t-n\tsort numerics" -#define sort_example_usage \ - "$ echo -e \"e\\nf\\nb\\nd\\nc\\na\" | sort\n" \ - "a\n" \ - "b\n" \ - "c\n" \ - "d\n" \ - "e\n" \ - "f\n" - -#define stty_trivial_usage \ - "[-a|g] [-F DEVICE] [SETTING]..." -#define stty_full_usage \ - "Without arguments, prints baud rate, line discipline," \ - "\nand deviations from stty sane." \ - "\n\nOptions:" \ - "\n\t-F DEVICE\topen device instead of stdin" \ - "\n\t-a\t\tprint all current settings in human-readable form" \ - "\n\t-g\t\tprint in stty-readable form" \ - "\n\t[SETTING]\tsee manpage" - -#define swapoff_trivial_usage \ - "[OPTION] [DEVICE]" -#define swapoff_full_usage \ - "Stop swapping virtual memory pages on DEVICE.\n\n" \ - "Options:\n" \ - "\t-a\tStop swapping on all swap devices" - -#define swapon_trivial_usage \ - "[OPTION] [DEVICE]" -#define swapon_full_usage \ - "Start swapping virtual memory pages on DEVICE.\n\n" \ - "Options:\n" \ - "\t-a\tStart swapping on all swap devices" - -#define sync_trivial_usage \ - "" -#define sync_full_usage \ - "Write all buffered filesystem blocks to disk." - - -#ifdef BB_FEATURE_REMOTE_LOG - #define USAGE_REMOTE_LOG(a) a -#else - #define USAGE_REMOTE_LOG(a) -#endif -#define syslogd_trivial_usage \ - "[OPTION]..." -#define syslogd_full_usage \ - "Linux system and kernel logging utility.\n" \ - "Note that this version of syslogd ignores /etc/syslog.conf.\n\n" \ - "Options:\n" \ - "\t-m NUM\t\tInterval between MARK lines (default=20min, 0=off)\n" \ - "\t-n\t\tRun as a foreground process\n" \ - "\t-O FILE\t\tUse an alternate log file (default=/var/log/messages)" \ - USAGE_REMOTE_LOG( \ - "\n\t-R HOST[:PORT]\tLog to IP or hostname on PORT (default PORT=514/UDP)\n" \ - "\t-L\t\tLog locally and via network logging (default is network only)") -#define syslogd_example_usage \ - "$ syslogd -R masterlog:514\n" \ - "$ syslogd -R 192.168.1.1:601\n" - - -#ifndef BB_FEATURE_FANCY_TAIL - #define USAGE_UNSIMPLE_TAIL(a) -#else - #define USAGE_UNSIMPLE_TAIL(a) a -#endif -#define tail_trivial_usage \ - "[OPTION]... [FILE]..." -#define tail_full_usage \ - "Print last 10 lines of each FILE to standard output.\n" \ - "With more than one FILE, precede each with a header giving the\n" \ - "file name. With no FILE, or when FILE is -, read standard input.\n\n" \ - "Options:\n" \ - USAGE_UNSIMPLE_TAIL("\t-c N[kbm]\toutput the last N bytes\n") \ - "\t-n N[kbm]\tprint last N lines instead of last 10\n" \ - "\t-f\t\toutput data as the file grows" \ - USAGE_UNSIMPLE_TAIL( "\n\t-q\t\tnever output headers giving file names\n" \ - "\t-s SEC\t\twait SEC seconds between reads with -f\n" \ - "\t-v\t\talways output headers giving file names\n\n" \ - "If the first character of N (bytes or lines) is a '+', output begins with \n" \ - "the Nth item from the start of each file, otherwise, print the last N items\n" \ - "in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2)." ) -#define tail_example_usage \ - "$ tail -n 1 /etc/resolv.conf\n" \ - "nameserver 10.0.0.1\n" - -#ifdef BB_FEATURE_TAR_CREATE - #define USAGE_TAR_CREATE(a) a -#else - #define USAGE_TAR_CREATE(a) -#endif -#ifdef BB_FEATURE_TAR_EXCLUDE - #define USAGE_TAR_EXCLUDE(a) a -#else - #define USAGE_TAR_EXCLUDE(a) -#endif -#define tar_trivial_usage \ - "-[" USAGE_TAR_CREATE("c") "xtvO] " \ - USAGE_TAR_EXCLUDE("[--exclude FILE] [-X FILE]") \ - "[-f TARFILE] [-C DIR] [FILE(s)] ..." -#define tar_full_usage \ - "Create, extract, or list files from a tar file.\n\n" \ - "Options:\n" \ - USAGE_TAR_CREATE("\tc\t\tcreate\n") \ - "\tx\t\textract\n" \ - "\tt\t\tlist\n" \ - "\nFile selection:\n" \ - "\tf\t\tname of TARFILE or \"-\" for stdin\n" \ - "\tO\t\textract to stdout\n" \ - USAGE_TAR_EXCLUDE( \ - "\texclude\t\tfile to exclude\n" \ - "\tX\t\tfile with names to exclude\n" \ - ) \ - "\tC\t\tchange to directory DIR before operation\n" \ - "\tv\t\tverbosely list files processed" -#define tar_example_usage \ - "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" \ - "$ tar -cf /tmp/tarball.tar /usr/local\n" - -#define tee_trivial_usage \ - "[OPTION]... [FILE]..." -#define tee_full_usage \ - "Copy standard input to each FILE, and also to standard output.\n\n" \ - "Options:\n" \ - "\t-a\tappend to the given FILEs, do not overwrite" -#define tee_example_usage \ - "$ echo "Hello" | tee /tmp/foo\n" \ - "$ cat /tmp/foo\n" \ - "Hello\n" - -#define telnet_trivial_usage \ - "HOST [PORT]" -#define telnet_full_usage \ - "Telnet is used to establish interactive communication with another\n"\ - "computer over a network using the TELNET protocol." - -#define test_trivial_usage \ - "EXPRESSION\n or [ EXPRESSION ]" -#define test_full_usage \ - "Checks file types and compares values returning an exit\n" \ - "code determined by the value of EXPRESSION." -#define test_example_usage \ - "$ test 1 -eq 2\n" \ - "$ echo $?\n" \ - "1\n" \ - "$ test 1 -eq 1\n" \ - "$ echo $? \n" \ - "0\n" \ - "$ [ -d /etc ]\n" \ - "$ echo $?\n" \ - "0\n" \ - "$ [ -d /junk ]\n" \ - "$ echo $?\n" \ - "1\n" - -#ifdef BB_FEATURE_TFTP_GET - #define USAGE_TFTP_GET(a) a -#else - #define USAGE_TFTP_GET(a) -#endif -#ifdef BB_FEATURE_TFTP_PUT - #define USAGE_TFTP_PUT(a) a -#else - #define USAGE_TFTP_PUT(a) -#endif - -#define tftp_trivial_usage \ - "[OPTION]... HOST [PORT]" -#define tftp_full_usage \ - "Transfers a file from/to a tftp server using \"octet\" mode.\n\n" \ - "Options:\n" \ - "\t-b SIZE\tTransfer blocks of SIZE octets.\n" \ - USAGE_TFTP_GET( \ - "\t-g\tGet file.\n" \ - ) \ - "\t-l FILE\tTransfer local FILE.\n" \ - USAGE_TFTP_PUT( \ - "\t-p\tPut file.\n" \ - ) \ - "\t-r FILE\tTransfer remote FILE.\n" - -#define touch_trivial_usage \ - "[-c] FILE [FILE ...]" -#define touch_full_usage \ - "Update the last-modified date on the given FILE[s].\n\n" \ - "Options:\n" \ - "\t-c\tDo not create any files" -#define touch_example_usage \ - "$ ls -l /tmp/foo\n" \ - "/bin/ls: /tmp/foo: No such file or directory\n" \ - "$ touch /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo\n" - -#define tr_trivial_usage \ - "[-cds] STRING1 [STRING2]" -#define tr_full_usage \ - "Translate, squeeze, and/or delete characters from\n" \ - "standard input, writing to standard output.\n\n" \ - "Options:\n" \ - "\t-c\ttake complement of STRING1\n" \ - "\t-d\tdelete input characters coded STRING1\n" \ - "\t-s\tsqueeze multiple output characters of STRING2 into one character" -#define tr_example_usage \ - "$ echo "gdkkn vnqkc" | tr [a-y] [b-z]\n" \ - "hello world\n" - -#define traceroute_trivial_usage \ - "[-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\ - [-s src_addr] [-t tos] [-w wait] host [data size]" -#define traceroute_full_usage \ - "trace the route ip packets follow going to \"host\"\n" \ - "Options:\n" \ - "\t-d\tset SO_DEBUG options to socket\n" \ - "\t-n\tPrint hop addresses numerically rather than symbolically\n" \ - "\t-r\tBypass the normal routing tables and send directly to a host\n" \ - "\t-v\tVerbose output\n" \ - "\t-m max_ttl\tSet the max time-to-live (max number of hops)\n" \ - "\t-p port#\tSet the base UDP port number used in probes\n" \ - "\t\t(default is 33434)\n" \ - "\t-q nqueries\tSet the number of probes per ``ttl'' to nqueries\n" \ - "\t\t(default is 3)\n" \ - "\t-s src_addr\tUse the following IP address as the source address\n" \ - "\t-t tos\tSet the type-of-service in probe packets to the following value\n" \ - "\t\t(default 0)\n" \ - "\t-w wait\tSet the time (in seconds) to wait for a response to a probe\n" \ - "\t\t(default 3 sec.)." - - -#define true_trivial_usage \ - "" -#define true_full_usage \ - "Return an exit code of TRUE (0)." -#define true_example_usage \ - "$ true\n" \ - "$ echo $?\n" \ - "0\n" - -#define tty_trivial_usage \ - "" -#define tty_full_usage \ - "Print the file name of the terminal connected to standard input.\n\n"\ - "Options:\n" \ - "\t-s\tprint nothing, only return an exit status" -#define tty_example_usage \ - "$ tty\n" \ - "/dev/tty2\n" - -#ifdef BB_FEATURE_MOUNT_FORCE - #define USAGE_MOUNT_FORCE(a) a -#else - #define USAGE_MOUNT_FORCE(a) -#endif -#define umount_trivial_usage \ - "[flags] FILESYSTEM|DIRECTORY" -#define umount_full_usage \ - "Unmount file systems\n" \ - "\nFlags:\n" "\t-a\tUnmount all file systems" \ - USAGE_MTAB(" in /etc/mtab\n\t-n\tDon't erase /etc/mtab entries") \ - "\n\t-r\tTry to remount devices as read-only if mount is busy" \ - USAGE_MOUNT_FORCE("\n\t-f\tForce umount (i.e., unreachable NFS server)") \ - USAGE_MOUNT_LOOP("\n\t-l\tDo not free loop device (if a loop device has been used)") -#define umount_example_usage \ - "$ umount /dev/hdc1 \n" - -#define uname_trivial_usage \ - "[OPTION]..." -#define uname_full_usage \ - "Print certain system information. With no OPTION, same as -s.\n\n" \ - "Options:\n" \ - "\t-a\tprint all information\n" \ - "\t-m\tthe machine (hardware) type\n" \ - "\t-n\tprint the machine's network node hostname\n" \ - "\t-r\tprint the operating system release\n" \ - "\t-s\tprint the operating system name\n" \ - "\t-p\tprint the host processor type\n" \ - "\t-v\tprint the operating system version" -#define uname_example_usage \ - "$ uname -a\n" \ - "Linux debian 2.2.15pre13 #5 Tue Mar 14 16:03:50 MST 2000 i686 unknown\n" - -#define uniq_trivial_usage \ - "[OPTION]... [INPUT [OUTPUT]]" -#define uniq_full_usage \ - "Discard all but one of successive identical lines from INPUT\n" \ - "(or standard input), writing to OUTPUT (or standard output).\n\n" \ - "Options:\n" \ - "\t-c\tprefix lines by the number of occurrences\n" \ - "\t-d\tonly print duplicate lines\n" \ - "\t-u\tonly print unique lines" -#define uniq_example_usage \ - "$ echo -e \"a\\na\\nb\\nc\\nc\\na\" | sort | uniq\n" \ - "a\n" \ - "b\n" \ - "c\n" - -#define unix2dos_trivial_usage \ - "[option] [FILE]" -#define unix2dos_full_usage \ - "Converts FILE from unix format to dos format. When no option\n" \ - "is given, the input is converted to the opposite output format.\n" \ - "When no file is given, uses stdin for input and stdout for output.\n" \ - "Options:\n" \ - "\t-u\toutput will be in UNIX format\n" \ - "\t-d\toutput will be in DOS format" - -#define update_trivial_usage \ - "[options]" -#define update_full_usage \ - "Periodically flushes filesystem buffers.\n\n" \ - "Options:\n" \ - "\t-S\tforce use of sync(2) instead of flushing\n" \ - "\t-s SECS\tcall sync this often (default 30)\n" \ - "\t-f SECS\tflush some buffers this often (default 5)" - -#define uptime_trivial_usage \ - "" -#define uptime_full_usage \ - "Display the time since the last boot." -#define uptime_example_usage \ - "$ uptime\n" \ - " 1:55pm up 2:30, load average: 0.09, 0.04, 0.00\n" - -#define usleep_trivial_usage \ - "N" -#define usleep_full_usage \ - "Pause for N microseconds." -#define usleep_example_usage \ - "$ usleep 1000000\n" \ - "[pauses for 1 second]\n" - -#define uudecode_trivial_usage \ - "[FILE]..." -#define uudecode_full_usage \ - "Uudecode a file that is uuencoded.\n\n" \ - "Options:\n" \ - "\t-o FILE\tdirect output to FILE" -#define uudecode_example_usage \ - "$ uudecode -o busybox busybox.uu\n" \ - "$ ls -l busybox\n" \ - "-rwxr-xr-x 1 ams ams 245264 Jun 7 21:35 busybox\n" - -#define uuencode_trivial_usage \ - "[OPTION] [INFILE] REMOTEFILE" -#define uuencode_full_usage \ - "Uuencode a file.\n\n" \ - "Options:\n" \ - "\t-m\tuse base64 encoding per RFC1521" -#define uuencode_example_usage \ - "$ uuencode busybox busybox\n" \ - "begin 755 busybox\n" \ - "\n" \ - "$ uudecode busybox busybox > busybox.uu\n" \ - "$\n" - -#define vi_trivial_usage \ - "[OPTION] [FILE]..." -#define vi_full_usage \ - "edit FILE.\n\n" \ - "Options:\n" \ - "\t-R\tRead-only- do not write to the file." - -#define watchdog_trivial_usage \ - "DEV" -#define watchdog_full_usage \ - "Periodically write to watchdog device DEV" - -#define wc_trivial_usage \ - "[OPTION]... [FILE]..." -#define wc_full_usage \ - "Print line, word, and byte counts for each FILE, and a total line if\n" \ - "more than one FILE is specified. With no FILE, read standard input.\n\n" \ - "Options:\n" \ - "\t-c\tprint the byte counts\n" \ - "\t-l\tprint the newline counts\n" \ - "\t-L\tprint the length of the longest line\n" \ - "\t-w\tprint the word counts" -#define wc_example_usage \ - "$ wc /etc/passwd\n" \ - " 31 46 1365 /etc/passwd\n" - -#define wget_trivial_usage \ - "[-c|--continue] [-q|--quiet] [-O|--output-document file]\n\t[--header 'header: value'] [-P DIR] url" -#define wget_full_usage \ - "wget retrieves files via HTTP or FTP\n\n" \ - "Options:\n" \ - "\t-c\tcontinue retrieval of aborted transfers\n" \ - "\t-q\tquiet mode - do not print\n" \ - "\t-P\tSet directory prefix to DIR\n" \ - "\t-O\tsave to filename ('-' for stdout)" - -#define which_trivial_usage \ - "[COMMAND ...]" -#define which_full_usage \ - "Locates a COMMAND." -#define which_example_usage \ - "$ which login\n" \ - "/bin/login\n" - -#define whoami_trivial_usage \ - "" -#define whoami_full_usage \ - "Prints the user name associated with the current effective user id." - -#define xargs_trivial_usage \ - "[COMMAND] [ARGS...]" -#define xargs_full_usage \ - "Executes COMMAND on every item given by standard input." -#define xargs_example_usage \ - "$ ls | xargs gzip\n" \ - "$ find . -name '*.c' -print | xargs rm\n" - -#define yes_trivial_usage \ - "[OPTION]... [STRING]..." -#define yes_full_usage \ - "Repeatedly outputs a line with all specified STRING(s), or 'y'." - -#define zcat_trivial_usage \ - "FILE" -#define zcat_full_usage \ - "Uncompress to stdout." diff --git a/busybox/usleep.c b/busybox/usleep.c deleted file mode 100644 index 6023bf430..000000000 --- a/busybox/usleep.c +++ /dev/null @@ -1,38 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini usleep implementation for busybox - * - * - * 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 - * - */ - -/* getopt not needed */ - -#include -#include -#include "busybox.h" - -extern int usleep_main(int argc, char **argv) -{ - if ((argc < 2) || (**(argv + 1) == '-')) { - show_usage(); - } - - usleep(atoi(*(++argv))); /* return void */ - return EXIT_SUCCESS; -} diff --git a/busybox/util-linux/dmesg.c b/busybox/util-linux/dmesg.c deleted file mode 100644 index 73de6d1ae..000000000 --- a/busybox/util-linux/dmesg.c +++ /dev/null @@ -1,95 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* dmesg.c -- Print out the contents of the kernel ring buffer - * Created: Sat Oct 9 16:19:47 1993 - * Revised: Thu Oct 28 21:52:17 1993 by faith@cs.unc.edu - * Copyright 1993 Theodore Ts'o (tytso@athena.mit.edu) - * This program comes with ABSOLUTELY NO WARRANTY. - * Modifications by Rick Sladkey (jrs@world.std.com) - * Larger buffersize 3 June 1998 by Nicolai Langfeldt, based on a patch - * by Peeter Joot. This was also suggested by John Hudson. - * 1999-02-22 Arkadiusz Mi¶kiewicz - * - added Native Language Support - * - * from util-linux -- adapted for busybox by - * Erik Andersen . I ripped out Native Language - * Support, replaced getopt, added some gotos for redundant stuff. - */ - -#include -#include -#include - -#if __GNU_LIBRARY__ < 5 -# ifdef __alpha__ -# define klogctl syslog -# endif -#else -# include -#endif - -#include "busybox.h" - -int dmesg_main(int argc, char **argv) -{ - char *buf; - int c; - int bufsize = 8196; - int i; - int n; - int level = 0; - int lastc; - int cmd = 3; - - while ((c = getopt(argc, argv, "cn:s:")) != EOF) { - switch (c) { - case 'c': - cmd = 4; - break; - case 'n': - cmd = 8; - if (optarg == NULL) - show_usage(); - level = atoi(optarg); - break; - case 's': - if (optarg == NULL) - show_usage(); - bufsize = atoi(optarg); - break; - default: - show_usage(); - } - } - - if (optind < argc) { - show_usage(); - } - - if (cmd == 8) { - if (klogctl(cmd, NULL, level) < 0) - perror_msg_and_die("klogctl"); - return EXIT_SUCCESS; - } - - if (bufsize < 4096) - bufsize = 4096; - buf = (char *) xmalloc(bufsize); - if ((n = klogctl(cmd, buf, bufsize)) < 0) - perror_msg_and_die("klogctl"); - - lastc = '\n'; - for (i = 0; i < n; i++) { - if (lastc == '\n' && buf[i] == '<') { - i++; - while (buf[i] >= '0' && buf[i] <= '9') - i++; - if (buf[i] == '>') - i++; - } - lastc = buf[i]; - putchar(lastc); - } - if (lastc != '\n') - putchar('\n'); - return EXIT_SUCCESS; -} diff --git a/busybox/util-linux/fbset.c b/busybox/util-linux/fbset.c deleted file mode 100644 index 5ccd80e79..000000000 --- a/busybox/util-linux/fbset.c +++ /dev/null @@ -1,424 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini fbset implementation for busybox - * - * Copyright (C) 1999 by Randolph Chung - * - * 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 - * - * This is a from-scratch implementation of fbset; but the de facto fbset - * implementation was a good reference. fbset (original) is released under - * the GPL, and is (c) 1995-1999 by: - * Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#define DEFAULTFBDEV "/dev/fb0" -#define DEFAULTFBMODE "/etc/fb.modes" - -static const int OPT_CHANGE = (1 << 0); -static const int OPT_INFO = (1 << 1); -static const int OPT_READMODE = (1 << 2); - -enum { - CMD_FB = 1, - CMD_DB = 2, - CMD_GEOMETRY = 3, - CMD_TIMING = 4, - CMD_ACCEL = 5, - CMD_HSYNC = 6, - CMD_VSYNC = 7, - CMD_LACED = 8, - CMD_DOUBLE = 9, -/* CMD_XCOMPAT = 10, */ - CMD_ALL = 11, - CMD_INFO = 12, - CMD_CHANGE = 13, - -#ifdef BB_FEATURE_FBSET_FANCY - CMD_XRES = 100, - CMD_YRES = 101, - CMD_VXRES = 102, - CMD_VYRES = 103, - CMD_DEPTH = 104, - CMD_MATCH = 105, - CMD_PIXCLOCK = 106, - CMD_LEFT = 107, - CMD_RIGHT = 108, - CMD_UPPER = 109, - CMD_LOWER = 110, - CMD_HSLEN = 111, - CMD_VSLEN = 112, - CMD_CSYNC = 113, - CMD_GSYNC = 114, - CMD_EXTSYNC = 115, - CMD_BCAST = 116, - CMD_RGBA = 117, - CMD_STEP = 118, - CMD_MOVE = 119, -#endif -}; - -static unsigned int g_options = 0; - -/* Stuff stolen from the kernel's fb.h */ -static const int FBIOGET_VSCREENINFO = 0x4600; -static const int FBIOPUT_VSCREENINFO = 0x4601; -#define __u32 u_int32_t -struct fb_bitfield { - __u32 offset; /* beginning of bitfield */ - __u32 length; /* length of bitfield */ - __u32 msb_right; /* != 0 : Most significant bit is */ - /* right */ -}; -struct fb_var_screeninfo { - __u32 xres; /* visible resolution */ - __u32 yres; - __u32 xres_virtual; /* virtual resolution */ - __u32 yres_virtual; - __u32 xoffset; /* offset from virtual to visible */ - __u32 yoffset; /* resolution */ - - __u32 bits_per_pixel; /* guess what */ - __u32 grayscale; /* != 0 Graylevels instead of colors */ - - struct fb_bitfield red; /* bitfield in fb mem if true color, */ - struct fb_bitfield green; /* else only length is significant */ - struct fb_bitfield blue; - struct fb_bitfield transp; /* transparency */ - - __u32 nonstd; /* != 0 Non standard pixel format */ - - __u32 activate; /* see FB_ACTIVATE_* */ - - __u32 height; /* height of picture in mm */ - __u32 width; /* width of picture in mm */ - - __u32 accel_flags; /* acceleration flags (hints) */ - - /* Timing: All values in pixclocks, except pixclock (of course) */ - __u32 pixclock; /* pixel clock in ps (pico seconds) */ - __u32 left_margin; /* time from sync to picture */ - __u32 right_margin; /* time from picture to sync */ - __u32 upper_margin; /* time from sync to picture */ - __u32 lower_margin; - __u32 hsync_len; /* length of horizontal sync */ - __u32 vsync_len; /* length of vertical sync */ - __u32 sync; /* see FB_SYNC_* */ - __u32 vmode; /* see FB_VMODE_* */ - __u32 reserved[6]; /* Reserved for future compatibility */ -}; - - -static struct cmdoptions_t { - char *name; - unsigned char param_count; - unsigned char code; -} g_cmdoptions[] = { - { - "-fb", 1, CMD_FB}, { - "-db", 1, CMD_DB}, { - "-a", 0, CMD_ALL}, { - "-i", 0, CMD_INFO}, { - "-g", 5, CMD_GEOMETRY}, { - "-t", 7, CMD_TIMING}, { - "-accel", 1, CMD_ACCEL}, { - "-hsync", 1, CMD_HSYNC}, { - "-vsync", 1, CMD_VSYNC}, { - "-laced", 1, CMD_LACED}, { - "-double", 1, CMD_DOUBLE}, { - "-n", 0, CMD_CHANGE}, { -#ifdef BB_FEATURE_FBSET_FANCY - "-all", 0, CMD_ALL}, { - "-xres", 1, CMD_XRES}, { - "-yres", 1, CMD_YRES}, { - "-vxres", 1, CMD_VXRES}, { - "-vyres", 1, CMD_VYRES}, { - "-depth", 1, CMD_DEPTH}, { - "-match", 0, CMD_MATCH}, { - "-geometry", 5, CMD_GEOMETRY}, { - "-pixclock", 1, CMD_PIXCLOCK}, { - "-left", 1, CMD_LEFT}, { - "-right", 1, CMD_RIGHT}, { - "-upper", 1, CMD_UPPER}, { - "-lower", 1, CMD_LOWER}, { - "-hslen", 1, CMD_HSLEN}, { - "-vslen", 1, CMD_VSLEN}, { - "-timings", 7, CMD_TIMING}, { - "-csync", 1, CMD_CSYNC}, { - "-gsync", 1, CMD_GSYNC}, { - "-extsync", 1, CMD_EXTSYNC}, { - "-bcast", 1, CMD_BCAST}, { - "-rgba", 1, CMD_RGBA}, { - "-step", 1, CMD_STEP}, { - "-move", 1, CMD_MOVE}, { -#endif - 0, 0, 0} -}; - -#ifdef BB_FEATURE_FBSET_READMODE -/* taken from linux/fb.h */ -static const int FB_VMODE_INTERLACED = 1; /* interlaced */ -static const int FB_VMODE_DOUBLE = 2; /* double scan */ -static const int FB_SYNC_HOR_HIGH_ACT = 1; /* horizontal sync high active */ -static const int FB_SYNC_VERT_HIGH_ACT = 2; /* vertical sync high active */ -static const int FB_SYNC_EXT = 4; /* external sync */ -static const int FB_SYNC_COMP_HIGH_ACT = 8; /* composite sync high active */ -#endif -static int readmode(struct fb_var_screeninfo *base, const char *fn, - const char *mode) -{ -#ifdef BB_FEATURE_FBSET_READMODE - FILE *f; - char buf[256]; - char *p = buf; - - f = xfopen(fn, "r"); - while (!feof(f)) { - fgets(buf, sizeof(buf), f); - if ((p = strstr(buf, "mode ")) || (p = strstr(buf, "mode\t"))) { - p += 5; - if ((p = strstr(buf, mode))) { - p += strlen(mode); - if (!isspace(*p) && (*p != 0) && (*p != '"') - && (*p != '\r') && (*p != '\n')) - continue; /* almost, but not quite */ - while (!feof(f)) { - fgets(buf, sizeof(buf), f); - - if ((p = strstr(buf, "geometry "))) { - p += 9; - - sscanf(p, "%d %d %d %d %d", - &(base->xres), &(base->yres), - &(base->xres_virtual), &(base->yres_virtual), - &(base->bits_per_pixel)); - } else if ((p = strstr(buf, "timings "))) { - p += 8; - - sscanf(p, "%d %d %d %d %d %d %d", - &(base->pixclock), - &(base->left_margin), &(base->right_margin), - &(base->upper_margin), &(base->lower_margin), - &(base->hsync_len), &(base->vsync_len)); - } else if ((p = strstr(buf, "laced "))) { - p += 6; - - if (strstr(buf, "false")) { - base->vmode &= ~FB_VMODE_INTERLACED; - } else { - base->vmode |= FB_VMODE_INTERLACED; - } - } else if ((p = strstr(buf, "double "))) { - p += 7; - - if (strstr(buf, "false")) { - base->vmode &= ~FB_VMODE_DOUBLE; - } else { - base->vmode |= FB_VMODE_DOUBLE; - } - } else if ((p = strstr(buf, "vsync "))) { - p += 6; - - if (strstr(buf, "low")) { - base->sync &= ~FB_SYNC_VERT_HIGH_ACT; - } else { - base->sync |= FB_SYNC_VERT_HIGH_ACT; - } - } else if ((p = strstr(buf, "hsync "))) { - p += 6; - - if (strstr(buf, "low")) { - base->sync &= ~FB_SYNC_HOR_HIGH_ACT; - } else { - base->sync |= FB_SYNC_HOR_HIGH_ACT; - } - } else if ((p = strstr(buf, "csync "))) { - p += 6; - - if (strstr(buf, "low")) { - base->sync &= ~FB_SYNC_COMP_HIGH_ACT; - } else { - base->sync |= FB_SYNC_COMP_HIGH_ACT; - } - } else if ((p = strstr(buf, "extsync "))) { - p += 8; - - if (strstr(buf, "false")) { - base->sync &= ~FB_SYNC_EXT; - } else { - base->sync |= FB_SYNC_EXT; - } - } - - if (strstr(buf, "endmode")) - return 1; - } - } - } - } -#else - error_msg( "mode reading not compiled in"); -#endif - return 0; -} - -static void setmode(struct fb_var_screeninfo *base, - struct fb_var_screeninfo *set) -{ - if ((int) set->xres > 0) - base->xres = set->xres; - if ((int) set->yres > 0) - base->yres = set->yres; - if ((int) set->xres_virtual > 0) - base->xres_virtual = set->xres_virtual; - if ((int) set->yres_virtual > 0) - base->yres_virtual = set->yres_virtual; - if ((int) set->bits_per_pixel > 0) - base->bits_per_pixel = set->bits_per_pixel; -} - -static void showmode(struct fb_var_screeninfo *v) -{ - double drate = 0, hrate = 0, vrate = 0; - - if (v->pixclock) { - drate = 1e12 / v->pixclock; - hrate = - drate / (v->left_margin + v->xres + v->right_margin + - v->hsync_len); - vrate = - hrate / (v->upper_margin + v->yres + v->lower_margin + - v->vsync_len); - } - printf("\nmode \"%ux%u-%u\"\n", v->xres, v->yres, (int) (vrate + 0.5)); -#ifdef BB_FEATURE_FBSET_FANCY - printf("\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n", drate / 1e6, - hrate / 1e3, vrate); -#endif - printf("\tgeometry %u %u %u %u %u\n", v->xres, v->yres, - v->xres_virtual, v->yres_virtual, v->bits_per_pixel); - printf("\ttimings %u %u %u %u %u %u %u\n", v->pixclock, v->left_margin, - v->right_margin, v->upper_margin, v->lower_margin, v->hsync_len, - v->vsync_len); - printf("\taccel %s\n", (v->accel_flags > 0 ? "true" : "false")); - printf("\trgba %u/%u,%u/%u,%u/%u,%u/%u\n", v->red.length, - v->red.offset, v->green.length, v->green.offset, v->blue.length, - v->blue.offset, v->transp.length, v->transp.offset); - printf("endmode\n\n"); -} - -#ifdef STANDALONE -int main(int argc, char **argv) -#else -extern int fbset_main(int argc, char **argv) -#endif -{ - struct fb_var_screeninfo var, varset; - int fh, i; - char *fbdev = DEFAULTFBDEV; - char *modefile = DEFAULTFBMODE; - char *thisarg, *mode = NULL; - - memset(&varset, 0xFF, sizeof(varset)); - - /* parse cmd args.... why do they have to make things so difficult? */ - argv++; - argc--; - for (; argc > 0 && (thisarg = *argv); argc--, argv++) { - for (i = 0; g_cmdoptions[i].name; i++) { - if (!strcmp(thisarg, g_cmdoptions[i].name)) { - if (argc - 1 < g_cmdoptions[i].param_count) - show_usage(); - switch (g_cmdoptions[i].code) { - case CMD_FB: - fbdev = argv[1]; - break; - case CMD_DB: - modefile = argv[1]; - break; - case CMD_GEOMETRY: - varset.xres = strtoul(argv[1], 0, 0); - varset.yres = strtoul(argv[2], 0, 0); - varset.xres_virtual = strtoul(argv[3], 0, 0); - varset.yres_virtual = strtoul(argv[4], 0, 0); - varset.bits_per_pixel = strtoul(argv[5], 0, 0); - break; - case CMD_TIMING: - varset.pixclock = strtoul(argv[1], 0, 0); - varset.left_margin = strtoul(argv[2], 0, 0); - varset.right_margin = strtoul(argv[3], 0, 0); - varset.upper_margin = strtoul(argv[4], 0, 0); - varset.lower_margin = strtoul(argv[5], 0, 0); - varset.hsync_len = strtoul(argv[6], 0, 0); - varset.vsync_len = strtoul(argv[7], 0, 0); - break; - case CMD_CHANGE: - g_options |= OPT_CHANGE; - break; -#ifdef BB_FEATURE_FBSET_FANCY - case CMD_XRES: - varset.xres = strtoul(argv[1], 0, 0); - break; - case CMD_YRES: - varset.yres = strtoul(argv[1], 0, 0); - break; -#endif - } - argc -= g_cmdoptions[i].param_count; - argv += g_cmdoptions[i].param_count; - break; - } - } - if (!g_cmdoptions[i].name) { - if (argc == 1) { - mode = *argv; - g_options |= OPT_READMODE; - } else { - show_usage(); - } - } - } - - if ((fh = open(fbdev, O_RDONLY)) < 0) - perror_msg_and_die("fbset(open)"); - if (ioctl(fh, FBIOGET_VSCREENINFO, &var)) - perror_msg_and_die("fbset(ioctl)"); - if (g_options & OPT_READMODE) { - if (!readmode(&var, modefile, mode)) { - error_msg("Unknown video mode `%s'", mode); - return EXIT_FAILURE; - } - } - - setmode(&var, &varset); - if (g_options & OPT_CHANGE) - if (ioctl(fh, FBIOPUT_VSCREENINFO, &var)) - perror_msg_and_die("fbset(ioctl)"); - showmode(&var); - /* Don't close the file, as exiting will take care of that */ - /* close(fh); */ - - return EXIT_SUCCESS; -} diff --git a/busybox/util-linux/fdflush.c b/busybox/util-linux/fdflush.c deleted file mode 100644 index 28f5cb68a..000000000 --- a/busybox/util-linux/fdflush.c +++ /dev/null @@ -1,47 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini fdflush implementation for busybox - * - * - * 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 - * - */ - -#include -#include -#include -#include -#include "busybox.h" - -/* From */ -#define FDFLUSH _IO(2,0x4b) - -extern int fdflush_main(int argc, char **argv) -{ - int fd; - - if (argc <= 1 || **(++argv) == '-') - show_usage(); - - if ((fd = open(*argv, 0)) < 0) - perror_msg_and_die("%s", *argv); - - if (ioctl(fd, FDFLUSH, 0)) - perror_msg_and_die("%s", *argv); - - return EXIT_SUCCESS; -} diff --git a/busybox/util-linux/freeramdisk.c b/busybox/util-linux/freeramdisk.c deleted file mode 100644 index cf25fae6a..000000000 --- a/busybox/util-linux/freeramdisk.c +++ /dev/null @@ -1,65 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * freeramdisk implementation for busybox - * - * Copyright (C) 2000 and written by Emanuele Caratti - * Adjusted a bit 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - - -/* From linux/fs.h */ -#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */ - -extern int -freeramdisk_main(int argc, char **argv) -{ - int f; - - if (argc != 2 || *argv[1] == '-') { - show_usage(); - } - - if ((f = open(argv[1], O_RDWR)) == -1) { - perror_msg_and_die("cannot open %s", argv[1]); - } - if (ioctl(f, BLKFLSBUF) < 0) { - perror_msg_and_die("failed ioctl on %s", argv[1]); - } - /* Don't bother closing. Exit does - * that, so we can save a few bytes */ - /* close(f); */ - return EXIT_SUCCESS; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ - diff --git a/busybox/util-linux/fsck_minix.c b/busybox/util-linux/fsck_minix.c deleted file mode 100644 index 952968d85..000000000 --- a/busybox/util-linux/fsck_minix.c +++ /dev/null @@ -1,1478 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * fsck.c - a file system consistency checker for Linux. - * - * (C) 1991, 1992 Linus Torvalds. This file may be redistributed - * as per the GNU copyleft. - */ - -/* - * 09.11.91 - made the first rudimetary functions - * - * 10.11.91 - updated, does checking, no repairs yet. - * Sent out to the mailing-list for testing. - * - * 14.11.91 - Testing seems to have gone well. Added some - * correction-code, and changed some functions. - * - * 15.11.91 - More correction code. Hopefully it notices most - * cases now, and tries to do something about them. - * - * 16.11.91 - More corrections (thanks to Mika Jalava). Most - * things seem to work now. Yeah, sure. - * - * - * 19.04.92 - Had to start over again from this old version, as a - * kernel bug ate my enhanced fsck in february. - * - * 28.02.93 - added support for different directory entry sizes.. - * - * Sat Mar 6 18:59:42 1993, faith@cs.unc.edu: Output namelen with - * super-block information - * - * Sat Oct 9 11:17:11 1993, faith@cs.unc.edu: make exit status conform - * to that required by fsutil - * - * Mon Jan 3 11:06:52 1994 - Dr. Wettstein (greg%wind.uucp@plains.nodak.edu) - * Added support for file system valid flag. Also - * added program_version variable and output of - * program name and version number when program - * is executed. - * - * 30.10.94 - added support for v2 filesystem - * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de) - * - * 10.12.94 - added test to prevent checking of mounted fs adapted - * from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck - * program. (Daniel Quinlan, quinlan@yggdrasil.com) - * - * 01.07.96 - Fixed the v2 fs stuff to use the right #defines and such - * for modern libcs (janl@math.uio.no, Nicolai Langfeldt) - * - * 02.07.96 - Added C bit fiddling routines from rmk@ecs.soton.ac.uk - * (Russell King). He made them for ARM. It would seem - * that the ARM is powerful enough to do this in C whereas - * i386 and m64k must use assembly to get it fast >:-) - * This should make minix fsck systemindependent. - * (janl@math.uio.no, Nicolai Langfeldt) - * - * 04.11.96 - Added minor fixes from Andreas Schwab to avoid compiler - * warnings. Added mc68k bitops from - * Joerg Dorchain . - * - * 06.11.96 - Added v2 code submitted by Joerg Dorchain, but written by - * Andreas Schwab. - * - * 1999-02-22 Arkadiusz Mi¶kiewicz - * - added Native Language Support - * - * - * I've had no time to add comments - hopefully the function names - * are comments enough. As with all file system checkers, this assumes - * the file system is quiescent - don't use it on a mounted device - * unless you can be sure nobody is writing to it (and remember that the - * kernel can write to it when it searches for files). - * - * Usuage: fsck [-larvsm] device - * -l for a listing of all the filenames - * -a for automatic repairs (not implemented) - * -r for repairs (interactive) (not implemented) - * -v for verbose (tells how many files) - * -s for super-block info - * -m for minix-like "mode not cleared" warnings - * -f force filesystem check even if filesystem marked as valid - * - * The device may be a block device or a image of one, but this isn't - * enforced (but it's not much fun on a character device :-). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -static const int MINIX_ROOT_INO = 1; -static const int MINIX_LINK_MAX = 250; -static const int MINIX2_LINK_MAX = 65530; - -static const int MINIX_I_MAP_SLOTS = 8; -static const int MINIX_Z_MAP_SLOTS = 64; -static const int MINIX_SUPER_MAGIC = 0x137F; /* original minix fs */ -static const int MINIX_SUPER_MAGIC2 = 0x138F; /* minix fs, 30 char names */ -static const int MINIX2_SUPER_MAGIC = 0x2468; /* minix V2 fs */ -static const int MINIX2_SUPER_MAGIC2 = 0x2478; /* minix V2 fs, 30 char names */ -static const int MINIX_VALID_FS = 0x0001; /* Clean fs. */ -static const int MINIX_ERROR_FS = 0x0002; /* fs has errors. */ - -#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) -#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode))) - -static const int MINIX_V1 = 0x0001; /* original minix fs */ -static const int MINIX_V2 = 0x0002; /* minix V2 fs */ - -#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version - -/* - * This is the original minix inode layout on disk. - * Note the 8-bit gid and atime and ctime. - */ -struct minix_inode { - u_int16_t i_mode; - u_int16_t i_uid; - u_int32_t i_size; - u_int32_t i_time; - u_int8_t i_gid; - u_int8_t i_nlinks; - u_int16_t i_zone[9]; -}; - -/* - * The new minix inode has all the time entries, as well as - * long block numbers and a third indirect block (7+1+1+1 - * instead of 7+1+1). Also, some previously 8-bit values are - * now 16-bit. The inode is now 64 bytes instead of 32. - */ -struct minix2_inode { - u_int16_t i_mode; - u_int16_t i_nlinks; - u_int16_t i_uid; - u_int16_t i_gid; - u_int32_t i_size; - u_int32_t i_atime; - u_int32_t i_mtime; - u_int32_t i_ctime; - u_int32_t i_zone[10]; -}; - -/* - * minix super-block data on disk - */ -struct minix_super_block { - u_int16_t s_ninodes; - u_int16_t s_nzones; - u_int16_t s_imap_blocks; - u_int16_t s_zmap_blocks; - u_int16_t s_firstdatazone; - u_int16_t s_log_zone_size; - u_int32_t s_max_size; - u_int16_t s_magic; - u_int16_t s_state; - u_int32_t s_zones; -}; - -struct minix_dir_entry { - u_int16_t inode; - char name[0]; -}; - -#define BLOCK_SIZE_BITS 10 -#define BLOCK_SIZE (1<> 3] & (1<<(i & 7))) != 0; -} -#define inode_in_use(x) (bit(inode_map,(x))) -#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1)) - -#define mark_inode(x) (setbit(inode_map,(x)),changed=1) -#define unmark_inode(x) (clrbit(inode_map,(x)),changed=1) - -#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1),changed=1) -#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1),changed=1) - -static void leave(int) __attribute__ ((noreturn)); -static void leave(int status) -{ - if (termios_set) - tcsetattr(0, TCSANOW, &termios); - exit(status); -} - -static void die(const char *str) -{ - error_msg("%s", str); - leave(8); -} - -/* - * This simply goes through the file-name data and prints out the - * current file. - */ -static void print_current_name(void) -{ - int i = 0; - - while (i < name_depth) - printf("/%.*s", namelen, name_list[i++]); - if (i == 0) - printf("/"); -} - -static int ask(const char *string, int def) -{ - int c; - - if (!repair) { - printf("\n"); - errors_uncorrected = 1; - return 0; - } - if (automatic) { - printf("\n"); - if (!def) - errors_uncorrected = 1; - return def; - } - printf(def ? "%s (y/n)? " : "%s (n/y)? ", string); - for (;;) { - fflush(stdout); - if ((c = getchar()) == EOF) { - if (!def) - errors_uncorrected = 1; - return def; - } - c = toupper(c); - if (c == 'Y') { - def = 1; - break; - } else if (c == 'N') { - def = 0; - break; - } else if (c == ' ' || c == '\n') - break; - } - if (def) - printf("y\n"); - else { - printf("n\n"); - errors_uncorrected = 1; - } - return def; -} - -/* - * Make certain that we aren't checking a filesystem that is on a - * mounted partition. Code adapted from e2fsck, Copyright (C) 1993, - * 1994 Theodore Ts'o. Also licensed under GPL. - */ -static void check_mount(void) -{ - FILE *f; - struct mntent *mnt; - int cont; - int fd; - - if ((f = setmntent(MOUNTED, "r")) == NULL) - return; - while ((mnt = getmntent(f)) != NULL) - if (strcmp(device_name, mnt->mnt_fsname) == 0) - break; - endmntent(f); - if (!mnt) - return; - - /* - * If the root is mounted read-only, then /etc/mtab is - * probably not correct; so we won't issue a warning based on - * it. - */ - fd = open(MOUNTED, O_RDWR); - if (fd < 0 && errno == EROFS) - return; - else - close(fd); - - printf("%s is mounted. ", device_name); - if (isatty(0) && isatty(1)) - cont = ask("Do you really want to continue", 0); - else - cont = 0; - if (!cont) { - printf("check aborted.\n"); - exit(0); - } - return; -} - -/* - * check_zone_nr checks to see that *nr is a valid zone nr. If it - * isn't, it will possibly be repaired. Check_zone_nr sets *corrected - * if an error was corrected, and returns the zone (0 for no zone - * or a bad zone-number). - */ -static int check_zone_nr(unsigned short *nr, int *corrected) -{ - if (!*nr) - return 0; - if (*nr < FIRSTZONE) - printf("Zone nr < FIRSTZONE in file `"); - else if (*nr >= ZONES) - printf("Zone nr >= ZONES in file `"); - else - return *nr; - print_current_name(); - printf("'."); - if (ask("Remove block", 1)) { - *nr = 0; - *corrected = 1; - } - return 0; -} - -#ifdef BB_FEATURE_MINIX2 -static int check_zone_nr2(unsigned int *nr, int *corrected) -{ - if (!*nr) - return 0; - if (*nr < FIRSTZONE) - printf("Zone nr < FIRSTZONE in file `"); - else if (*nr >= ZONES) - printf("Zone nr >= ZONES in file `"); - else - return *nr; - print_current_name(); - printf("'."); - if (ask("Remove block", 1)) { - *nr = 0; - *corrected = 1; - } - return 0; -} -#endif - -/* - * read-block reads block nr into the buffer at addr. - */ -static void read_block(unsigned int nr, char *addr) -{ - if (!nr) { - memset(addr, 0, BLOCK_SIZE); - return; - } - if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) { - printf("Read error: unable to seek to block in file '"); - print_current_name(); - printf("'\n"); - memset(addr, 0, BLOCK_SIZE); - errors_uncorrected = 1; - } else if (BLOCK_SIZE != read(IN, addr, BLOCK_SIZE)) { - printf("Read error: bad block in file '"); - print_current_name(); - printf("'\n"); - memset(addr, 0, BLOCK_SIZE); - errors_uncorrected = 1; - } -} - -/* - * write_block writes block nr to disk. - */ -static void write_block(unsigned int nr, char *addr) -{ - if (!nr) - return; - if (nr < FIRSTZONE || nr >= ZONES) { - printf("Internal error: trying to write bad block\n" - "Write request ignored\n"); - errors_uncorrected = 1; - return; - } - if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) - die("seek failed in write_block"); - if (BLOCK_SIZE != write(IN, addr, BLOCK_SIZE)) { - printf("Write error: bad block in file '"); - print_current_name(); - printf("'\n"); - errors_uncorrected = 1; - } -} - -/* - * map-block calculates the absolute block nr of a block in a file. - * It sets 'changed' if the inode has needed changing, and re-writes - * any indirect blocks with errors. - */ -static int map_block(struct minix_inode *inode, unsigned int blknr) -{ - unsigned short ind[BLOCK_SIZE >> 1]; - unsigned short dind[BLOCK_SIZE >> 1]; - int blk_chg, block, result; - - if (blknr < 7) - return check_zone_nr(inode->i_zone + blknr, &changed); - blknr -= 7; - if (blknr < 512) { - block = check_zone_nr(inode->i_zone + 7, &changed); - read_block(block, (char *) ind); - blk_chg = 0; - result = check_zone_nr(blknr + ind, &blk_chg); - if (blk_chg) - write_block(block, (char *) ind); - return result; - } - blknr -= 512; - block = check_zone_nr(inode->i_zone + 8, &changed); - read_block(block, (char *) dind); - blk_chg = 0; - result = check_zone_nr(dind + (blknr / 512), &blk_chg); - if (blk_chg) - write_block(block, (char *) dind); - block = result; - read_block(block, (char *) ind); - blk_chg = 0; - result = check_zone_nr(ind + (blknr % 512), &blk_chg); - if (blk_chg) - write_block(block, (char *) ind); - return result; -} - -#ifdef BB_FEATURE_MINIX2 -static int map_block2(struct minix2_inode *inode, unsigned int blknr) -{ - unsigned int ind[BLOCK_SIZE >> 2]; - unsigned int dind[BLOCK_SIZE >> 2]; - unsigned int tind[BLOCK_SIZE >> 2]; - int blk_chg, block, result; - - if (blknr < 7) - return check_zone_nr2(inode->i_zone + blknr, &changed); - blknr -= 7; - if (blknr < 256) { - block = check_zone_nr2(inode->i_zone + 7, &changed); - read_block(block, (char *) ind); - blk_chg = 0; - result = check_zone_nr2(blknr + ind, &blk_chg); - if (blk_chg) - write_block(block, (char *) ind); - return result; - } - blknr -= 256; - if (blknr >= 256 * 256) { - block = check_zone_nr2(inode->i_zone + 8, &changed); - read_block(block, (char *) dind); - blk_chg = 0; - result = check_zone_nr2(dind + blknr / 256, &blk_chg); - if (blk_chg) - write_block(block, (char *) dind); - block = result; - read_block(block, (char *) ind); - blk_chg = 0; - result = check_zone_nr2(ind + blknr % 256, &blk_chg); - if (blk_chg) - write_block(block, (char *) ind); - return result; - } - blknr -= 256 * 256; - block = check_zone_nr2(inode->i_zone + 9, &changed); - read_block(block, (char *) tind); - blk_chg = 0; - result = check_zone_nr2(tind + blknr / (256 * 256), &blk_chg); - if (blk_chg) - write_block(block, (char *) tind); - block = result; - read_block(block, (char *) dind); - blk_chg = 0; - result = check_zone_nr2(dind + (blknr / 256) % 256, &blk_chg); - if (blk_chg) - write_block(block, (char *) dind); - block = result; - read_block(block, (char *) ind); - blk_chg = 0; - result = check_zone_nr2(ind + blknr % 256, &blk_chg); - if (blk_chg) - write_block(block, (char *) ind); - return result; -} -#endif - -static void write_super_block(void) -{ - /* - * Set the state of the filesystem based on whether or not there - * are uncorrected errors. The filesystem valid flag is - * unconditionally set if we get this far. - */ - Super.s_state |= MINIX_VALID_FS; - if (errors_uncorrected) - Super.s_state |= MINIX_ERROR_FS; - else - Super.s_state &= ~MINIX_ERROR_FS; - - if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET)) - die("seek failed in write_super_block"); - if (BLOCK_SIZE != write(IN, super_block_buffer, BLOCK_SIZE)) - die("unable to write super-block"); - - return; -} - -static void write_tables(void) -{ - write_super_block(); - - if (IMAPS * BLOCK_SIZE != write(IN, inode_map, IMAPS * BLOCK_SIZE)) - die("Unable to write inode map"); - if (ZMAPS * BLOCK_SIZE != write(IN, zone_map, ZMAPS * BLOCK_SIZE)) - die("Unable to write zone map"); - if (INODE_BUFFER_SIZE != write(IN, inode_buffer, INODE_BUFFER_SIZE)) - die("Unable to write inodes"); -} - -static void get_dirsize(void) -{ - int block; - char blk[BLOCK_SIZE]; - int size; - -#ifdef BB_FEATURE_MINIX2 - if (version2) - block = Inode2[ROOT_INO].i_zone[0]; - else -#endif - block = Inode[ROOT_INO].i_zone[0]; - read_block(block, blk); - for (size = 16; size < BLOCK_SIZE; size <<= 1) { - if (strcmp(blk + size + 2, "..") == 0) { - dirsize = size; - namelen = size - 2; - return; - } - } - /* use defaults */ -} - -static void read_superblock(void) -{ - if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET)) - die("seek failed"); - if (BLOCK_SIZE != read(IN, super_block_buffer, BLOCK_SIZE)) - die("unable to read super block"); - if (MAGIC == MINIX_SUPER_MAGIC) { - namelen = 14; - dirsize = 16; - version2 = 0; - } else if (MAGIC == MINIX_SUPER_MAGIC2) { - namelen = 30; - dirsize = 32; - version2 = 0; -#ifdef BB_FEATURE_MINIX2 - } else if (MAGIC == MINIX2_SUPER_MAGIC) { - namelen = 14; - dirsize = 16; - version2 = 1; - } else if (MAGIC == MINIX2_SUPER_MAGIC2) { - namelen = 30; - dirsize = 32; - version2 = 1; -#endif - } else - die("bad magic number in super-block"); - if (ZONESIZE != 0 || BLOCK_SIZE != 1024) - die("Only 1k blocks/zones supported"); - if (IMAPS * BLOCK_SIZE * 8 < INODES + 1) - die("bad s_imap_blocks field in super-block"); - if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1) - die("bad s_zmap_blocks field in super-block"); -} - -static void read_tables(void) -{ - inode_map = xmalloc(IMAPS * BLOCK_SIZE); - zone_map = xmalloc(ZMAPS * BLOCK_SIZE); - memset(inode_map, 0, sizeof(inode_map)); - memset(zone_map, 0, sizeof(zone_map)); - inode_buffer = xmalloc(INODE_BUFFER_SIZE); - inode_count = xmalloc(INODES + 1); - zone_count = xmalloc(ZONES); - if (IMAPS * BLOCK_SIZE != read(IN, inode_map, IMAPS * BLOCK_SIZE)) - die("Unable to read inode map"); - if (ZMAPS * BLOCK_SIZE != read(IN, zone_map, ZMAPS * BLOCK_SIZE)) - die("Unable to read zone map"); - if (INODE_BUFFER_SIZE != read(IN, inode_buffer, INODE_BUFFER_SIZE)) - die("Unable to read inodes"); - if (NORM_FIRSTZONE != FIRSTZONE) { - printf("Warning: Firstzone != Norm_firstzone\n"); - errors_uncorrected = 1; - } - get_dirsize(); - if (show) { - printf("%ld inodes\n", INODES); - printf("%ld blocks\n", ZONES); - printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE); - printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE); - printf("Maxsize=%ld\n", MAXSIZE); - printf("Filesystem state=%d\n", Super.s_state); - printf("namelen=%d\n\n", namelen); - } -} - -static struct minix_inode *get_inode(unsigned int nr) -{ - struct minix_inode *inode; - - if (!nr || nr > INODES) - return NULL; - total++; - inode = Inode + nr; - if (!inode_count[nr]) { - if (!inode_in_use(nr)) { - printf("Inode %d marked not used, but used for file '", nr); - print_current_name(); - printf("'\n"); - if (repair) { - if (ask("Mark in use", 1)) - mark_inode(nr); - } else { - errors_uncorrected = 1; - } - } - if (S_ISDIR(inode->i_mode)) - directory++; - else if (S_ISREG(inode->i_mode)) - regular++; - else if (S_ISCHR(inode->i_mode)) - chardev++; - else if (S_ISBLK(inode->i_mode)) - blockdev++; - else if (S_ISLNK(inode->i_mode)) - symlinks++; - else if (S_ISSOCK(inode->i_mode)); - else if (S_ISFIFO(inode->i_mode)); - else { - print_current_name(); - printf(" has mode %05o\n", inode->i_mode); - } - - } else - links++; - if (!++inode_count[nr]) { - printf("Warning: inode count too big.\n"); - inode_count[nr]--; - errors_uncorrected = 1; - } - return inode; -} - -#ifdef BB_FEATURE_MINIX2 -static struct minix2_inode *get_inode2(unsigned int nr) -{ - struct minix2_inode *inode; - - if (!nr || nr > INODES) - return NULL; - total++; - inode = Inode2 + nr; - if (!inode_count[nr]) { - if (!inode_in_use(nr)) { - printf("Inode %d marked not used, but used for file '", nr); - print_current_name(); - printf("'\n"); - if (repair) { - if (ask("Mark in use", 1)) - mark_inode(nr); - else - errors_uncorrected = 1; - } - } - if (S_ISDIR(inode->i_mode)) - directory++; - else if (S_ISREG(inode->i_mode)) - regular++; - else if (S_ISCHR(inode->i_mode)) - chardev++; - else if (S_ISBLK(inode->i_mode)) - blockdev++; - else if (S_ISLNK(inode->i_mode)) - symlinks++; - else if (S_ISSOCK(inode->i_mode)); - else if (S_ISFIFO(inode->i_mode)); - else { - print_current_name(); - printf(" has mode %05o\n", inode->i_mode); - } - } else - links++; - if (!++inode_count[nr]) { - printf("Warning: inode count too big.\n"); - inode_count[nr]--; - errors_uncorrected = 1; - } - return inode; -} -#endif - -static void check_root(void) -{ - struct minix_inode *inode = Inode + ROOT_INO; - - if (!inode || !S_ISDIR(inode->i_mode)) - die("root inode isn't a directory"); -} - -#ifdef BB_FEATURE_MINIX2 -static void check_root2(void) -{ - struct minix2_inode *inode = Inode2 + ROOT_INO; - - if (!inode || !S_ISDIR(inode->i_mode)) - die("root inode isn't a directory"); -} -#endif - -static int add_zone(unsigned short *znr, int *corrected) -{ - int result; - int block; - - result = 0; - block = check_zone_nr(znr, corrected); - if (!block) - return 0; - if (zone_count[block]) { - printf("Block has been used before. Now in file `"); - print_current_name(); - printf("'."); - if (ask("Clear", 1)) { - *znr = 0; - block = 0; - *corrected = 1; - } - } - if (!block) - return 0; - if (!zone_in_use(block)) { - printf("Block %d in file `", block); - print_current_name(); - printf("' is marked not in use."); - if (ask("Correct", 1)) - mark_zone(block); - } - if (!++zone_count[block]) - zone_count[block]--; - return block; -} - -#ifdef BB_FEATURE_MINIX2 -static int add_zone2(unsigned int *znr, int *corrected) -{ - int result; - int block; - - result = 0; - block = check_zone_nr2(znr, corrected); - if (!block) - return 0; - if (zone_count[block]) { - printf("Block has been used before. Now in file `"); - print_current_name(); - printf("'."); - if (ask("Clear", 1)) { - *znr = 0; - block = 0; - *corrected = 1; - } - } - if (!block) - return 0; - if (!zone_in_use(block)) { - printf("Block %d in file `", block); - print_current_name(); - printf("' is marked not in use."); - if (ask("Correct", 1)) - mark_zone(block); - } - if (!++zone_count[block]) - zone_count[block]--; - return block; -} -#endif - -static void add_zone_ind(unsigned short *znr, int *corrected) -{ - static char blk[BLOCK_SIZE]; - int i, chg_blk = 0; - int block; - - block = add_zone(znr, corrected); - if (!block) - return; - read_block(block, blk); - for (i = 0; i < (BLOCK_SIZE >> 1); i++) - add_zone(i + (unsigned short *) blk, &chg_blk); - if (chg_blk) - write_block(block, blk); -} - -#ifdef BB_FEATURE_MINIX2 -static void add_zone_ind2(unsigned int *znr, int *corrected) -{ - static char blk[BLOCK_SIZE]; - int i, chg_blk = 0; - int block; - - block = add_zone2(znr, corrected); - if (!block) - return; - read_block(block, blk); - for (i = 0; i < BLOCK_SIZE >> 2; i++) - add_zone2(i + (unsigned int *) blk, &chg_blk); - if (chg_blk) - write_block(block, blk); -} -#endif - -static void add_zone_dind(unsigned short *znr, int *corrected) -{ - static char blk[BLOCK_SIZE]; - int i, blk_chg = 0; - int block; - - block = add_zone(znr, corrected); - if (!block) - return; - read_block(block, blk); - for (i = 0; i < (BLOCK_SIZE >> 1); i++) - add_zone_ind(i + (unsigned short *) blk, &blk_chg); - if (blk_chg) - write_block(block, blk); -} - -#ifdef BB_FEATURE_MINIX2 -static void add_zone_dind2(unsigned int *znr, int *corrected) -{ - static char blk[BLOCK_SIZE]; - int i, blk_chg = 0; - int block; - - block = add_zone2(znr, corrected); - if (!block) - return; - read_block(block, blk); - for (i = 0; i < BLOCK_SIZE >> 2; i++) - add_zone_ind2(i + (unsigned int *) blk, &blk_chg); - if (blk_chg) - write_block(block, blk); -} - -static void add_zone_tind2(unsigned int *znr, int *corrected) -{ - static char blk[BLOCK_SIZE]; - int i, blk_chg = 0; - int block; - - block = add_zone2(znr, corrected); - if (!block) - return; - read_block(block, blk); - for (i = 0; i < BLOCK_SIZE >> 2; i++) - add_zone_dind2(i + (unsigned int *) blk, &blk_chg); - if (blk_chg) - write_block(block, blk); -} -#endif - -static void check_zones(unsigned int i) -{ - struct minix_inode *inode; - - if (!i || i > INODES) - return; - if (inode_count[i] > 1) /* have we counted this file already? */ - return; - inode = Inode + i; - if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) && - !S_ISLNK(inode->i_mode)) return; - for (i = 0; i < 7; i++) - add_zone(i + inode->i_zone, &changed); - add_zone_ind(7 + inode->i_zone, &changed); - add_zone_dind(8 + inode->i_zone, &changed); -} - -#ifdef BB_FEATURE_MINIX2 -static void check_zones2(unsigned int i) -{ - struct minix2_inode *inode; - - if (!i || i > INODES) - return; - if (inode_count[i] > 1) /* have we counted this file already? */ - return; - inode = Inode2 + i; - if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) - && !S_ISLNK(inode->i_mode)) - return; - for (i = 0; i < 7; i++) - add_zone2(i + inode->i_zone, &changed); - add_zone_ind2(7 + inode->i_zone, &changed); - add_zone_dind2(8 + inode->i_zone, &changed); - add_zone_tind2(9 + inode->i_zone, &changed); -} -#endif - -static void check_file(struct minix_inode *dir, unsigned int offset) -{ - static char blk[BLOCK_SIZE]; - struct minix_inode *inode; - int ino; - char *name; - int block; - - block = map_block(dir, offset / BLOCK_SIZE); - read_block(block, blk); - name = blk + (offset % BLOCK_SIZE) + 2; - ino = *(unsigned short *) (name - 2); - if (ino > INODES) { - print_current_name(); - printf(" contains a bad inode number for file '"); - printf("%.*s'.", namelen, name); - if (ask(" Remove", 1)) { - *(unsigned short *) (name - 2) = 0; - write_block(block, blk); - } - ino = 0; - } - if (name_depth < MAX_DEPTH) - strncpy(name_list[name_depth], name, namelen); - name_depth++; - inode = get_inode(ino); - name_depth--; - if (!offset) { - if (!inode || strcmp(".", name)) { - print_current_name(); - printf(": bad directory: '.' isn't first\n"); - errors_uncorrected = 1; - } else - return; - } - if (offset == dirsize) { - if (!inode || strcmp("..", name)) { - print_current_name(); - printf(": bad directory: '..' isn't second\n"); - errors_uncorrected = 1; - } else - return; - } - if (!inode) - return; - if (name_depth < MAX_DEPTH) - strncpy(name_list[name_depth], name, namelen); - name_depth++; - if (list) { - if (verbose) - printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks); - print_current_name(); - if (S_ISDIR(inode->i_mode)) - printf(":\n"); - else - printf("\n"); - } - check_zones(ino); - if (inode && S_ISDIR(inode->i_mode)) - recursive_check(ino); - name_depth--; - return; -} - -#ifdef BB_FEATURE_MINIX2 -static void check_file2(struct minix2_inode *dir, unsigned int offset) -{ - static char blk[BLOCK_SIZE]; - struct minix2_inode *inode; - int ino; - char *name; - int block; - - block = map_block2(dir, offset / BLOCK_SIZE); - read_block(block, blk); - name = blk + (offset % BLOCK_SIZE) + 2; - ino = *(unsigned short *) (name - 2); - if (ino > INODES) { - print_current_name(); - printf(" contains a bad inode number for file '"); - printf("%.*s'.", namelen, name); - if (ask(" Remove", 1)) { - *(unsigned short *) (name - 2) = 0; - write_block(block, blk); - } - ino = 0; - } - if (name_depth < MAX_DEPTH) - strncpy(name_list[name_depth], name, namelen); - name_depth++; - inode = get_inode2(ino); - name_depth--; - if (!offset) { - if (!inode || strcmp(".", name)) { - print_current_name(); - printf(": bad directory: '.' isn't first\n"); - errors_uncorrected = 1; - } else - return; - } - if (offset == dirsize) { - if (!inode || strcmp("..", name)) { - print_current_name(); - printf(": bad directory: '..' isn't second\n"); - errors_uncorrected = 1; - } else - return; - } - if (!inode) - return; - name_depth++; - if (list) { - if (verbose) - printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks); - print_current_name(); - if (S_ISDIR(inode->i_mode)) - printf(":\n"); - else - printf("\n"); - } - check_zones2(ino); - if (inode && S_ISDIR(inode->i_mode)) - recursive_check2(ino); - name_depth--; - return; -} -#endif - -static void recursive_check(unsigned int ino) -{ - struct minix_inode *dir; - unsigned int offset; - - dir = Inode + ino; - if (!S_ISDIR(dir->i_mode)) - die("internal error"); - if (dir->i_size < 2 * dirsize) { - print_current_name(); - printf(": bad directory: size<32"); - errors_uncorrected = 1; - } - for (offset = 0; offset < dir->i_size; offset += dirsize) - check_file(dir, offset); -} - -#ifdef BB_FEATURE_MINIX2 -static void recursive_check2(unsigned int ino) -{ - struct minix2_inode *dir; - unsigned int offset; - - dir = Inode2 + ino; - if (!S_ISDIR(dir->i_mode)) - die("internal error"); - if (dir->i_size < 2 * dirsize) { - print_current_name(); - printf(": bad directory: size < 32"); - errors_uncorrected = 1; - } - for (offset = 0; offset < dir->i_size; offset += dirsize) - check_file2(dir, offset); -} -#endif - -static int bad_zone(int i) -{ - char buffer[1024]; - - if (BLOCK_SIZE * i != lseek(IN, BLOCK_SIZE * i, SEEK_SET)) - die("seek failed in bad_zone"); - return (BLOCK_SIZE != read(IN, buffer, BLOCK_SIZE)); -} - -static void check_counts(void) -{ - int i; - - for (i = 1; i <= INODES; i++) { - if (!inode_in_use(i) && Inode[i].i_mode && warn_mode) { - printf("Inode %d mode not cleared.", i); - if (ask("Clear", 1)) { - Inode[i].i_mode = 0; - changed = 1; - } - } - if (!inode_count[i]) { - if (!inode_in_use(i)) - continue; - printf("Inode %d not used, marked used in the bitmap.", i); - if (ask("Clear", 1)) - unmark_inode(i); - continue; - } - if (!inode_in_use(i)) { - printf("Inode %d used, marked unused in the bitmap.", i); - if (ask("Set", 1)) - mark_inode(i); - } - if (Inode[i].i_nlinks != inode_count[i]) { - printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.", - i, Inode[i].i_mode, Inode[i].i_nlinks, inode_count[i]); - if (ask("Set i_nlinks to count", 1)) { - Inode[i].i_nlinks = inode_count[i]; - changed = 1; - } - } - } - for (i = FIRSTZONE; i < ZONES; i++) { - if (zone_in_use(i) == zone_count[i]) - continue; - if (!zone_count[i]) { - if (bad_zone(i)) - continue; - printf("Zone %d: marked in use, no file uses it.", i); - if (ask("Unmark", 1)) - unmark_zone(i); - continue; - } - printf("Zone %d: %sin use, counted=%d\n", - i, zone_in_use(i) ? "" : "not ", zone_count[i]); - } -} - -#ifdef BB_FEATURE_MINIX2 -static void check_counts2(void) -{ - int i; - - for (i = 1; i <= INODES; i++) { - if (!inode_in_use(i) && Inode2[i].i_mode && warn_mode) { - printf("Inode %d mode not cleared.", i); - if (ask("Clear", 1)) { - Inode2[i].i_mode = 0; - changed = 1; - } - } - if (!inode_count[i]) { - if (!inode_in_use(i)) - continue; - printf("Inode %d not used, marked used in the bitmap.", i); - if (ask("Clear", 1)) - unmark_inode(i); - continue; - } - if (!inode_in_use(i)) { - printf("Inode %d used, marked unused in the bitmap.", i); - if (ask("Set", 1)) - mark_inode(i); - } - if (Inode2[i].i_nlinks != inode_count[i]) { - printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.", - i, Inode2[i].i_mode, Inode2[i].i_nlinks, - inode_count[i]); - if (ask("Set i_nlinks to count", 1)) { - Inode2[i].i_nlinks = inode_count[i]; - changed = 1; - } - } - } - for (i = FIRSTZONE; i < ZONES; i++) { - if (zone_in_use(i) == zone_count[i]) - continue; - if (!zone_count[i]) { - if (bad_zone(i)) - continue; - printf("Zone %d: marked in use, no file uses it.", i); - if (ask("Unmark", 1)) - unmark_zone(i); - continue; - } - printf("Zone %d: %sin use, counted=%d\n", - i, zone_in_use(i) ? "" : "not ", zone_count[i]); - } -} -#endif - -static void check(void) -{ - memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count)); - memset(zone_count, 0, ZONES * sizeof(*zone_count)); - check_zones(ROOT_INO); - recursive_check(ROOT_INO); - check_counts(); -} - -#ifdef BB_FEATURE_MINIX2 -static void check2(void) -{ - memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count)); - memset(zone_count, 0, ZONES * sizeof(*zone_count)); - check_zones2(ROOT_INO); - recursive_check2(ROOT_INO); - check_counts2(); -} -#endif - -/* Wed Feb 9 15:17:06 MST 2000 */ -/* dynamically allocate name_list (instead of making it static) */ -static void alloc_name_list(void) -{ - int i; - - name_list = xmalloc(sizeof(char *) * MAX_DEPTH); - for (i = 0; i < MAX_DEPTH; i++) - name_list[i] = xmalloc(sizeof(char) * BUFSIZ + 1); -} - -#ifdef BB_FEATURE_CLEAN_UP -/* execute this atexit() to deallocate name_list[] */ -/* piptigger was here */ -static void free_name_list(void) -{ - int i; - - if (name_list) { - for (i = 0; i < MAX_DEPTH; i++) { - if (name_list[i]) { - free(name_list[i]); - } - } - free(name_list); - } -} -#endif - -extern int fsck_minix_main(int argc, char **argv) -{ - struct termios tmp; - int count; - int retcode = 0; - - alloc_name_list(); -#ifdef BB_FEATURE_CLEAN_UP - /* Don't bother to free memory. Exit does - * that automagically, so we can save a few bytes */ - atexit(free_name_list); -#endif - - if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) - die("bad inode size"); -#ifdef BB_FEATURE_MINIX2 - if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) - die("bad v2 inode size"); -#endif - while (argc-- > 1) { - argv++; - if (argv[0][0] != '-') { - if (device_name) - show_usage(); - else - device_name = argv[0]; - } else - while (*++argv[0]) - switch (argv[0][0]) { - case 'l': - list = 1; - break; - case 'a': - automatic = 1; - repair = 1; - break; - case 'r': - automatic = 0; - repair = 1; - break; - case 'v': - verbose = 1; - break; - case 's': - show = 1; - break; - case 'm': - warn_mode = 1; - break; - case 'f': - force = 1; - break; - default: - show_usage(); - } - } - if (!device_name) - show_usage(); - check_mount(); /* trying to check a mounted filesystem? */ - if (repair && !automatic) { - if (!isatty(0) || !isatty(1)) - die("need terminal for interactive repairs"); - } - IN = open(device_name, repair ? O_RDWR : O_RDONLY); - if (IN < 0){ - fprintf(stderr,"unable to open device '%s'.\n",device_name); - leave(8); - } - for (count = 0; count < 3; count++) - sync(); - read_superblock(); - - /* - * Determine whether or not we should continue with the checking. - * This is based on the status of the filesystem valid and error - * flags and whether or not the -f switch was specified on the - * command line. - */ - printf("%s, %s\n", applet_name, program_version); - if (!(Super.s_state & MINIX_ERROR_FS) && - (Super.s_state & MINIX_VALID_FS) && !force) { - if (repair) - printf("%s is clean, no check.\n", device_name); - return retcode; - } else if (force) - printf("Forcing filesystem check on %s.\n", device_name); - else if (repair) - printf("Filesystem on %s is dirty, needs checking.\n", - device_name); - - read_tables(); - - if (repair && !automatic) { - tcgetattr(0, &termios); - tmp = termios; - tmp.c_lflag &= ~(ICANON | ECHO); - tcsetattr(0, TCSANOW, &tmp); - termios_set = 1; - } -#ifdef BB_FEATURE_MINIX2 - if (version2) { - check_root2(); - check2(); - } else -#endif - { - check_root(); - check(); - } - if (verbose) { - int i, free_cnt; - - for (i = 1, free_cnt = 0; i <= INODES; i++) - if (!inode_in_use(i)) - free_cnt++; - printf("\n%6ld inodes used (%ld%%)\n", (INODES - free_cnt), - 100 * (INODES - free_cnt) / INODES); - for (i = FIRSTZONE, free_cnt = 0; i < ZONES; i++) - if (!zone_in_use(i)) - free_cnt++; - printf("%6ld zones used (%ld%%)\n", (ZONES - free_cnt), - 100 * (ZONES - free_cnt) / ZONES); - printf("\n%6d regular files\n" - "%6d directories\n" - "%6d character device files\n" - "%6d block device files\n" - "%6d links\n" - "%6d symbolic links\n" - "------\n" - "%6d files\n", - regular, directory, chardev, blockdev, - links - 2 * directory + 1, symlinks, - total - 2 * directory + 1); - } - if (changed) { - write_tables(); - printf("----------------------------\n" - "FILE SYSTEM HAS BEEN CHANGED\n" - "----------------------------\n"); - for (count = 0; count < 3; count++) - sync(); - } else if (repair) - write_super_block(); - - if (repair && !automatic) - tcsetattr(0, TCSANOW, &termios); - - if (changed) - retcode += 3; - if (errors_uncorrected) - retcode += 4; - return retcode; -} diff --git a/busybox/util-linux/getopt.c b/busybox/util-linux/getopt.c deleted file mode 100644 index 95ecba6e6..000000000 --- a/busybox/util-linux/getopt.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * getopt.c - Enhanced implementation of BSD getopt(1) - * Copyright (c) 1997, 1998, 1999, 2000 Frodo Looijaard - * - * 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. - */ - -/* - * Version 1.0-b4: Tue Sep 23 1997. First public release. - * Version 1.0: Wed Nov 19 1997. - * Bumped up the version number to 1.0 - * Fixed minor typo (CSH instead of TCSH) - * Version 1.0.1: Tue Jun 3 1998 - * Fixed sizeof instead of strlen bug - * Bumped up the version number to 1.0.1 - * Version 1.0.2: Thu Jun 11 1998 (not present) - * Fixed gcc-2.8.1 warnings - * Fixed --version/-V option (not present) - * Version 1.0.5: Tue Jun 22 1999 - * Make -u option work (not present) - * Version 1.0.6: Tue Jun 27 2000 - * No important changes - * Version 1.1.0: Tue Jun 30 2000 - * Added NLS support (partly written by Arkadiusz Mikiewicz - * ) - * Ported to Busybox - Alfred M. Szmidt - * Removed --version/-V and --help/-h in - * Removed prase_error(), using error_msg() from Busybox instead - * Replaced our_malloc with xmalloc and our_realloc with xrealloc - * - */ - -#include -#include -#include -#include -#include -#include - -#include "busybox.h" - -/* NON_OPT is the code that is returned when a non-option is found in '+' - mode */ -static const int NON_OPT = 1; -/* LONG_OPT is the code that is returned when a long option is found. */ -static const int LONG_OPT = 2; - -/* The shells recognized. */ -typedef enum {BASH,TCSH} shell_t; - - -/* Some global variables that tells us how to parse. */ -static shell_t shell=BASH; /* The shell we generate output for. */ -static int quiet_errors=0; /* 0 is not quiet. */ -static int quiet_output=0; /* 0 is not quiet. */ -static int quote=1; /* 1 is do quote. */ -static int alternative=0; /* 0 is getopt_long, 1 is getopt_long_only */ - -/* Function prototypes */ -static const char *normalize(const char *arg); -static int generate_output(char * argv[],int argc,const char *optstr, - const struct option *longopts); -static void add_long_options(char *options); -static void add_longopt(const char *name,int has_arg); -static void set_shell(const char *new_shell); - - -/* - * This function 'normalizes' a single argument: it puts single quotes around - * it and escapes other special characters. If quote is false, it just - * returns its argument. - * Bash only needs special treatment for single quotes; tcsh also recognizes - * exclamation marks within single quotes, and nukes whitespace. - * This function returns a pointer to a buffer that is overwritten by - * each call. - */ -const char *normalize(const char *arg) -{ - static char *BUFFER=NULL; - const char *argptr=arg; - char *bufptr; - - if (BUFFER != NULL) - free(BUFFER); - - if (!quote) { /* Just copy arg */ - BUFFER=xmalloc(strlen(arg)+1); - - strcpy(BUFFER,arg); - return BUFFER; - } - - /* Each character in arg may take upto four characters in the result: - For a quote we need a closing quote, a backslash, a quote and an - opening quote! We need also the global opening and closing quote, - and one extra character for '\0'. */ - BUFFER=xmalloc(strlen(arg)*4+3); - - bufptr=BUFFER; - *bufptr++='\''; - - while (*argptr) { - if (*argptr == '\'') { - /* Quote: replace it with: '\'' */ - *bufptr++='\''; - *bufptr++='\\'; - *bufptr++='\''; - *bufptr++='\''; - } else if (shell==TCSH && *argptr=='!') { - /* Exclamation mark: replace it with: \! */ - *bufptr++='\''; - *bufptr++='\\'; - *bufptr++='!'; - *bufptr++='\''; - } else if (shell==TCSH && *argptr=='\n') { - /* Newline: replace it with: \n */ - *bufptr++='\\'; - *bufptr++='n'; - } else if (shell==TCSH && isspace(*argptr)) { - /* Non-newline whitespace: replace it with \ */ - *bufptr++='\''; - *bufptr++='\\'; - *bufptr++=*argptr; - *bufptr++='\''; - } else - /* Just copy */ - *bufptr++=*argptr; - argptr++; - } - *bufptr++='\''; - *bufptr++='\0'; - return BUFFER; -} - -/* - * Generate the output. argv[0] is the program name (used for reporting errors). - * argv[1..] contains the options to be parsed. argc must be the number of - * elements in argv (ie. 1 if there are no options, only the program name), - * optstr must contain the short options, and longopts the long options. - * Other settings are found in global variables. - */ -int generate_output(char * argv[],int argc,const char *optstr, - const struct option *longopts) -{ - int exit_code = 0; /* We assume everything will be OK */ - int opt; - int longindex; - const char *charptr; - - if (quiet_errors) /* No error reporting from getopt(3) */ - opterr=0; - optind=0; /* Reset getopt(3) */ - - while ((opt = (alternative? - getopt_long_only(argc,argv,optstr,longopts,&longindex): - getopt_long(argc,argv,optstr,longopts,&longindex))) - != EOF) - if (opt == '?' || opt == ':' ) - exit_code = 1; - else if (!quiet_output) { - if (opt == LONG_OPT) { - printf(" --%s",longopts[longindex].name); - if (longopts[longindex].has_arg) - printf(" %s", - normalize(optarg?optarg:"")); - } else if (opt == NON_OPT) - printf(" %s",normalize(optarg)); - else { - printf(" -%c",opt); - charptr = strchr(optstr,opt); - if (charptr != NULL && *++charptr == ':') - printf(" %s", - normalize(optarg?optarg:"")); - } - } - - if (! quiet_output) { - printf(" --"); - while (optind < argc) - printf(" %s",normalize(argv[optind++])); - printf("\n"); - } - return exit_code; -} - -static struct option *long_options=NULL; -static int long_options_length=0; /* Length of array */ -static int long_options_nr=0; /* Nr of used elements in array */ -static const int LONG_OPTIONS_INCR = 10; -#define init_longopt() add_longopt(NULL,0) - -/* Register a long option. The contents of name is copied. */ -void add_longopt(const char *name,int has_arg) -{ - char *tmp; - if (!name) { /* init */ - free(long_options); - long_options=NULL; - long_options_length=0; - long_options_nr=0; - } - - if (long_options_nr == long_options_length) { - long_options_length += LONG_OPTIONS_INCR; - long_options=xrealloc(long_options, - sizeof(struct option) * - long_options_length); - } - - long_options[long_options_nr].name=NULL; - long_options[long_options_nr].has_arg=0; - long_options[long_options_nr].flag=NULL; - long_options[long_options_nr].val=0; - - if (long_options_nr) { /* Not for init! */ - long_options[long_options_nr-1].has_arg=has_arg; - long_options[long_options_nr-1].flag=NULL; - long_options[long_options_nr-1].val=LONG_OPT; - tmp = xmalloc(strlen(name)+1); - strcpy(tmp,name); - long_options[long_options_nr-1].name=tmp; - } - long_options_nr++; -} - - -/* - * Register several long options. options is a string of long options, - * separated by commas or whitespace. - * This nukes options! - */ -void add_long_options(char *options) -{ - int arg_opt, tlen; - char *tokptr=strtok(options,", \t\n"); - while (tokptr) { - arg_opt=no_argument; - tlen=strlen(tokptr); - if (tlen > 0) { - if (tokptr[tlen-1] == ':') { - if (tlen > 1 && tokptr[tlen-2] == ':') { - tokptr[tlen-2]='\0'; - tlen -= 2; - arg_opt=optional_argument; - } else { - tokptr[tlen-1]='\0'; - tlen -= 1; - arg_opt=required_argument; - } - if (tlen == 0) - error_msg("empty long option after -l or --long argument"); - } - add_longopt(tokptr,arg_opt); - } - tokptr=strtok(NULL,", \t\n"); - } -} - -void set_shell(const char *new_shell) -{ - if (!strcmp(new_shell,"bash")) - shell=BASH; - else if (!strcmp(new_shell,"tcsh")) - shell=TCSH; - else if (!strcmp(new_shell,"sh")) - shell=BASH; - else if (!strcmp(new_shell,"csh")) - shell=TCSH; - else - error_msg("unknown shell after -s or --shell argument"); -} - - -/* Exit codes: - * 0) No errors, succesful operation. - * 1) getopt(3) returned an error. - * 2) A problem with parameter parsing for getopt(1). - * 3) Internal error, out of memory - * 4) Returned for -T - */ - -static struct option longopts[]= -{ - {"options",required_argument,NULL,'o'}, - {"longoptions",required_argument,NULL,'l'}, - {"quiet",no_argument,NULL,'q'}, - {"quiet-output",no_argument,NULL,'Q'}, - {"shell",required_argument,NULL,'s'}, - {"test",no_argument,NULL,'T'}, - {"unquoted",no_argument,NULL,'u'}, - {"alternative",no_argument,NULL,'a'}, - {"name",required_argument,NULL,'n'}, - {NULL,0,NULL,0} -}; - -/* Stop scanning as soon as a non-option argument is found! */ -static const char *shortopts="+ao:l:n:qQs:Tu"; - - -int getopt_main(int argc, char *argv[]) -{ - char *optstr=NULL; - char *name=NULL; - int opt; - int compatible=0; - - init_longopt(); - - if (getenv("GETOPT_COMPATIBLE")) - compatible=1; - - if (argc == 1) { - if (compatible) { - /* For some reason, the original getopt gave no error - when there were no arguments. */ - printf(" --\n"); - exit(0); - } else - error_msg_and_die("missing optstring argument"); - } - - if (argv[1][0] != '-' || compatible) { - quote=0; - optstr=xmalloc(strlen(argv[1])+1); - strcpy(optstr,argv[1]+strspn(argv[1],"-+")); - argv[1]=argv[0]; - exit(generate_output(argv+1,argc-1,optstr,long_options)); - } - - while ((opt=getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF) - switch (opt) { - case 'a': - alternative=1; - break; - case 'o': - if (optstr) - free(optstr); - optstr=xmalloc(strlen(optarg)+1); - strcpy(optstr,optarg); - break; - case 'l': - add_long_options(optarg); - break; - case 'n': - if (name) - free(name); - name=xmalloc(strlen(optarg)+1); - strcpy(name,optarg); - break; - case 'q': - quiet_errors=1; - break; - case 'Q': - quiet_output=1; - break; - case 's': - set_shell(optarg); - break; - case 'T': - exit(4); - case 'u': - quote=0; - break; - default: - show_usage(); - } - - if (!optstr) { - if (optind >= argc) - error_msg_and_die("missing optstring argument"); - else { - optstr=xmalloc(strlen(argv[optind])+1); - strcpy(optstr,argv[optind]); - optind++; - } - } - if (name) - argv[optind-1]=name; - else - argv[optind-1]=argv[0]; - exit(generate_output(argv+optind-1,argc-optind+1,optstr,long_options)); -} - -/* - Local Variables: - c-file-style: "linux" - c-basic-offset: 4 - tab-width: 4 - End: -*/ diff --git a/busybox/util-linux/mkfs_minix.c b/busybox/util-linux/mkfs_minix.c deleted file mode 100644 index ccc0e85d7..000000000 --- a/busybox/util-linux/mkfs_minix.c +++ /dev/null @@ -1,847 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * mkfs.c - make a linux (minix) file-system. - * - * (C) 1991 Linus Torvalds. This file may be redistributed as per - * the Linux copyright. - */ - -/* - * DD.MM.YY - * - * 24.11.91 - Time began. Used the fsck sources to get started. - * - * 25.11.91 - Corrected some bugs. Added support for ".badblocks" - * The algorithm for ".badblocks" is a bit weird, but - * it should work. Oh, well. - * - * 25.01.92 - Added the -l option for getting the list of bad blocks - * out of a named file. (Dave Rivers, rivers@ponds.uucp) - * - * 28.02.92 - Added %-information when using -c. - * - * 28.02.93 - Added support for other namelengths than the original - * 14 characters so that I can test the new kernel routines.. - * - * 09.10.93 - Make exit status conform to that required by fsutil - * (Rik Faith, faith@cs.unc.edu) - * - * 31.10.93 - Added inode request feature, for backup floppies: use - * 32 inodes, for a news partition use more. - * (Scott Heavner, sdh@po.cwru.edu) - * - * 03.01.94 - Added support for file system valid flag. - * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu) - * - * 30.10.94 - added support for v2 filesystem - * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de) - * - * 09.11.94 - Added test to prevent overwrite of mounted fs adapted - * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs - * program. (Daniel Quinlan, quinlan@yggdrasil.com) - * - * 03.20.95 - Clear first 512 bytes of filesystem to make certain that - * the filesystem is not misidentified as a MS-DOS FAT filesystem. - * (Daniel Quinlan, quinlan@yggdrasil.com) - * - * 02.07.96 - Added small patch from Russell King to make the program a - * good deal more portable (janl@math.uio.no) - * - * Usage: mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks] - * - * -c for readablility checking (SLOW!) - * -l for getting a list of bad blocks from a file. - * -n for namelength (currently the kernel only uses 14 or 30) - * -i for number of inodes - * -v for v2 filesystem - * - * The device may be a block device or a image of one, but this isn't - * enforced (but it's not much fun on a character device :-). - * - * Modified for BusyBox by Erik Andersen -- - * removed getopt based parser and added a hand rolled one. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -#define MINIX_ROOT_INO 1 -#define MINIX_LINK_MAX 250 -#define MINIX2_LINK_MAX 65530 - -#define MINIX_I_MAP_SLOTS 8 -#define MINIX_Z_MAP_SLOTS 64 -#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ -#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ -#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */ -#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */ -#define MINIX_VALID_FS 0x0001 /* Clean fs. */ -#define MINIX_ERROR_FS 0x0002 /* fs has errors. */ - -#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) -#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode))) - -#define MINIX_V1 0x0001 /* original minix fs */ -#define MINIX_V2 0x0002 /* minix V2 fs */ - -#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version - -/* - * This is the original minix inode layout on disk. - * Note the 8-bit gid and atime and ctime. - */ -struct minix_inode { - u_int16_t i_mode; - u_int16_t i_uid; - u_int32_t i_size; - u_int32_t i_time; - u_int8_t i_gid; - u_int8_t i_nlinks; - u_int16_t i_zone[9]; -}; - -/* - * The new minix inode has all the time entries, as well as - * long block numbers and a third indirect block (7+1+1+1 - * instead of 7+1+1). Also, some previously 8-bit values are - * now 16-bit. The inode is now 64 bytes instead of 32. - */ -struct minix2_inode { - u_int16_t i_mode; - u_int16_t i_nlinks; - u_int16_t i_uid; - u_int16_t i_gid; - u_int32_t i_size; - u_int32_t i_atime; - u_int32_t i_mtime; - u_int32_t i_ctime; - u_int32_t i_zone[10]; -}; - -/* - * minix super-block data on disk - */ -struct minix_super_block { - u_int16_t s_ninodes; - u_int16_t s_nzones; - u_int16_t s_imap_blocks; - u_int16_t s_zmap_blocks; - u_int16_t s_firstdatazone; - u_int16_t s_log_zone_size; - u_int32_t s_max_size; - u_int16_t s_magic; - u_int16_t s_state; - u_int32_t s_zones; -}; - -struct minix_dir_entry { - u_int16_t inode; - char name[0]; -}; - -#define BLOCK_SIZE_BITS 10 -#define BLOCK_SIZE (1<> 3] & (1<<(i & 7))) != 0; -} -#define inode_in_use(x) (bit(inode_map,(x))) -#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1)) - -#define mark_inode(x) (setbit(inode_map,(x))) -#define unmark_inode(x) (clrbit(inode_map,(x))) - -#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1)) -#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1)) - -/* - * Check to make certain that our new filesystem won't be created on - * an already mounted partition. Code adapted from mke2fs, Copyright - * (C) 1994 Theodore Ts'o. Also licensed under GPL. - */ -static void check_mount(void) -{ - FILE *f; - struct mntent *mnt; - - if ((f = setmntent(MOUNTED, "r")) == NULL) - return; - while ((mnt = getmntent(f)) != NULL) - if (strcmp(device_name, mnt->mnt_fsname) == 0) - break; - endmntent(f); - if (!mnt) - return; - - error_msg_and_die("%s is mounted; will not make a filesystem here!", device_name); -} - -static long valid_offset(int fd, int offset) -{ - char ch; - - if (lseek(fd, offset, 0) < 0) - return 0; - if (read(fd, &ch, 1) < 1) - return 0; - return 1; -} - -static int count_blocks(int fd) -{ - int high, low; - - low = 0; - for (high = 1; valid_offset(fd, high); high *= 2) - low = high; - while (low < high - 1) { - const int mid = (low + high) / 2; - - if (valid_offset(fd, mid)) - low = mid; - else - high = mid; - } - valid_offset(fd, 0); - return (low + 1); -} - -static int get_size(const char *file) -{ - int fd; - long size; - - if ((fd = open(file, O_RDWR)) < 0) - perror_msg_and_die("%s", file); - if (ioctl(fd, BLKGETSIZE, &size) >= 0) { - close(fd); - return (size * 512); - } - - size = count_blocks(fd); - close(fd); - return size; -} - -static void write_tables(void) -{ - /* Mark the super block valid. */ - Super.s_state |= MINIX_VALID_FS; - Super.s_state &= ~MINIX_ERROR_FS; - - if (lseek(DEV, 0, SEEK_SET)) - error_msg_and_die("seek to boot block failed in write_tables"); - if (512 != write(DEV, boot_block_buffer, 512)) - error_msg_and_die("unable to clear boot sector"); - if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET)) - error_msg_and_die("seek failed in write_tables"); - if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE)) - error_msg_and_die("unable to write super-block"); - if (IMAPS * BLOCK_SIZE != write(DEV, inode_map, IMAPS * BLOCK_SIZE)) - error_msg_and_die("unable to write inode map"); - if (ZMAPS * BLOCK_SIZE != write(DEV, zone_map, ZMAPS * BLOCK_SIZE)) - error_msg_and_die("unable to write zone map"); - if (INODE_BUFFER_SIZE != write(DEV, inode_buffer, INODE_BUFFER_SIZE)) - error_msg_and_die("unable to write inodes"); - -} - -static void write_block(int blk, char *buffer) -{ - if (blk * BLOCK_SIZE != lseek(DEV, blk * BLOCK_SIZE, SEEK_SET)) - error_msg_and_die("seek failed in write_block"); - if (BLOCK_SIZE != write(DEV, buffer, BLOCK_SIZE)) - error_msg_and_die("write failed in write_block"); -} - -static int get_free_block(void) -{ - int blk; - - if (used_good_blocks + 1 >= MAX_GOOD_BLOCKS) - error_msg_and_die("too many bad blocks"); - if (used_good_blocks) - blk = good_blocks_table[used_good_blocks - 1] + 1; - else - blk = FIRSTZONE; - while (blk < ZONES && zone_in_use(blk)) - blk++; - if (blk >= ZONES) - error_msg_and_die("not enough good blocks"); - good_blocks_table[used_good_blocks] = blk; - used_good_blocks++; - return blk; -} - -static void mark_good_blocks(void) -{ - int blk; - - for (blk = 0; blk < used_good_blocks; blk++) - mark_zone(good_blocks_table[blk]); -} - -static int next(int zone) -{ - if (!zone) - zone = FIRSTZONE - 1; - while (++zone < ZONES) - if (zone_in_use(zone)) - return zone; - return 0; -} - -static void make_bad_inode(void) -{ - struct minix_inode *inode = &Inode[MINIX_BAD_INO]; - int i, j, zone; - int ind = 0, dind = 0; - unsigned short ind_block[BLOCK_SIZE >> 1]; - unsigned short dind_block[BLOCK_SIZE >> 1]; - -#define NEXT_BAD (zone = next(zone)) - - if (!badblocks) - return; - mark_inode(MINIX_BAD_INO); - inode->i_nlinks = 1; - inode->i_time = time(NULL); - inode->i_mode = S_IFREG + 0000; - inode->i_size = badblocks * BLOCK_SIZE; - zone = next(0); - for (i = 0; i < 7; i++) { - inode->i_zone[i] = zone; - if (!NEXT_BAD) - goto end_bad; - } - inode->i_zone[7] = ind = get_free_block(); - memset(ind_block, 0, BLOCK_SIZE); - for (i = 0; i < 512; i++) { - ind_block[i] = zone; - if (!NEXT_BAD) - goto end_bad; - } - inode->i_zone[8] = dind = get_free_block(); - memset(dind_block, 0, BLOCK_SIZE); - for (i = 0; i < 512; i++) { - write_block(ind, (char *) ind_block); - dind_block[i] = ind = get_free_block(); - memset(ind_block, 0, BLOCK_SIZE); - for (j = 0; j < 512; j++) { - ind_block[j] = zone; - if (!NEXT_BAD) - goto end_bad; - } - } - error_msg_and_die("too many bad blocks"); - end_bad: - if (ind) - write_block(ind, (char *) ind_block); - if (dind) - write_block(dind, (char *) dind_block); -} - -#ifdef BB_FEATURE_MINIX2 -static void make_bad_inode2(void) -{ - struct minix2_inode *inode = &Inode2[MINIX_BAD_INO]; - int i, j, zone; - int ind = 0, dind = 0; - unsigned long ind_block[BLOCK_SIZE >> 2]; - unsigned long dind_block[BLOCK_SIZE >> 2]; - - if (!badblocks) - return; - mark_inode(MINIX_BAD_INO); - inode->i_nlinks = 1; - inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL); - inode->i_mode = S_IFREG + 0000; - inode->i_size = badblocks * BLOCK_SIZE; - zone = next(0); - for (i = 0; i < 7; i++) { - inode->i_zone[i] = zone; - if (!NEXT_BAD) - goto end_bad; - } - inode->i_zone[7] = ind = get_free_block(); - memset(ind_block, 0, BLOCK_SIZE); - for (i = 0; i < 256; i++) { - ind_block[i] = zone; - if (!NEXT_BAD) - goto end_bad; - } - inode->i_zone[8] = dind = get_free_block(); - memset(dind_block, 0, BLOCK_SIZE); - for (i = 0; i < 256; i++) { - write_block(ind, (char *) ind_block); - dind_block[i] = ind = get_free_block(); - memset(ind_block, 0, BLOCK_SIZE); - for (j = 0; j < 256; j++) { - ind_block[j] = zone; - if (!NEXT_BAD) - goto end_bad; - } - } - /* Could make triple indirect block here */ - error_msg_and_die("too many bad blocks"); - end_bad: - if (ind) - write_block(ind, (char *) ind_block); - if (dind) - write_block(dind, (char *) dind_block); -} -#endif - -static void make_root_inode(void) -{ - struct minix_inode *inode = &Inode[MINIX_ROOT_INO]; - - mark_inode(MINIX_ROOT_INO); - inode->i_zone[0] = get_free_block(); - inode->i_nlinks = 2; - inode->i_time = time(NULL); - if (badblocks) - inode->i_size = 3 * dirsize; - else { - root_block[2 * dirsize] = '\0'; - root_block[2 * dirsize + 1] = '\0'; - inode->i_size = 2 * dirsize; - } - inode->i_mode = S_IFDIR + 0755; - inode->i_uid = getuid(); - if (inode->i_uid) - inode->i_gid = getgid(); - write_block(inode->i_zone[0], root_block); -} - -#ifdef BB_FEATURE_MINIX2 -static void make_root_inode2(void) -{ - struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO]; - - mark_inode(MINIX_ROOT_INO); - inode->i_zone[0] = get_free_block(); - inode->i_nlinks = 2; - inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL); - if (badblocks) - inode->i_size = 3 * dirsize; - else { - root_block[2 * dirsize] = '\0'; - root_block[2 * dirsize + 1] = '\0'; - inode->i_size = 2 * dirsize; - } - inode->i_mode = S_IFDIR + 0755; - inode->i_uid = getuid(); - if (inode->i_uid) - inode->i_gid = getgid(); - write_block(inode->i_zone[0], root_block); -} -#endif - -static void setup_tables(void) -{ - int i; - unsigned long inodes; - - memset(super_block_buffer, 0, BLOCK_SIZE); - memset(boot_block_buffer, 0, 512); - MAGIC = magic; - ZONESIZE = 0; - MAXSIZE = version2 ? 0x7fffffff : (7 + 512 + 512 * 512) * 1024; - ZONES = BLOCKS; -/* some magic nrs: 1 inode / 3 blocks */ - if (req_nr_inodes == 0) - inodes = BLOCKS / 3; - else - inodes = req_nr_inodes; - /* Round up inode count to fill block size */ -#ifdef BB_FEATURE_MINIX2 - if (version2) - inodes = ((inodes + MINIX2_INODES_PER_BLOCK - 1) & - ~(MINIX2_INODES_PER_BLOCK - 1)); - else -#endif - inodes = ((inodes + MINIX_INODES_PER_BLOCK - 1) & - ~(MINIX_INODES_PER_BLOCK - 1)); - if (inodes > 65535) - inodes = 65535; - INODES = inodes; - IMAPS = UPPER(INODES + 1, BITS_PER_BLOCK); - ZMAPS = 0; - i = 0; - while (ZMAPS != - UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1, - BITS_PER_BLOCK) && i < 1000) { - ZMAPS = - UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1, - BITS_PER_BLOCK); - i++; - } - /* Real bad hack but overwise mkfs.minix can be thrown - * in infinite loop... - * try: - * dd if=/dev/zero of=test.fs count=10 bs=1024 - * /sbin/mkfs.minix -i 200 test.fs - * */ - if (i >= 999) { - error_msg_and_die("unable to allocate buffers for maps"); - } - FIRSTZONE = NORM_FIRSTZONE; - inode_map = xmalloc(IMAPS * BLOCK_SIZE); - zone_map = xmalloc(ZMAPS * BLOCK_SIZE); - memset(inode_map, 0xff, IMAPS * BLOCK_SIZE); - memset(zone_map, 0xff, ZMAPS * BLOCK_SIZE); - for (i = FIRSTZONE; i < ZONES; i++) - unmark_zone(i); - for (i = MINIX_ROOT_INO; i <= INODES; i++) - unmark_inode(i); - inode_buffer = xmalloc(INODE_BUFFER_SIZE); - memset(inode_buffer, 0, INODE_BUFFER_SIZE); - printf("%ld inodes\n", INODES); - printf("%ld blocks\n", ZONES); - printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE); - printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE); - printf("Maxsize=%ld\n\n", MAXSIZE); -} - -/* - * Perform a test of a block; return the number of - * blocks readable/writeable. - */ -static long do_check(char *buffer, int try, unsigned int current_block) -{ - long got; - - /* Seek to the correct loc. */ - if (lseek(DEV, current_block * BLOCK_SIZE, SEEK_SET) != - current_block * BLOCK_SIZE) { - error_msg_and_die("seek failed during testing of blocks"); - } - - - /* Try the read */ - got = read(DEV, buffer, try * BLOCK_SIZE); - if (got < 0) - got = 0; - if (got & (BLOCK_SIZE - 1)) { - printf("Weird values in do_check: probably bugs\n"); - } - got /= BLOCK_SIZE; - return got; -} - -static unsigned int currently_testing = 0; - -static void alarm_intr(int alnum) -{ - if (currently_testing >= ZONES) - return; - signal(SIGALRM, alarm_intr); - alarm(5); - if (!currently_testing) - return; - printf("%d ...", currently_testing); - fflush(stdout); -} - -static void check_blocks(void) -{ - int try, got; - static char buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS]; - - currently_testing = 0; - signal(SIGALRM, alarm_intr); - alarm(5); - while (currently_testing < ZONES) { - if (lseek(DEV, currently_testing * BLOCK_SIZE, SEEK_SET) != - currently_testing * BLOCK_SIZE) - error_msg_and_die("seek failed in check_blocks"); - try = TEST_BUFFER_BLOCKS; - if (currently_testing + try > ZONES) - try = ZONES - currently_testing; - got = do_check(buffer, try, currently_testing); - currently_testing += got; - if (got == try) - continue; - if (currently_testing < FIRSTZONE) - error_msg_and_die("bad blocks before data-area: cannot make fs"); - mark_zone(currently_testing); - badblocks++; - currently_testing++; - } - if (badblocks > 1) - printf("%d bad blocks\n", badblocks); - else if (badblocks == 1) - printf("one bad block\n"); -} - -static void get_list_blocks(filename) -char *filename; - -{ - FILE *listfile; - unsigned long blockno; - - listfile = xfopen(filename, "r"); - while (!feof(listfile)) { - fscanf(listfile, "%ld\n", &blockno); - mark_zone(blockno); - badblocks++; - } - if (badblocks > 1) - printf("%d bad blocks\n", badblocks); - else if (badblocks == 1) - printf("one bad block\n"); -} - -extern int mkfs_minix_main(int argc, char **argv) -{ - int i=1; - char *tmp; - struct stat statbuf; - char *listfile = NULL; - int stopIt=FALSE; - - if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) - error_msg_and_die("bad inode size"); -#ifdef BB_FEATURE_MINIX2 - if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) - error_msg_and_die("bad inode size"); -#endif - - /* Parse options */ - argv++; - while (--argc >= 0 && *argv && **argv) { - if (**argv == '-') { - stopIt=FALSE; - while (i > 0 && *++(*argv) && stopIt==FALSE) { - switch (**argv) { - case 'c': - check = 1; - break; - case 'i': - { - char *cp=NULL; - if (*(*argv+1) != 0) { - cp = ++(*argv); - } else { - if (--argc == 0) { - goto goodbye; - } - cp = *(++argv); - } - req_nr_inodes = strtoul(cp, &tmp, 0); - if (*tmp) - show_usage(); - stopIt=TRUE; - break; - } - case 'l': - if (--argc == 0) { - goto goodbye; - } - listfile = *(++argv); - break; - case 'n': - { - char *cp=NULL; - - if (*(*argv+1) != 0) { - cp = ++(*argv); - } else { - if (--argc == 0) { - goto goodbye; - } - cp = *(++argv); - } - i = strtoul(cp, &tmp, 0); - if (*tmp) - show_usage(); - if (i == 14) - magic = MINIX_SUPER_MAGIC; - else if (i == 30) - magic = MINIX_SUPER_MAGIC2; - else - show_usage(); - namelen = i; - dirsize = i + 2; - stopIt=TRUE; - break; - } - case 'v': -#ifdef BB_FEATURE_MINIX2 - version2 = 1; -#else - error_msg("%s: not compiled with minix v2 support", - device_name); - exit(-1); -#endif - break; - case '-': - case 'h': - default: -goodbye: - show_usage(); - } - } - } else { - if (device_name == NULL) - device_name = *argv; - else if (BLOCKS == 0) - BLOCKS = strtol(*argv, &tmp, 0); - else { - goto goodbye; - } - } - argv++; - } - - if (device_name && !BLOCKS) - BLOCKS = get_size(device_name) / 1024; - if (!device_name || BLOCKS < 10) { - show_usage(); - } -#ifdef BB_FEATURE_MINIX2 - if (version2) { - if (namelen == 14) - magic = MINIX2_SUPER_MAGIC; - else - magic = MINIX2_SUPER_MAGIC2; - } else -#endif - if (BLOCKS > 65535) - BLOCKS = 65535; - check_mount(); /* is it already mounted? */ - tmp = root_block; - *(short *) tmp = 1; - strcpy(tmp + 2, "."); - tmp += dirsize; - *(short *) tmp = 1; - strcpy(tmp + 2, ".."); - tmp += dirsize; - *(short *) tmp = 2; - strcpy(tmp + 2, ".badblocks"); - DEV = open(device_name, O_RDWR); - if (DEV < 0) - error_msg_and_die("unable to open %s", device_name); - if (fstat(DEV, &statbuf) < 0) - error_msg_and_die("unable to stat %s", device_name); - if (!S_ISBLK(statbuf.st_mode)) - check = 0; - else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) - error_msg_and_die("will not try to make filesystem on '%s'", device_name); - setup_tables(); - if (check) - check_blocks(); - else if (listfile) - get_list_blocks(listfile); -#ifdef BB_FEATURE_MINIX2 - if (version2) { - make_root_inode2(); - make_bad_inode2(); - } else -#endif - { - make_root_inode(); - make_bad_inode(); - } - mark_good_blocks(); - write_tables(); - return( 0); - -} diff --git a/busybox/util-linux/mkswap.c b/busybox/util-linux/mkswap.c deleted file mode 100644 index f72c7009a..000000000 --- a/busybox/util-linux/mkswap.c +++ /dev/null @@ -1,422 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * mkswap.c - set up a linux swap device - * - * (C) 1991 Linus Torvalds. This file may be redistributed as per - * the Linux copyright. - */ - -/* - * 20.12.91 - time began. Got VM working yesterday by doing this by hand. - * - * Usage: mkswap [-c] [-vN] [-f] device [size-in-blocks] - * - * -c for readability checking. (Use it unless you are SURE!) - * -vN for swap areas version N. (Only N=0,1 known today.) - * -f for forcing swap creation even if it would smash partition table. - * - * The device may be a block device or an image of one, but this isn't - * enforced (but it's not much fun on a character device :-). - * - * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the - * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995. - * - * Version 1 swap area code (for kernel 2.1.117), aeb, 981010. - * - * Sparc fixes, jj@ultra.linux.cz (Jakub Jelinek), 981201 - mangled by aeb. - * V1_MAX_PAGES fixes, jj, 990325. - * - * 1999-02-22 Arkadiusz Mi¶kiewicz - * - added Native Language Support - * - * from util-linux -- adapted for busybox by - * Erik Andersen . I ripped out Native Language - * Support, made some stuff smaller, and fitted for life in busybox. - * - */ - -#include -#include -#include -#include -#include -#include /* for _IO */ -#include -#include /* for PAGE_SIZE and PAGE_SHIFT */ - /* we also get PAGE_SIZE via getpagesize() */ -#include "busybox.h" - -#ifndef _IO -/* pre-1.3.45 */ -static const int BLKGETSIZE = 0x1260; -#else -/* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */ -#define BLKGETSIZE _IO(0x12,96) -#endif - -static char *device_name = NULL; -static int DEV = -1; -static long PAGES = 0; -static int check = 0; -static int badpages = 0; -static int version = -1; - -#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r)) - -/* - * The definition of the union swap_header uses the constant PAGE_SIZE. - * Unfortunately, on some architectures this depends on the hardware model, - * and can only be found at run time -- we use getpagesize(). - */ - -static int pagesize; -static int *signature_page; - -static struct swap_header_v1 { - char bootbits[1024]; /* Space for disklabel etc. */ - unsigned int version; - unsigned int last_page; - unsigned int nr_badpages; - unsigned int padding[125]; - unsigned int badpages[1]; -} *p; - -static void init_signature_page() -{ - pagesize = getpagesize(); - -#ifdef PAGE_SIZE - if (pagesize != PAGE_SIZE) - error_msg("Assuming pages of size %d", pagesize); -#endif - signature_page = (int *) xmalloc(pagesize); - memset(signature_page, 0, pagesize); - p = (struct swap_header_v1 *) signature_page; -} - -static void write_signature(char *sig) -{ - char *sp = (char *) signature_page; - - strncpy(sp + pagesize - 10, sig, 10); -} - -#define V0_MAX_PAGES (8 * (pagesize - 10)) -/* Before 2.2.0pre9 */ -#define V1_OLD_MAX_PAGES ((0x7fffffff / pagesize) - 1) -/* Since 2.2.0pre9: - error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL)) - with variations on - #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8)) - #define SWP_OFFSET(entry) ((entry) >> 8) - on the various architectures. Below the result - yuk. - - Machine pagesize SWP_ENTRY SWP_OFFSET bound+1 oldbound+2 - i386 2^12 o<<8 e>>8 1<<24 1<<19 - mips 2^12 o<<15 e>>15 1<<17 1<<19 - alpha 2^13 o<<40 e>>40 1<<24 1<<18 - m68k 2^12 o<<12 e>>12 1<<20 1<<19 - sparc 2^{12,13} (o&0x3ffff)<<9 (e>>9)&0x3ffff 1<<18 1<<{19,18} - sparc64 2^13 o<<13 e>>13 1<<51 1<<18 - ppc 2^12 o<<8 e>>8 1<<24 1<<19 - armo 2^{13,14,15} o<<8 e>>8 1<<24 1<<{18,17,16} - armv 2^12 o<<9 e>>9 1<<23 1<<19 - - assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere. - - The bad part is that we need to know this since the kernel will - refuse a swap space if it is too large. -*/ -/* patch from jj - why does this differ from the above? */ -#if defined(__alpha__) -#define V1_MAX_PAGES ((1 << 24) - 1) -#elif defined(__mips__) -#define V1_MAX_PAGES ((1 << 17) - 1) -#elif defined(__sparc_v9__) -#define V1_MAX_PAGES ((3 << 29) - 1) -#elif defined(__sparc__) -#define V1_MAX_PAGES (pagesize == 8192 ? ((3 << 29) - 1) : ((1 << 18) - 1)) -#else -#define V1_MAX_PAGES V1_OLD_MAX_PAGES -#endif -/* man page now says: -The maximum useful size of a swap area now depends on the architecture. -It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips, -128GB on alpha and 3TB on sparc64. -*/ - -#define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int)) - -static void bit_set(unsigned int *addr, unsigned int nr) -{ - unsigned int r, m; - - addr += nr / (8 * sizeof(int)); - - r = *addr; - m = 1 << (nr & (8 * sizeof(int) - 1)); - - *addr = r | m; -} - -static int bit_test_and_clear(unsigned int *addr, unsigned int nr) -{ - unsigned int r, m; - - addr += nr / (8 * sizeof(int)); - - r = *addr; - m = 1 << (nr & (8 * sizeof(int) - 1)); - - *addr = r & ~m; - return (r & m) != 0; -} - - -static void page_ok(int page) -{ - if (version == 0) - bit_set(signature_page, page); -} - -static void page_bad(int page) -{ - if (version == 0) - bit_test_and_clear(signature_page, page); - else { - if (badpages == MAX_BADPAGES) - error_msg_and_die("too many bad pages"); - p->badpages[badpages] = page; - } - badpages++; -} - -static void check_blocks(void) -{ - unsigned int current_page; - int do_seek = 1; - char *buffer; - - buffer = xmalloc(pagesize); - current_page = 0; - while (current_page < PAGES) { - if (!check) { - page_ok(current_page++); - continue; - } - if (do_seek && lseek(DEV, current_page * pagesize, SEEK_SET) != - current_page * pagesize) - error_msg_and_die("seek failed in check_blocks"); - if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) { - page_bad(current_page++); - continue; - } - page_ok(current_page++); - } - if (badpages == 1) - printf("one bad page\n"); - else if (badpages > 1) - printf("%d bad pages\n", badpages); -} - -static long valid_offset(int fd, int offset) -{ - char ch; - - if (lseek(fd, offset, 0) < 0) - return 0; - if (read(fd, &ch, 1) < 1) - return 0; - return 1; -} - -static int find_size(int fd) -{ - unsigned int high, low; - - low = 0; - for (high = 1; high > 0 && valid_offset(fd, high); high *= 2) - low = high; - while (low < high - 1) { - const int mid = (low + high) / 2; - - if (valid_offset(fd, mid)) - low = mid; - else - high = mid; - } - return (low + 1); -} - -/* return size in pages, to avoid integer overflow */ -static long get_size(const char *file) -{ - int fd; - long size; - - if ((fd = open(file, O_RDONLY)) < 0) - perror_msg_and_die("%s", file); - if (ioctl(fd, BLKGETSIZE, &size) >= 0) { - int sectors_per_page = pagesize / 512; - - size /= sectors_per_page; - } else { - size = find_size(fd) / pagesize; - } - close(fd); - return size; -} - -int mkswap_main(int argc, char **argv) -{ - char *tmp; - struct stat statbuf; - int sz; - int maxpages; - int goodpages; - int offset; - int force = 0; - - init_signature_page(); /* get pagesize */ - - while (argc-- > 1) { - argv++; - if (argv[0][0] != '-') { - if (device_name) { - int blocks_per_page = pagesize / 1024; - - PAGES = strtol(argv[0], &tmp, 0) / blocks_per_page; - if (*tmp) - show_usage(); - } else - device_name = argv[0]; - } else { - switch (argv[0][1]) { - case 'c': - check = 1; - break; - case 'f': - force = 1; - break; - case 'v': - version = atoi(argv[0] + 2); - break; - default: - show_usage(); - } - } - } - if (!device_name) { - error_msg("error: Nowhere to set up swap on?"); - show_usage(); - } - sz = get_size(device_name); - if (!PAGES) { - PAGES = sz; - } else if (PAGES > sz && !force) { - error_msg("error: size %ld is larger than device size %d", - PAGES * (pagesize / 1024), sz * (pagesize / 1024)); - return EXIT_FAILURE; - } - - if (version == -1) { - if (PAGES <= V0_MAX_PAGES) - version = 0; - else if (get_kernel_revision() < MAKE_VERSION(2, 1, 117)) - version = 0; - else if (pagesize < 2048) - version = 0; - else - version = 1; - } - if (version != 0 && version != 1) { - error_msg("error: unknown version %d", version); - show_usage(); - } - if (PAGES < 10) { - error_msg("error: swap area needs to be at least %ldkB", - (long) (10 * pagesize / 1024)); - show_usage(); - } -#if 0 - maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES); -#else - if (!version) - maxpages = V0_MAX_PAGES; - else if (get_kernel_revision() >= MAKE_VERSION(2, 2, 1)) - maxpages = V1_MAX_PAGES; - else { - maxpages = V1_OLD_MAX_PAGES; - if (maxpages > V1_MAX_PAGES) - maxpages = V1_MAX_PAGES; - } -#endif - if (PAGES > maxpages) { - PAGES = maxpages; - error_msg("warning: truncating swap area to %ldkB", - PAGES * pagesize / 1024); - } - - DEV = open(device_name, O_RDWR); - if (DEV < 0 || fstat(DEV, &statbuf) < 0) - perror_msg_and_die("%s", device_name); - if (!S_ISBLK(statbuf.st_mode)) - check = 0; - else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) - error_msg_and_die("Will not try to make swapdevice on '%s'", device_name); - -#ifdef __sparc__ - if (!force && version == 0) { - /* Don't overwrite partition table unless forced */ - unsigned char *buffer = (unsigned char *) signature_page; - unsigned short *q, sum; - - if (read(DEV, buffer, 512) != 512) - error_msg_and_die("fatal: first page unreadable"); - if (buffer[508] == 0xDA && buffer[509] == 0xBE) { - q = (unsigned short *) (buffer + 510); - for (sum = 0; q >= (unsigned short *) buffer;) - sum ^= *q--; - if (!sum) { - error_msg("Device '%s' contains a valid Sun disklabel.\n" -"This probably means creating v0 swap would destroy your partition table\n" -"No swap created. If you really want to create swap v0 on that device, use\n" -"the -f option to force it.", device_name); - return EXIT_FAILURE; - } - } - } -#endif - - if (version == 0 || check) - check_blocks(); - if (version == 0 && !bit_test_and_clear(signature_page, 0)) - error_msg_and_die("fatal: first page unreadable"); - if (version == 1) { - p->version = version; - p->last_page = PAGES - 1; - p->nr_badpages = badpages; - } - - goodpages = PAGES - badpages - 1; - if (goodpages <= 0) - error_msg_and_die("Unable to set up swap-space: unreadable"); - printf("Setting up swapspace version %d, size = %ld bytes\n", - version, (long) (goodpages * pagesize)); - write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2"); - - offset = ((version == 0) ? 0 : 1024); - if (lseek(DEV, offset, SEEK_SET) != offset) - error_msg_and_die("unable to rewind swap-device"); - if (write(DEV, (char *) signature_page + offset, pagesize - offset) - != pagesize - offset) - error_msg_and_die("unable to write signature page"); - - /* - * A subsequent swapon() will fail if the signature - * is not actually on disk. (This is a kernel bug.) - */ - if (fsync(DEV)) - error_msg_and_die("fsync failed"); - return EXIT_SUCCESS; -} diff --git a/busybox/util-linux/more.c b/busybox/util-linux/more.c deleted file mode 100644 index 780cddf66..000000000 --- a/busybox/util-linux/more.c +++ /dev/null @@ -1,217 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini more implementation for busybox - * - * - * Copyright (C) 1995, 1996 by Bruce Perens . - * - * Latest version blended together by Erik Andersen , - * based on the original more implementation by Bruce, and code from the - * Debian boot-floppies team. - * - * Termios corrects by Vladimir Oleynik - * - * 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 "busybox.h" - -static FILE *cin; - -#ifdef BB_FEATURE_USE_TERMIOS -#include -#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp) -#define getTermSettings(fd,argp) tcgetattr(fd, argp); - -static struct termios initial_settings, new_settings; - -static void set_tty_to_initial_mode(void) -{ - setTermSettings(fileno(cin), &initial_settings); -} - -static void gotsig(int sig) -{ - putchar('\n'); - exit(EXIT_FAILURE); -} -#endif /* BB_FEATURE_USE_TERMIOS */ - - -static int terminal_width = 79; /* not 80 in case terminal has linefold bug */ -static int terminal_height = 24; - - -extern int more_main(int argc, char **argv) -{ - int c, lines, input = 0; - int please_display_more_prompt = -1; - struct stat st; - FILE *file; - int len, page_height; - -#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS - struct winsize win = { 0, 0, 0, 0 }; -#endif - - argc--; - argv++; - - - /* not use inputing from terminal if usage: more > outfile */ - if(isatty(fileno(stdout))) { - cin = fopen(CURRENT_TTY, "r"); - if (!cin) - cin = xfopen(CONSOLE_DEV, "r"); - please_display_more_prompt = 0; -#ifdef BB_FEATURE_USE_TERMIOS - getTermSettings(fileno(cin), &initial_settings); - new_settings = initial_settings; - new_settings.c_lflag &= ~ICANON; - new_settings.c_lflag &= ~ECHO; -#ifndef linux - /* Hmm, in linux c_cc[] not parsed if set ~ICANON */ - new_settings.c_cc[VMIN] = 1; - new_settings.c_cc[VTIME] = 0; -#endif - setTermSettings(fileno(cin), &new_settings); - atexit(set_tty_to_initial_mode); - (void) signal(SIGINT, gotsig); - (void) signal(SIGQUIT, gotsig); - (void) signal(SIGTERM, gotsig); -#endif - } - - do { - if (argc == 0) { - file = stdin; - } else - file = wfopen(*argv, "r"); - if(file==0) - goto loop; - - fstat(fileno(file), &st); - - if(please_display_more_prompt>0) - please_display_more_prompt = 0; - -#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS - ioctl(fileno(stdout), TIOCGWINSZ, &win); - if (win.ws_row > 4) - terminal_height = win.ws_row - 2; - if (win.ws_col > 0) - terminal_width = win.ws_col - 1; -#endif - len=0; - lines = 0; - page_height = terminal_height; - while ((c = getc(file)) != EOF) { - - if (please_display_more_prompt>0) { - len = printf("--More-- "); - if (file != stdin) { -#if _FILE_OFFSET_BITS == 64 - len += printf("(%d%% of %lld bytes)", - (int) (100 * ((double) ftell(file) / - (double) st.st_size)), (long long)st.st_size); -#else - len += printf("(%d%% of %ld bytes)", - (int) (100 * ((double) ftell(file) / - (double) st.st_size)), (long)st.st_size); -#endif - } - - fflush(stdout); - - /* - * We've just displayed the "--More--" prompt, so now we need - * to get input from the user. - */ - input = getc(cin); -#ifndef BB_FEATURE_USE_TERMIOS - printf("\033[A"); /* up cursor */ -#endif - /* Erase the "More" message */ - putc('\r', stdout); - while (--len >= 0) - putc(' ', stdout); - putc('\r', stdout); - fflush(stdout); - len=0; - lines = 0; - page_height = terminal_height; - please_display_more_prompt = 0; - - if (input == 'q') - goto end; - } - - /* - * There are two input streams to worry about here: - * - * c : the character we are reading from the file being "mored" - * input : a character received from the keyboard - * - * If we hit a newline in the _file_ stream, we want to test and - * see if any characters have been hit in the _input_ stream. This - * allows the user to quit while in the middle of a file. - */ - if (c == '\n') { - /* increment by just one line if we are at - * the end of this line */ - if (input == '\n') - if(please_display_more_prompt==0) - please_display_more_prompt = 1; - /* Adjust the terminal height for any overlap, so that - * no lines get lost off the top. */ - if (len >= terminal_width) { - int quot, rem; - quot = len / terminal_width; - rem = len - (quot * terminal_width); - if (quot) { - if (rem) - page_height-=quot; - else - page_height-=(quot-1); - } - } - if (++lines >= page_height) { - if(please_display_more_prompt==0) - please_display_more_prompt = 1; - } - len=0; - } - /* - * If we just read a newline from the file being 'mored' and any - * key other than a return is hit, scroll by one page - */ - putc(c, stdout); - len++; - } - fclose(file); - fflush(stdout); -loop: - argv++; - } while (--argc > 0); - end: - return 0; -} diff --git a/busybox/util-linux/mount.c b/busybox/util-linux/mount.c deleted file mode 100644 index af57a7623..000000000 --- a/busybox/util-linux/mount.c +++ /dev/null @@ -1,498 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini mount implementation for busybox - * - * 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 - * - * 3/21/1999 Charles P. Wright - * searches through fstab when -a is passed - * will try mounting stuff with all fses when passed -t auto - * - * 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab. - * - * 1999-10-07 Erik Andersen , . - * Rewrite of a lot of code. Removed mtab usage (I plan on - * putting it back as a compile-time option some time), - * major adjustments to option parsing, and some serious - * dieting all around. - * - * 1999-11-06 mtab suppport is back - andersee - * - * 2000-01-12 Ben Collins , Borrowed utils-linux's - * mount to add loop support. - * - * 2000-04-30 Dave Cinege - * Rewrote fstab while loop and lower mount section. Can now do - * single mounts from fstab. Can override fstab options for single - * mount. Common mount_one call for single mounts and 'all'. Fixed - * mtab updating and stale entries. Removed 'remount' default. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" -#if defined BB_FEATURE_USE_DEVPS_PATCH -# include /* For Erik's nifty devmtab device driver */ -#endif - -enum { - MS_MGC_VAL = 0xc0ed0000, /* Magic number indicatng "new" flags */ - MS_RDONLY = 1, /* Mount read-only */ - MS_NOSUID = 2, /* Ignore suid and sgid bits */ - MS_NODEV = 4, /* Disallow access to device special files */ - MS_NOEXEC = 8, /* Disallow program execution */ - MS_SYNCHRONOUS = 16, /* Writes are synced at once */ - MS_REMOUNT = 32, /* Alter flags of a mounted FS */ - MS_MANDLOCK = 64, /* Allow mandatory locks on an FS */ - S_QUOTA = 128, /* Quota initialized for file/directory/symlink */ - S_APPEND = 256, /* Append-only file */ - S_IMMUTABLE = 512, /* Immutable file */ - MS_NOATIME = 1024, /* Do not update access times. */ - MS_NODIRATIME = 2048, /* Do not update directory access times */ - MS_BIND = 4096, /* Use the new linux 2.4.x "mount --bind" feature */ -}; - - -#if defined BB_FEATURE_MOUNT_LOOP -#include -#include -static int use_loop = FALSE; -#endif - -extern int mount (__const char *__special_file, __const char *__dir, - __const char *__fstype, unsigned long int __rwflag, - __const void *__data); -extern int umount (__const char *__special_file); -extern int umount2 (__const char *__special_file, int __flags); - -extern int sysfs( int option, unsigned int fs_index, char * buf); - -extern const char mtab_file[]; /* Defined in utility.c */ - -struct mount_options { - const char *name; - unsigned long and; - unsigned long or; -}; - -static const struct mount_options mount_options[] = { - {"async", ~MS_SYNCHRONOUS, 0}, - {"atime", ~0, ~MS_NOATIME}, - {"defaults", ~0, 0}, - {"dev", ~MS_NODEV, 0}, - {"diratime", ~0, ~MS_NODIRATIME}, - {"exec", ~MS_NOEXEC, 0}, - {"noatime", ~0, MS_NOATIME}, - {"nodev", ~0, MS_NODEV}, - {"nodiratime", ~0, MS_NODIRATIME}, - {"noexec", ~0, MS_NOEXEC}, - {"nosuid", ~0, MS_NOSUID}, - {"remount", ~0, MS_REMOUNT}, - {"ro", ~0, MS_RDONLY}, - {"rw", ~MS_RDONLY, 0}, - {"suid", ~MS_NOSUID, 0}, - {"sync", ~0, MS_SYNCHRONOUS}, - {"bind", ~0, MS_BIND}, - {0, 0, 0} -}; - -static int -do_mount(char *specialfile, char *dir, char *filesystemtype, - long flags, void *string_flags, int useMtab, int fakeIt, - char *mtab_opts, int mount_all) -{ - int status = 0; -#if defined BB_FEATURE_MOUNT_LOOP - char *lofile = NULL; -#endif - - if (fakeIt == FALSE) - { -#if defined BB_FEATURE_MOUNT_LOOP - if (use_loop==TRUE) { - int loro = flags & MS_RDONLY; - - lofile = specialfile; - - specialfile = find_unused_loop_device(); - if (specialfile == NULL) { - error_msg_and_die("Could not find a spare loop device"); - } - if (set_loop(specialfile, lofile, 0, &loro)) { - error_msg_and_die("Could not setup loop device"); - } - if (!(flags & MS_RDONLY) && loro) { /* loop is ro, but wanted rw */ - error_msg("WARNING: loop device is read-only"); - flags |= MS_RDONLY; - } - } -#endif - status = mount(specialfile, dir, filesystemtype, flags, string_flags); - if (status < 0 && errno == EROFS) { - error_msg("%s is write-protected, mounting read-only", specialfile); - status = mount(specialfile, dir, filesystemtype, flags |= MS_RDONLY, string_flags); - } - /* Don't whine about already mounted filesystems when mounting all. */ - if (status < 0 && errno == EBUSY && mount_all) - return TRUE; - } - - - /* If the mount was sucessful, do anything needed, then return TRUE */ - if (status == 0 || fakeIt==TRUE) { - -#if defined BB_FEATURE_MTAB_SUPPORT - if (useMtab == TRUE) { - erase_mtab(specialfile); // Clean any stale entries - write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts); - } -#endif - return (TRUE); - } - - /* Bummer. mount failed. Clean up */ -#if defined BB_FEATURE_MOUNT_LOOP - if (lofile != NULL) { - del_loop(specialfile); - } -#endif - - if (errno == EPERM) { - error_msg_and_die("permission denied. Are you root?"); - } - - return (FALSE); -} - - - -/* Seperate standard mount options from the nonstandard string options */ -static void -parse_mount_options(char *options, int *flags, char *strflags) -{ - while (options) { - int gotone = FALSE; - char *comma = strchr(options, ','); - const struct mount_options *f = mount_options; - - if (comma) - *comma = '\0'; - - while (f->name != 0) { - if (strcasecmp(f->name, options) == 0) { - - *flags &= f->and; - *flags |= f->or; - gotone = TRUE; - break; - } - f++; - } -#if defined BB_FEATURE_MOUNT_LOOP - if (gotone == FALSE && !strcasecmp("loop", options)) { /* loop device support */ - use_loop = TRUE; - gotone = TRUE; - } -#endif - if (*strflags && strflags != '\0' && gotone == FALSE) { - char *temp = strflags; - - temp += strlen(strflags); - *temp++ = ','; - *temp++ = '\0'; - } - if (gotone == FALSE) - strcat(strflags, options); - if (comma) { - *comma = ','; - options = ++comma; - } else { - break; - } - } -} - -static int -mount_one(char *blockDevice, char *directory, char *filesystemType, - unsigned long flags, char *string_flags, int useMtab, int fakeIt, - char *mtab_opts, int whineOnErrors, int mount_all) -{ - int status = 0; - -#if defined BB_FEATURE_USE_DEVPS_PATCH - if (strcmp(filesystemType, "auto") == 0) { - static const char *noauto_array[] = { "tmpfs", "shm", "proc", "ramfs", "devpts", "devfs", "usbdevfs", 0 }; - const char **noauto_fstype; - const int num_of_filesystems = sysfs(3, 0, 0); - char buf[255]; - int i=0; - - filesystemType=buf; - - while(i < num_of_filesystems) { - sysfs(2, i++, filesystemType); - for (noauto_fstype = noauto_array; *noauto_fstype; noauto_fstype++) { - if (!strcmp(filesystemType, *noauto_fstype)) { - break; - } - } - if (!*noauto_fstype) { - status = do_mount(blockDevice, directory, filesystemType, - flags | MS_MGC_VAL, string_flags, - useMtab, fakeIt, mtab_opts, mount_all); - if (status == TRUE) - break; - } - } - } -#else - if (strcmp(filesystemType, "auto") == 0) { - char buf[255]; - FILE *f = xfopen("/proc/filesystems", "r"); - - while (fgets(buf, sizeof(buf), f) != NULL) { - filesystemType = buf; - if (*filesystemType == '\t') { // Not a nodev filesystem - - // Add NULL termination to each line - while (*filesystemType && *filesystemType != '\n') - filesystemType++; - *filesystemType = '\0'; - - filesystemType = buf; - filesystemType++; // hop past tab - - status = do_mount(blockDevice, directory, filesystemType, - flags | MS_MGC_VAL, string_flags, - useMtab, fakeIt, mtab_opts, mount_all); - if (status == TRUE) - break; - } - } - fclose(f); - } -#endif - else { - status = do_mount(blockDevice, directory, filesystemType, - flags | MS_MGC_VAL, string_flags, useMtab, - fakeIt, mtab_opts, mount_all); - } - - if (status == FALSE) { - if (whineOnErrors == TRUE) { - perror_msg("Mounting %s on %s failed", blockDevice, directory); - } - return (FALSE); - } - return (TRUE); -} - -void show_mounts(void) -{ -#if defined BB_FEATURE_USE_DEVPS_PATCH - int fd, i, numfilesystems; - char device[] = "/dev/mtab"; - struct k_mntent *mntentlist; - - /* open device */ - fd = open(device, O_RDONLY); - if (fd < 0) - perror_msg_and_die("open failed for `%s'", device); - - /* How many mounted filesystems? We need to know to - * allocate enough space for later... */ - numfilesystems = ioctl (fd, DEVMTAB_COUNT_MOUNTS); - if (numfilesystems<0) - perror_msg_and_die( "\nDEVMTAB_COUNT_MOUNTS"); - mntentlist = (struct k_mntent *) xcalloc ( numfilesystems, sizeof(struct k_mntent)); - - /* Grab the list of mounted filesystems */ - if (ioctl (fd, DEVMTAB_GET_MOUNTS, mntentlist)<0) - perror_msg_and_die( "\nDEVMTAB_GET_MOUNTS"); - - for( i = 0 ; i < numfilesystems ; i++) { - printf( "%s %s %s %s %d %d\n", mntentlist[i].mnt_fsname, - mntentlist[i].mnt_dir, mntentlist[i].mnt_type, - mntentlist[i].mnt_opts, mntentlist[i].mnt_freq, - mntentlist[i].mnt_passno); - } -#ifdef BB_FEATURE_CLEAN_UP - /* Don't bother to close files or free memory. Exit - * does that automagically, so we can save a few bytes */ - free( mntentlist); - close(fd); -#endif - exit(EXIT_SUCCESS); -#else - FILE *mountTable = setmntent(mtab_file, "r"); - - if (mountTable) { - struct mntent *m; - - while ((m = getmntent(mountTable)) != 0) { - char *blockDevice = m->mnt_fsname; - if (strcmp(blockDevice, "/dev/root") == 0) { - blockDevice = find_real_root_device_name(blockDevice); - } - printf("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir, - m->mnt_type, m->mnt_opts); -#ifdef BB_FEATURE_CLEAN_UP - if(blockDevice != m->mnt_fsname) - free(blockDevice); -#endif - } - endmntent(mountTable); - } else { - perror_msg_and_die("%s", mtab_file); - } - exit(EXIT_SUCCESS); -#endif -} - -extern int mount_main(int argc, char **argv) -{ - struct stat statbuf; - char string_flags_buf[1024] = ""; - char *string_flags = string_flags_buf; - char *extra_opts = string_flags_buf; - int flags = 0; - char *filesystemType = "auto"; - char *device = xmalloc(PATH_MAX); - char *directory = xmalloc(PATH_MAX); - int all = FALSE; - int fakeIt = FALSE; - int useMtab = TRUE; - int rc = EXIT_FAILURE; - int fstabmount = FALSE; - int opt; - - /* Parse options */ - while ((opt = getopt(argc, argv, "o:rt:wafnv")) > 0) { - switch (opt) { - case 'o': - parse_mount_options(optarg, &flags, string_flags); - break; - case 'r': - flags |= MS_RDONLY; - break; - case 't': - filesystemType = optarg; - break; - case 'w': - flags &= ~MS_RDONLY; - break; - case 'a': - all = TRUE; - break; - case 'f': - fakeIt = TRUE; - break; -#ifdef BB_FEATURE_MTAB_SUPPORT - case 'n': - useMtab = FALSE; - break; -#endif - case 'v': - break; /* ignore -v */ - } - } - - if (!all && optind == argc) - show_mounts(); - - if (optind < argc) { - /* if device is a filename get its real path */ - if (stat(argv[optind], &statbuf) == 0) { - device = simplify_path(argv[optind]); - } else { - safe_strncpy(device, argv[optind], PATH_MAX); - } - } - - if (optind + 1 < argc) - directory = simplify_path(argv[optind + 1]); - - if (all == TRUE || optind + 1 == argc) { - struct mntent *m = NULL; - FILE *f = setmntent("/etc/fstab", "r"); - fstabmount = TRUE; - - if (f == NULL) - perror_msg_and_die( "\nCannot read /etc/fstab"); - - while ((m = getmntent(f)) != NULL) { - if (all == FALSE && optind + 1 == argc && ( - (strcmp(device, m->mnt_fsname) != 0) && - (strcmp(device, m->mnt_dir) != 0) ) ) { - continue; - } - - if (all == TRUE && ( // If we're mounting 'all' - (strstr(m->mnt_opts, "noauto")) || // and the file system isn't noauto, - (strstr(m->mnt_type, "swap")) || // and isn't swap or nfs, then mount it - (strstr(m->mnt_type, "nfs")) ) ) { - continue; - } - - if (all == TRUE || flags == 0) { // Allow single mount to override fstab flags - flags = 0; - *string_flags = '\0'; - parse_mount_options(m->mnt_opts, &flags, string_flags); - } - - strcpy(device, m->mnt_fsname); - strcpy(directory, m->mnt_dir); - filesystemType = strdup(m->mnt_type); -singlemount: - string_flags = strdup(string_flags); - rc = EXIT_SUCCESS; -#ifdef BB_NFSMOUNT - if (strchr(device, ':') != NULL) - filesystemType = "nfs"; - if (strcmp(filesystemType, "nfs") == 0) { - if (nfsmount (device, directory, &flags, &extra_opts, - &string_flags, 1)) { - perror_msg("nfsmount failed"); - rc = EXIT_FAILURE; - } - } -#endif - if (!mount_one(device, directory, filesystemType, flags, - string_flags, useMtab, fakeIt, extra_opts, TRUE, all)) - rc = EXIT_FAILURE; - - if (all == FALSE) - break; - } - if (fstabmount == TRUE) - endmntent(f); - - if (all == FALSE && fstabmount == TRUE && m == NULL) - fprintf(stderr, "Can't find %s in /etc/fstab\n", device); - - return rc; - } - - goto singlemount; -} diff --git a/busybox/util-linux/nfsmount.c b/busybox/util-linux/nfsmount.c deleted file mode 100644 index cd722acc3..000000000 --- a/busybox/util-linux/nfsmount.c +++ /dev/null @@ -1,977 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * nfsmount.c -- Linux NFS mount - * Copyright (C) 1993 Rick Sladkey - * - * 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. - * - * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port - * numbers to be specified on the command line. - * - * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler : - * Omit the call to connect() for Linux version 1.3.11 or later. - * - * Wed Oct 1 23:55:28 1997: Dick Streefland - * Implemented the "bg", "fg" and "retry" mount options for NFS. - * - * 1999-02-22 Arkadiusz Mi¶kiewicz - * - added Native Language Support - * - * Modified by Olaf Kirch and Trond Myklebust for new NFS code, - * plus NFSv3 stuff. - */ - -/* - * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "busybox.h" -#undef TRUE -#undef FALSE -#include -#include -#include -#include /* For the kernels nfs stuff */ -#include "nfsmount.h" - -#ifndef NFS_FHSIZE -static const int NFS_FHSIZE = 32; -#endif -#ifndef NFS_PORT -static const int NFS_PORT = 2049; -#endif - -/* Disable the nls stuff */ -# undef bindtextdomain -# define bindtextdomain(Domain, Directory) /* empty */ -# undef textdomain -# define textdomain(Domain) /* empty */ -# define _(Text) (Text) -# define N_(Text) (Text) - -static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */ -static const int MS_RDONLY = 1; /* Mount read-only */ -static const int MS_NOSUID = 2; /* Ignore suid and sgid bits */ -static const int MS_NODEV = 4; /* Disallow access to device special files */ -static const int MS_NOEXEC = 8; /* Disallow program execution */ -static const int MS_SYNCHRONOUS = 16; /* Writes are synced at once */ -static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS */ -static const int MS_MANDLOCK = 64; /* Allow mandatory locks on an FS */ -static const int S_QUOTA = 128; /* Quota initialized for file/directory/symlink */ -static const int S_APPEND = 256; /* Append-only file */ -static const int S_IMMUTABLE = 512; /* Immutable file */ -static const int MS_NOATIME = 1024; /* Do not update access times. */ -static const int MS_NODIRATIME = 2048; /* Do not update directory access times */ - - -/* - * We want to be able to compile mount on old kernels in such a way - * that the binary will work well on more recent kernels. - * Thus, if necessary we teach nfsmount.c the structure of new fields - * that will come later. - * - * Moreover, the new kernel includes conflict with glibc includes - * so it is easiest to ignore the kernel altogether (at compile time). - */ - -/* NOTE: Do not make this into a 'static const int' because the pre-processor - * needs to test this value in some #if statements. */ -#define NFS_MOUNT_VERSION 4 - -struct nfs2_fh { - char data[32]; -}; -struct nfs3_fh { - unsigned short size; - unsigned char data[64]; -}; - -struct nfs_mount_data { - int version; /* 1 */ - int fd; /* 1 */ - struct nfs2_fh old_root; /* 1 */ - int flags; /* 1 */ - int rsize; /* 1 */ - int wsize; /* 1 */ - int timeo; /* 1 */ - int retrans; /* 1 */ - int acregmin; /* 1 */ - int acregmax; /* 1 */ - int acdirmin; /* 1 */ - int acdirmax; /* 1 */ - struct sockaddr_in addr; /* 1 */ - char hostname[256]; /* 1 */ - int namlen; /* 2 */ - unsigned int bsize; /* 3 */ - struct nfs3_fh root; /* 4 */ -}; - -/* bits in the flags field */ - -static const int NFS_MOUNT_SOFT = 0x0001; /* 1 */ -static const int NFS_MOUNT_INTR = 0x0002; /* 1 */ -static const int NFS_MOUNT_SECURE = 0x0004; /* 1 */ -static const int NFS_MOUNT_POSIX = 0x0008; /* 1 */ -static const int NFS_MOUNT_NOCTO = 0x0010; /* 1 */ -static const int NFS_MOUNT_NOAC = 0x0020; /* 1 */ -static const int NFS_MOUNT_TCP = 0x0040; /* 2 */ -static const int NFS_MOUNT_VER3 = 0x0080; /* 3 */ -static const int NFS_MOUNT_KERBEROS = 0x0100; /* 3 */ -static const int NFS_MOUNT_NONLM = 0x0200; /* 3 */ - - -#define UTIL_LINUX_VERSION "2.10m" -#define util_linux_version "util-linux-2.10m" - -#define HAVE_inet_aton -#define HAVE_scsi_h -#define HAVE_blkpg_h -#define HAVE_kd_h -#define HAVE_termcap -#define HAVE_locale_h -#define HAVE_libintl_h -#define ENABLE_NLS -#define HAVE_langinfo_h -#define HAVE_progname -#define HAVE_openpty -#define HAVE_nanosleep -#define HAVE_personality -#define HAVE_tm_gmtoff - -static char *nfs_strerror(int status); - -#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r)) -#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2) - -static const int EX_FAIL = 32; /* mount failure */ -static const int EX_BG = 256; /* retry in background (internal only) */ - - -/* - * nfs_mount_version according to the sources seen at compile time. - */ -static int nfs_mount_version; - -/* - * Unfortunately, the kernel prints annoying console messages - * in case of an unexpected nfs mount version (instead of - * just returning some error). Therefore we'll have to try - * and figure out what version the kernel expects. - * - * Variables: - * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time - * NFS_MOUNT_VERSION: these nfsmount sources at compile time - * nfs_mount_version: version this source and running kernel can handle - */ -static void -find_kernel_nfs_mount_version(void) -{ - static int kernel_version = 0; - - if (kernel_version) - return; - - nfs_mount_version = NFS_MOUNT_VERSION; /* default */ - - kernel_version = get_kernel_revision(); - if (kernel_version) { - if (kernel_version < MAKE_VERSION(2,1,32)) - nfs_mount_version = 1; - else if (kernel_version < MAKE_VERSION(2,2,18) || - (kernel_version >= MAKE_VERSION(2,3,0) && - kernel_version < MAKE_VERSION(2,3,99))) - nfs_mount_version = 3; - else - nfs_mount_version = 4; /* since 2.3.99pre4 */ - } - if (nfs_mount_version > NFS_MOUNT_VERSION) - nfs_mount_version = NFS_MOUNT_VERSION; -} - -static struct pmap * -get_mountport(struct sockaddr_in *server_addr, - long unsigned prog, - long unsigned version, - long unsigned proto, - long unsigned port) -{ -struct pmaplist *pmap; -static struct pmap p = {0, 0, 0, 0}; - -server_addr->sin_port = PMAPPORT; -pmap = pmap_getmaps(server_addr); - -if (version > MAX_NFSPROT) - version = MAX_NFSPROT; -if (!prog) - prog = MOUNTPROG; -p.pm_prog = prog; -p.pm_vers = version; -p.pm_prot = proto; -p.pm_port = port; - -while (pmap) { - if (pmap->pml_map.pm_prog != prog) - goto next; - if (!version && p.pm_vers > pmap->pml_map.pm_vers) - goto next; - if (version > 2 && pmap->pml_map.pm_vers != version) - goto next; - if (version && version <= 2 && pmap->pml_map.pm_vers > 2) - goto next; - if (pmap->pml_map.pm_vers > MAX_NFSPROT || - (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) || - (port && pmap->pml_map.pm_port != port)) - goto next; - memcpy(&p, &pmap->pml_map, sizeof(p)); -next: - pmap = pmap->pml_next; -} -if (!p.pm_vers) - p.pm_vers = MOUNTVERS; -if (!p.pm_port) - p.pm_port = MOUNTPORT; -if (!p.pm_prot) - p.pm_prot = IPPROTO_TCP; -return &p; -} - -int nfsmount(const char *spec, const char *node, int *flags, - char **extra_opts, char **mount_opts, int running_bg) -{ - static char *prev_bg_host; - char hostdir[1024]; - CLIENT *mclient; - char *hostname; - char *pathname; - char *old_opts; - char *mounthost=NULL; - char new_opts[1024]; - struct timeval total_timeout; - enum clnt_stat clnt_stat; - static struct nfs_mount_data data; - char *opt, *opteq; - int val; - struct hostent *hp; - struct sockaddr_in server_addr; - struct sockaddr_in mount_server_addr; - struct pmap* pm_mnt; - int msock, fsock; - struct timeval retry_timeout; - union { - struct fhstatus nfsv2; - struct mountres3 nfsv3; - } status; - struct stat statbuf; - char *s; - int port; - int mountport; - int proto; - int bg; - int soft; - int intr; - int posix; - int nocto; - int noac; - int nolock; - int retry; - int tcp; - int mountprog; - int mountvers; - int nfsprog; - int nfsvers; - int retval; - time_t t; - time_t prevt; - time_t timeout; - - find_kernel_nfs_mount_version(); - - retval = EX_FAIL; - msock = fsock = -1; - mclient = NULL; - if (strlen(spec) >= sizeof(hostdir)) { - error_msg("excessively long host:dir argument"); - goto fail; - } - strcpy(hostdir, spec); - if ((s = strchr(hostdir, ':'))) { - hostname = hostdir; - pathname = s + 1; - *s = '\0'; - /* Ignore all but first hostname in replicated mounts - until they can be fully supported. (mack@sgi.com) */ - if ((s = strchr(hostdir, ','))) { - *s = '\0'; - error_msg("warning: multiple hostnames not supported"); - } - } else { - error_msg("directory to mount not in host:dir format"); - goto fail; - } - - server_addr.sin_family = AF_INET; -#ifdef HAVE_inet_aton - if (!inet_aton(hostname, &server_addr.sin_addr)) -#endif - { - if ((hp = gethostbyname(hostname)) == NULL) { - herror_msg("%s", hostname); - goto fail; - } else { - if (hp->h_length > sizeof(struct in_addr)) { - error_msg("got bad hp->h_length"); - hp->h_length = sizeof(struct in_addr); - } - memcpy(&server_addr.sin_addr, - hp->h_addr, hp->h_length); - } - } - - memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr)); - - /* add IP address to mtab options for use when unmounting */ - - s = inet_ntoa(server_addr.sin_addr); - old_opts = *extra_opts; - if (!old_opts) - old_opts = ""; - if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) { - error_msg("excessively long option argument"); - goto fail; - } - sprintf(new_opts, "%s%saddr=%s", - old_opts, *old_opts ? "," : "", s); - *extra_opts = xstrdup(new_opts); - - /* Set default options. - * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to - * let the kernel decide. - * timeo is filled in after we know whether it'll be TCP or UDP. */ - memset(&data, 0, sizeof(data)); - data.retrans = 3; - data.acregmin = 3; - data.acregmax = 60; - data.acdirmin = 30; - data.acdirmax = 60; -#if NFS_MOUNT_VERSION >= 2 - data.namlen = NAME_MAX; -#endif - - bg = 0; - soft = 0; - intr = 0; - posix = 0; - nocto = 0; - nolock = 0; - noac = 0; - retry = 10000; /* 10000 minutes ~ 1 week */ - tcp = 0; - - mountprog = MOUNTPROG; - mountvers = 0; - port = 0; - mountport = 0; - nfsprog = NFS_PROGRAM; - nfsvers = 0; - - /* parse options */ - - for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) { - if ((opteq = strchr(opt, '='))) { - val = atoi(opteq + 1); - *opteq = '\0'; - if (!strcmp(opt, "rsize")) - data.rsize = val; - else if (!strcmp(opt, "wsize")) - data.wsize = val; - else if (!strcmp(opt, "timeo")) - data.timeo = val; - else if (!strcmp(opt, "retrans")) - data.retrans = val; - else if (!strcmp(opt, "acregmin")) - data.acregmin = val; - else if (!strcmp(opt, "acregmax")) - data.acregmax = val; - else if (!strcmp(opt, "acdirmin")) - data.acdirmin = val; - else if (!strcmp(opt, "acdirmax")) - data.acdirmax = val; - else if (!strcmp(opt, "actimeo")) { - data.acregmin = val; - data.acregmax = val; - data.acdirmin = val; - data.acdirmax = val; - } - else if (!strcmp(opt, "retry")) - retry = val; - else if (!strcmp(opt, "port")) - port = val; - else if (!strcmp(opt, "mountport")) - mountport = val; - else if (!strcmp(opt, "mounthost")) - mounthost=xstrndup(opteq+1, - strcspn(opteq+1," \t\n\r,")); - else if (!strcmp(opt, "mountprog")) - mountprog = val; - else if (!strcmp(opt, "mountvers")) - mountvers = val; - else if (!strcmp(opt, "nfsprog")) - nfsprog = val; - else if (!strcmp(opt, "nfsvers") || - !strcmp(opt, "vers")) - nfsvers = val; - else if (!strcmp(opt, "proto")) { - if (!strncmp(opteq+1, "tcp", 3)) - tcp = 1; - else if (!strncmp(opteq+1, "udp", 3)) - tcp = 0; - else - printf(_("Warning: Unrecognized proto= option.\n")); - } else if (!strcmp(opt, "namlen")) { -#if NFS_MOUNT_VERSION >= 2 - if (nfs_mount_version >= 2) - data.namlen = val; - else -#endif - printf(_("Warning: Option namlen is not supported.\n")); - } else if (!strcmp(opt, "addr")) - /* ignore */; - else { - printf(_("unknown nfs mount parameter: " - "%s=%d\n"), opt, val); - goto fail; - } - } - else { - val = 1; - if (!strncmp(opt, "no", 2)) { - val = 0; - opt += 2; - } - if (!strcmp(opt, "bg")) - bg = val; - else if (!strcmp(opt, "fg")) - bg = !val; - else if (!strcmp(opt, "soft")) - soft = val; - else if (!strcmp(opt, "hard")) - soft = !val; - else if (!strcmp(opt, "intr")) - intr = val; - else if (!strcmp(opt, "posix")) - posix = val; - else if (!strcmp(opt, "cto")) - nocto = !val; - else if (!strcmp(opt, "ac")) - noac = !val; - else if (!strcmp(opt, "tcp")) - tcp = val; - else if (!strcmp(opt, "udp")) - tcp = !val; - else if (!strcmp(opt, "lock")) { - if (nfs_mount_version >= 3) - nolock = !val; - else - printf(_("Warning: option nolock is not supported.\n")); - } else { - printf(_("unknown nfs mount option: " - "%s%s\n"), val ? "" : "no", opt); - goto fail; - } - } - } - proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP; - - data.flags = (soft ? NFS_MOUNT_SOFT : 0) - | (intr ? NFS_MOUNT_INTR : 0) - | (posix ? NFS_MOUNT_POSIX : 0) - | (nocto ? NFS_MOUNT_NOCTO : 0) - | (noac ? NFS_MOUNT_NOAC : 0); -#if NFS_MOUNT_VERSION >= 2 - if (nfs_mount_version >= 2) - data.flags |= (tcp ? NFS_MOUNT_TCP : 0); -#endif -#if NFS_MOUNT_VERSION >= 3 - if (nfs_mount_version >= 3) - data.flags |= (nolock ? NFS_MOUNT_NONLM : 0); -#endif - if (nfsvers > MAX_NFSPROT) { - error_msg("NFSv%d not supported!", nfsvers); - return 0; - } - if (mountvers > MAX_NFSPROT) { - error_msg("NFSv%d not supported!", nfsvers); - return 0; - } - if (nfsvers && !mountvers) - mountvers = (nfsvers < 3) ? 1 : nfsvers; - if (nfsvers && nfsvers < mountvers) { - mountvers = nfsvers; - } - - /* Adjust options if none specified */ - if (!data.timeo) - data.timeo = tcp ? 70 : 7; - -#ifdef NFS_MOUNT_DEBUG - printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", - data.rsize, data.wsize, data.timeo, data.retrans); - printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n", - data.acregmin, data.acregmax, data.acdirmin, data.acdirmax); - printf("port = %d, bg = %d, retry = %d, flags = %.8x\n", - port, bg, retry, data.flags); - printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n", - mountprog, mountvers, nfsprog, nfsvers); - printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n", - (data.flags & NFS_MOUNT_SOFT) != 0, - (data.flags & NFS_MOUNT_INTR) != 0, - (data.flags & NFS_MOUNT_POSIX) != 0, - (data.flags & NFS_MOUNT_NOCTO) != 0, - (data.flags & NFS_MOUNT_NOAC) != 0); -#if NFS_MOUNT_VERSION >= 2 - printf("tcp = %d\n", - (data.flags & NFS_MOUNT_TCP) != 0); -#endif -#endif - - data.version = nfs_mount_version; - *mount_opts = (char *) &data; - - if (*flags & MS_REMOUNT) - return 0; - - /* - * If the previous mount operation on the same host was - * backgrounded, and the "bg" for this mount is also set, - * give up immediately, to avoid the initial timeout. - */ - if (bg && !running_bg && - prev_bg_host && strcmp(hostname, prev_bg_host) == 0) { - if (retry > 0) - retval = EX_BG; - return retval; - } - - /* create mount deamon client */ - /* See if the nfs host = mount host. */ - if (mounthost) { - if (mounthost[0] >= '0' && mounthost[0] <= '9') { - mount_server_addr.sin_family = AF_INET; - mount_server_addr.sin_addr.s_addr = inet_addr(hostname); - } else { - if ((hp = gethostbyname(mounthost)) == NULL) { - herror_msg("%s", mounthost); - goto fail; - } else { - if (hp->h_length > sizeof(struct in_addr)) { - error_msg("got bad hp->h_length?"); - hp->h_length = sizeof(struct in_addr); - } - mount_server_addr.sin_family = AF_INET; - memcpy(&mount_server_addr.sin_addr, - hp->h_addr, hp->h_length); - } - } - } - - /* - * The following loop implements the mount retries. On the first - * call, "running_bg" is 0. When the mount times out, and the - * "bg" option is set, the exit status EX_BG will be returned. - * For a backgrounded mount, there will be a second call by the - * child process with "running_bg" set to 1. - * - * The case where the mount point is not present and the "bg" - * option is set, is treated as a timeout. This is done to - * support nested mounts. - * - * The "retry" count specified by the user is the number of - * minutes to retry before giving up. - * - * Only the first error message will be displayed. - */ - retry_timeout.tv_sec = 3; - retry_timeout.tv_usec = 0; - total_timeout.tv_sec = 20; - total_timeout.tv_usec = 0; - timeout = time(NULL) + 60 * retry; - prevt = 0; - t = 30; - val = 1; - for (;;) { - if (bg && stat(node, &statbuf) == -1) { - if (running_bg) { - sleep(val); /* 1, 2, 4, 8, 16, 30, ... */ - val *= 2; - if (val > 30) - val = 30; - } - } else { - /* be careful not to use too many CPU cycles */ - if (t - prevt < 30) - sleep(30); - - pm_mnt = get_mountport(&mount_server_addr, - mountprog, - mountvers, - proto, - mountport); - - /* contact the mount daemon via TCP */ - mount_server_addr.sin_port = htons(pm_mnt->pm_port); - msock = RPC_ANYSOCK; - - switch (pm_mnt->pm_prot) { - case IPPROTO_UDP: - mclient = clntudp_create(&mount_server_addr, - pm_mnt->pm_prog, - pm_mnt->pm_vers, - retry_timeout, - &msock); - if (mclient) - break; - mount_server_addr.sin_port = htons(pm_mnt->pm_port); - msock = RPC_ANYSOCK; - case IPPROTO_TCP: - mclient = clnttcp_create(&mount_server_addr, - pm_mnt->pm_prog, - pm_mnt->pm_vers, - &msock, 0, 0); - break; - default: - mclient = 0; - } - if (mclient) { - /* try to mount hostname:pathname */ - mclient->cl_auth = authunix_create_default(); - - /* make pointers in xdr_mountres3 NULL so - * that xdr_array allocates memory for us - */ - memset(&status, 0, sizeof(status)); - - if (pm_mnt->pm_vers == 3) - clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT, - (xdrproc_t) xdr_dirpath, - (caddr_t) &pathname, - (xdrproc_t) xdr_mountres3, - (caddr_t) &status, - total_timeout); - else - clnt_stat = clnt_call(mclient, MOUNTPROC_MNT, - (xdrproc_t) xdr_dirpath, - (caddr_t) &pathname, - (xdrproc_t) xdr_fhstatus, - (caddr_t) &status, - total_timeout); - - if (clnt_stat == RPC_SUCCESS) - break; /* we're done */ - if (errno != ECONNREFUSED) { - clnt_perror(mclient, "mount"); - goto fail; /* don't retry */ - } - if (!running_bg && prevt == 0) - clnt_perror(mclient, "mount"); - auth_destroy(mclient->cl_auth); - clnt_destroy(mclient); - mclient = 0; - close(msock); - } else { - if (!running_bg && prevt == 0) - clnt_pcreateerror("mount"); - } - prevt = t; - } - if (!bg) - goto fail; - if (!running_bg) { - prev_bg_host = xstrdup(hostname); - if (retry > 0) - retval = EX_BG; - goto fail; - } - t = time(NULL); - if (t >= timeout) - goto fail; - } - nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers; - - if (nfsvers == 2) { - if (status.nfsv2.fhs_status != 0) { - error_msg("%s:%s failed, reason given by server: %s", - hostname, pathname, - nfs_strerror(status.nfsv2.fhs_status)); - goto fail; - } - memcpy(data.root.data, - (char *) status.nfsv2.fhstatus_u.fhs_fhandle, - NFS_FHSIZE); -#if NFS_MOUNT_VERSION >= 4 - data.root.size = NFS_FHSIZE; - memcpy(data.old_root.data, - (char *) status.nfsv2.fhstatus_u.fhs_fhandle, - NFS_FHSIZE); -#endif - } else { -#if NFS_MOUNT_VERSION >= 4 - fhandle3 *my_fhandle; - if (status.nfsv3.fhs_status != 0) { - error_msg("%s:%s failed, reason given by server: %s", - hostname, pathname, - nfs_strerror(status.nfsv3.fhs_status)); - goto fail; - } - my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle; - memset(data.old_root.data, 0, NFS_FHSIZE); - memset(&data.root, 0, sizeof(data.root)); - data.root.size = my_fhandle->fhandle3_len; - memcpy(data.root.data, - (char *) my_fhandle->fhandle3_val, - my_fhandle->fhandle3_len); - - data.flags |= NFS_MOUNT_VER3; -#endif - } - - /* create nfs socket for kernel */ - - if (tcp) { - if (nfs_mount_version < 3) { - printf(_("NFS over TCP is not supported.\n")); - goto fail; - } - fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - } else - fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (fsock < 0) { - perror(_("nfs socket")); - goto fail; - } - if (bindresvport(fsock, 0) < 0) { - perror(_("nfs bindresvport")); - goto fail; - } - if (port == 0) { - server_addr.sin_port = PMAPPORT; - port = pmap_getport(&server_addr, nfsprog, nfsvers, - tcp ? IPPROTO_TCP : IPPROTO_UDP); - if (port == 0) - port = NFS_PORT; -#ifdef NFS_MOUNT_DEBUG - else - printf(_("used portmapper to find NFS port\n")); -#endif - } -#ifdef NFS_MOUNT_DEBUG - printf(_("using port %d for nfs deamon\n"), port); -#endif - server_addr.sin_port = htons(port); - /* - * connect() the socket for kernels 1.3.10 and below only, - * to avoid problems with multihomed hosts. - * --Swen - */ - if (get_kernel_revision() <= 66314 - && connect(fsock, (struct sockaddr *) &server_addr, - sizeof (server_addr)) < 0) { - perror(_("nfs connect")); - goto fail; - } - - /* prepare data structure for kernel */ - - data.fd = fsock; - memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr)); - strncpy(data.hostname, hostname, sizeof(data.hostname)); - - /* clean up */ - - auth_destroy(mclient->cl_auth); - clnt_destroy(mclient); - close(msock); - return 0; - - /* abort */ - -fail: - if (msock != -1) { - if (mclient) { - auth_destroy(mclient->cl_auth); - clnt_destroy(mclient); - } - close(msock); - } - if (fsock != -1) - close(fsock); - return retval; -} - -/* - * We need to translate between nfs status return values and - * the local errno values which may not be the same. - * - * Andreas Schwab : change errno: - * "after #include the symbol errno is reserved for any use, - * it cannot even be used as a struct tag or field name". - */ - -#ifndef EDQUOT -#define EDQUOT ENOSPC -#endif - -static struct { - enum nfs_stat stat; - int errnum; -} nfs_errtbl[] = { - { NFS_OK, 0 }, - { NFSERR_PERM, EPERM }, - { NFSERR_NOENT, ENOENT }, - { NFSERR_IO, EIO }, - { NFSERR_NXIO, ENXIO }, - { NFSERR_ACCES, EACCES }, - { NFSERR_EXIST, EEXIST }, - { NFSERR_NODEV, ENODEV }, - { NFSERR_NOTDIR, ENOTDIR }, - { NFSERR_ISDIR, EISDIR }, -#ifdef NFSERR_INVAL - { NFSERR_INVAL, EINVAL }, /* that Sun forgot */ -#endif - { NFSERR_FBIG, EFBIG }, - { NFSERR_NOSPC, ENOSPC }, - { NFSERR_ROFS, EROFS }, - { NFSERR_NAMETOOLONG, ENAMETOOLONG }, - { NFSERR_NOTEMPTY, ENOTEMPTY }, - { NFSERR_DQUOT, EDQUOT }, - { NFSERR_STALE, ESTALE }, -#ifdef EWFLUSH - { NFSERR_WFLUSH, EWFLUSH }, -#endif - /* Throw in some NFSv3 values for even more fun (HP returns these) */ - { 71, EREMOTE }, - - { -1, EIO } -}; - -static char *nfs_strerror(int status) -{ - int i; - static char buf[256]; - - for (i = 0; nfs_errtbl[i].stat != -1; i++) { - if (nfs_errtbl[i].stat == status) - return strerror(nfs_errtbl[i].errnum); - } - sprintf(buf, _("unknown nfs status return value: %d"), status); - return buf; -} - -static bool_t -xdr_fhandle (XDR *xdrs, fhandle objp) -{ - //register int32_t *buf; - - if (!xdr_opaque (xdrs, objp, FHSIZE)) - return FALSE; - return TRUE; -} - -bool_t -xdr_fhstatus (XDR *xdrs, fhstatus *objp) -{ - //register int32_t *buf; - - if (!xdr_u_int (xdrs, &objp->fhs_status)) - return FALSE; - switch (objp->fhs_status) { - case 0: - if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle)) - return FALSE; - break; - default: - break; - } - return TRUE; -} - -bool_t -xdr_dirpath (XDR *xdrs, dirpath *objp) -{ - //register int32_t *buf; - - if (!xdr_string (xdrs, objp, MNTPATHLEN)) - return FALSE; - return TRUE; -} - -bool_t -xdr_fhandle3 (XDR *xdrs, fhandle3 *objp) -{ - //register int32_t *buf; - - if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp) -{ - //register int32_t *buf; - - if (!xdr_fhandle3 (xdrs, &objp->fhandle)) - return FALSE; - if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->auth_flavours.auth_flavours_len, ~0, - sizeof (int), (xdrproc_t) xdr_int)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mountstat3 (XDR *xdrs, mountstat3 *objp) -{ - //register int32_t *buf; - - if (!xdr_enum (xdrs, (enum_t *) objp)) - return FALSE; - return TRUE; -} - -bool_t -xdr_mountres3 (XDR *xdrs, mountres3 *objp) -{ - //register int32_t *buf; - - if (!xdr_mountstat3 (xdrs, &objp->fhs_status)) - return FALSE; - switch (objp->fhs_status) { - case MNT_OK: - if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo)) - return FALSE; - break; - default: - break; - } - return TRUE; -} - diff --git a/busybox/util-linux/nfsmount.h b/busybox/util-linux/nfsmount.h deleted file mode 100644 index b3d5a51e6..000000000 --- a/busybox/util-linux/nfsmount.h +++ /dev/null @@ -1,242 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * This file was originally generated using rpcgen. - * But now we edit it by hand as needed to make it - * shut up... - */ - -#ifndef _NFSMOUNT_H_RPCGEN -#define _NFSMOUNT_H_RPCGEN - -#include - - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Sun RPC is a product of Sun Microsystems, Inc. and is provided for - * unrestricted use provided that this legend is included on all tape - * media and as a part of the software program in whole or part. Users - * may copy or modify Sun RPC without charge, but are not authorized - * to license or distribute it to anyone else except as part of a product or - * program developed by the user or with the express written consent of - * Sun Microsystems, Inc. - * - * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE - * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR - * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. - * - * Sun RPC is provided with no support and without any obligation on the - * part of Sun Microsystems, Inc. to assist in its use, correction, - * modification or enhancement. - * - * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE - * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC - * OR ANY PART THEREOF. - * - * In no event will Sun Microsystems, Inc. be liable for any lost revenue - * or profits or other special, indirect and consequential damages, even if - * Sun has been advised of the possibility of such damages. - * - * Sun Microsystems, Inc. - * 2550 Garcia Avenue - * Mountain View, California 94043 - */ -/* - * Copyright (c) 1985, 1990 by Sun Microsystems, Inc. - */ - -/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */ -#ifndef _rpcsvc_mount_h -#define _rpcsvc_mount_h -#include -#define MOUNTPORT 635 -#define MNTPATHLEN 1024 -#define MNTNAMLEN 255 -#define FHSIZE 32 -#define FHSIZE3 64 - -typedef char fhandle[FHSIZE]; - -typedef struct { - u_int fhandle3_len; - char *fhandle3_val; -} fhandle3; - -enum mountstat3 { - MNT_OK = 0, - MNT3ERR_PERM = 1, - MNT3ERR_NOENT = 2, - MNT3ERR_IO = 5, - MNT3ERR_ACCES = 13, - MNT3ERR_NOTDIR = 20, - MNT3ERR_INVAL = 22, - MNT3ERR_NAMETOOLONG = 63, - MNT3ERR_NOTSUPP = 10004, - MNT3ERR_SERVERFAULT = 10006, -}; -typedef enum mountstat3 mountstat3; - -struct fhstatus { - u_int fhs_status; - union { - fhandle fhs_fhandle; - } fhstatus_u; -}; -typedef struct fhstatus fhstatus; - -struct mountres3_ok { - fhandle3 fhandle; - struct { - u_int auth_flavours_len; - int *auth_flavours_val; - } auth_flavours; -}; -typedef struct mountres3_ok mountres3_ok; - -struct mountres3 { - mountstat3 fhs_status; - union { - mountres3_ok mountinfo; - } mountres3_u; -}; -typedef struct mountres3 mountres3; - -typedef char *dirpath; - -typedef char *name; - -typedef struct mountbody *mountlist; - -struct mountbody { - name ml_hostname; - dirpath ml_directory; - mountlist ml_next; -}; -typedef struct mountbody mountbody; - -typedef struct groupnode *groups; - -struct groupnode { - name gr_name; - groups gr_next; -}; -typedef struct groupnode groupnode; - -typedef struct exportnode *exports; - -struct exportnode { - dirpath ex_dir; - groups ex_groups; - exports ex_next; -}; -typedef struct exportnode exportnode; - -struct ppathcnf { - int pc_link_max; - short pc_max_canon; - short pc_max_input; - short pc_name_max; - short pc_path_max; - short pc_pipe_buf; - u_char pc_vdisable; - char pc_xxx; - short pc_mask[2]; -}; -typedef struct ppathcnf ppathcnf; -#endif /*!_rpcsvc_mount_h*/ - -#define MOUNTPROG 100005 -#define MOUNTVERS 1 - -#define MOUNTPROC_NULL 0 -extern void * mountproc_null_1(void *, CLIENT *); -extern void * mountproc_null_1_svc(void *, struct svc_req *); -#define MOUNTPROC_MNT 1 -extern fhstatus * mountproc_mnt_1(dirpath *, CLIENT *); -extern fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *); -#define MOUNTPROC_DUMP 2 -extern mountlist * mountproc_dump_1(void *, CLIENT *); -extern mountlist * mountproc_dump_1_svc(void *, struct svc_req *); -#define MOUNTPROC_UMNT 3 -extern void * mountproc_umnt_1(dirpath *, CLIENT *); -extern void * mountproc_umnt_1_svc(dirpath *, struct svc_req *); -#define MOUNTPROC_UMNTALL 4 -extern void * mountproc_umntall_1(void *, CLIENT *); -extern void * mountproc_umntall_1_svc(void *, struct svc_req *); -#define MOUNTPROC_EXPORT 5 -extern exports * mountproc_export_1(void *, CLIENT *); -extern exports * mountproc_export_1_svc(void *, struct svc_req *); -#define MOUNTPROC_EXPORTALL 6 -extern exports * mountproc_exportall_1(void *, CLIENT *); -extern exports * mountproc_exportall_1_svc(void *, struct svc_req *); -extern int mountprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); - -#define MOUNTVERS_POSIX 2 - -extern void * mountproc_null_2(void *, CLIENT *); -extern void * mountproc_null_2_svc(void *, struct svc_req *); -extern fhstatus * mountproc_mnt_2(dirpath *, CLIENT *); -extern fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *); -extern mountlist * mountproc_dump_2(void *, CLIENT *); -extern mountlist * mountproc_dump_2_svc(void *, struct svc_req *); -extern void * mountproc_umnt_2(dirpath *, CLIENT *); -extern void * mountproc_umnt_2_svc(dirpath *, struct svc_req *); -extern void * mountproc_umntall_2(void *, CLIENT *); -extern void * mountproc_umntall_2_svc(void *, struct svc_req *); -extern exports * mountproc_export_2(void *, CLIENT *); -extern exports * mountproc_export_2_svc(void *, struct svc_req *); -extern exports * mountproc_exportall_2(void *, CLIENT *); -extern exports * mountproc_exportall_2_svc(void *, struct svc_req *); -#define MOUNTPROC_PATHCONF 7 -extern ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *); -extern ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *); -extern int mountprog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t); - -#define MOUNT_V3 3 - -#define MOUNTPROC3_NULL 0 -extern void * mountproc3_null_3(void *, CLIENT *); -extern void * mountproc3_null_3_svc(void *, struct svc_req *); -#define MOUNTPROC3_MNT 1 -extern mountres3 * mountproc3_mnt_3(dirpath *, CLIENT *); -extern mountres3 * mountproc3_mnt_3_svc(dirpath *, struct svc_req *); -#define MOUNTPROC3_DUMP 2 -extern mountlist * mountproc3_dump_3(void *, CLIENT *); -extern mountlist * mountproc3_dump_3_svc(void *, struct svc_req *); -#define MOUNTPROC3_UMNT 3 -extern void * mountproc3_umnt_3(dirpath *, CLIENT *); -extern void * mountproc3_umnt_3_svc(dirpath *, struct svc_req *); -#define MOUNTPROC3_UMNTALL 4 -extern void * mountproc3_umntall_3(void *, CLIENT *); -extern void * mountproc3_umntall_3_svc(void *, struct svc_req *); -#define MOUNTPROC3_EXPORT 5 -extern exports * mountproc3_export_3(void *, CLIENT *); -extern exports * mountproc3_export_3_svc(void *, struct svc_req *); -extern int mountprog_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t); - -/* the xdr functions */ - -static bool_t xdr_fhandle (XDR *, fhandle); -extern bool_t xdr_fhandle3 (XDR *, fhandle3*); -extern bool_t xdr_mountstat3 (XDR *, mountstat3*); -extern bool_t xdr_fhstatus (XDR *, fhstatus*); -extern bool_t xdr_mountres3_ok (XDR *, mountres3_ok*); -extern bool_t xdr_mountres3 (XDR *, mountres3*); -extern bool_t xdr_dirpath (XDR *, dirpath*); -extern bool_t xdr_name (XDR *, name*); -extern bool_t xdr_mountlist (XDR *, mountlist*); -extern bool_t xdr_mountbody (XDR *, mountbody*); -extern bool_t xdr_groups (XDR *, groups*); -extern bool_t xdr_groupnode (XDR *, groupnode*); -extern bool_t xdr_exports (XDR *, exports*); -extern bool_t xdr_exportnode (XDR *, exportnode*); -extern bool_t xdr_ppathcnf (XDR *, ppathcnf*); - -#ifdef __cplusplus -} -#endif - -#endif /* !_NFSMOUNT_H_RPCGEN */ diff --git a/busybox/util-linux/pivot_root.c b/busybox/util-linux/pivot_root.c deleted file mode 100644 index ba26b9c58..000000000 --- a/busybox/util-linux/pivot_root.c +++ /dev/null @@ -1,35 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * pivot_root.c - Change root file system. Based on util-linux 2.10s - * - * busyboxed by Evin Robertson - * pivot_root syscall stubbed by Erik Andersen, so it will compile - * regardless of the kernel being used. - */ -#include -#include -#include -#include "busybox.h" - -extern int pivot_root(const char * new_root,const char * put_old); - -int pivot_root_main(int argc, char **argv) -{ - if (argc != 3) - show_usage(); - - if (pivot_root(argv[1],argv[2]) < 0) - perror_msg_and_die("pivot_root"); - - return EXIT_SUCCESS; - -} - - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/util-linux/rdate.c b/busybox/util-linux/rdate.c deleted file mode 100644 index 50be4de8c..000000000 --- a/busybox/util-linux/rdate.c +++ /dev/null @@ -1,116 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * The Rdate command will ask a time server for the RFC 868 time - * and optionally set the system time. - * - * by Sterling Huxley - * - * 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 -#include -#include "busybox.h" - - -static const int RFC_868_BIAS = 2208988800UL; - -static time_t askremotedate(const char *host) -{ - struct hostent *h; - struct sockaddr_in s_in; - struct servent *tserv; - unsigned long int nett, localt; - int fd; - - h = xgethostbyname(host); /* get the IP addr */ - - if ((tserv = getservbyname("time", "tcp")) == NULL) /* find port # */ - perror_msg_and_die("time"); - - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) /* get net connection */ - perror_msg_and_die("socket"); - - memcpy(&s_in.sin_addr, h->h_addr, sizeof(s_in.sin_addr)); - s_in.sin_port= tserv->s_port; - s_in.sin_family = AF_INET; - - if (connect(fd, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) /* connect to time server */ - perror_msg_and_die("%s", host); - - if (read(fd, (void *)&nett, 4) != 4) /* read time from server */ - error_msg_and_die("%s did not send the complete time", host); - - close(fd); - - /* convert from network byte order to local byte order. - * RFC 868 time is the number of seconds - * since 00:00 (midnight) 1 January 1900 GMT - * the RFC 868 time 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT - * Subtract the RFC 868 time to get Linux epoch - */ - localt= ntohl(nett) - RFC_868_BIAS; - - return(localt); -} - -int rdate_main(int argc, char **argv) -{ - time_t remote_time; - int opt; - int setdate = 1; - int printdate = 1; - - /* Interpret command line args */ - while ((opt = getopt(argc, argv, "sp")) > 0) { - switch (opt) { - case 's': - printdate = 0; - setdate = 1; - break; - case 'p': - printdate = 1; - setdate = 0; - break; - default: - show_usage(); - } - } - - if (optind == argc) - show_usage(); - - remote_time = askremotedate(argv[optind]); - - if (setdate) { - if (stime(&remote_time) < 0) - perror_msg_and_die("Could not set time of day"); - } - - if (printdate) - printf("%s", ctime(&remote_time)); - - return EXIT_SUCCESS; -} diff --git a/busybox/util-linux/swaponoff.c b/busybox/util-linux/swaponoff.c deleted file mode 100644 index ce0e2c6cc..000000000 --- a/busybox/util-linux/swaponoff.c +++ /dev/null @@ -1,115 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini swapon/swapoff implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#if __GNU_LIBRARY__ < 5 -/* libc5 doesn't have sys/swap.h, define these here. */ -extern int swapon (__const char *__path, int __flags); -extern int swapoff (__const char *__path); -#else -#include -#endif - -#include "busybox.h" - -static int whichApp; - -static const int SWAPON_APP = 1; -static const int SWAPOFF_APP = 2; - - -static void swap_enable_disable(char *device) -{ - int status; - - if (whichApp == SWAPON_APP) - status = swapon(device, 0); - else - status = swapoff(device); - - if (status != 0) - perror_msg_and_die(applet_name); -} - -static void do_em_all() -{ - struct mntent *m; - FILE *f = setmntent("/etc/fstab", "r"); - - if (f == NULL) - perror_msg_and_die("/etc/fstab"); - while ((m = getmntent(f)) != NULL) { - if (strcmp(m->mnt_type, MNTTYPE_SWAP)==0) { - swap_enable_disable(m->mnt_fsname); - } - } - endmntent(f); - exit(EXIT_SUCCESS); -} - - -extern int swap_on_off_main(int argc, char **argv) -{ - if (strcmp(applet_name, "swapon") == 0) { - whichApp = SWAPON_APP; - } else { - whichApp = SWAPOFF_APP; - } - - if (argc != 2) { - goto usage_and_exit; - } - argc--; - argv++; - - /* Parse any options */ - while (**argv == '-') { - while (*++(*argv)) - switch (**argv) { - case 'a': - { - struct stat statBuf; - - if (stat("/etc/fstab", &statBuf) < 0) - error_msg_and_die("/etc/fstab file missing"); - } - do_em_all(); - break; - default: - goto usage_and_exit; - } - } - swap_enable_disable(*argv); - return EXIT_SUCCESS; - - usage_and_exit: - show_usage(); -} diff --git a/busybox/util-linux/umount.c b/busybox/util-linux/umount.c deleted file mode 100644 index 74638d21c..000000000 --- a/busybox/util-linux/umount.c +++ /dev/null @@ -1,298 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini umount implementation for busybox - * - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -/* Teach libc5 about realpath -- it includes it but the - * prototype is missing... */ -#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1) -extern char *realpath(const char *path, char *resolved_path); -#endif - -static const int MNT_FORCE = 1; -static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */ -static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS. */ -static const int MS_RDONLY = 1; /* Mount read-only. */ - -extern int mount (__const char *__special_file, __const char *__dir, - __const char *__fstype, unsigned long int __rwflag, - __const void *__data); -extern int umount (__const char *__special_file); -extern int umount2 (__const char *__special_file, int __flags); - -struct _mtab_entry_t { - char *device; - char *mountpt; - struct _mtab_entry_t *next; -}; - -static struct _mtab_entry_t *mtab_cache = NULL; - - - -#if defined BB_FEATURE_MOUNT_FORCE -static int doForce = FALSE; -#endif -#if defined BB_FEATURE_MOUNT_LOOP -static int freeLoop = TRUE; -#endif -#if defined BB_FEATURE_MTAB_SUPPORT -static int useMtab = TRUE; -#endif -static int umountAll = FALSE; -static int doRemount = FALSE; -extern const char mtab_file[]; /* Defined in utility.c */ - - - -/* These functions are here because the getmntent functions do not appear - * to be re-entrant, which leads to all sorts of problems when we try to - * use them recursively - randolph - * - * TODO: Perhaps switch to using Glibc's getmntent_r - * -Erik - */ -static void mtab_read(void) -{ - struct _mtab_entry_t *entry = NULL; - struct mntent *e; - FILE *fp; - - if (mtab_cache != NULL) - return; - - if ((fp = setmntent(mtab_file, "r")) == NULL) { - error_msg("Cannot open %s", mtab_file); - return; - } - while ((e = getmntent(fp))) { - entry = xmalloc(sizeof(struct _mtab_entry_t)); - entry->device = strdup(e->mnt_fsname); - entry->mountpt = strdup(e->mnt_dir); - entry->next = mtab_cache; - mtab_cache = entry; - } - endmntent(fp); -} - -static char *mtab_getinfo(const char *match, const char which) -{ - struct _mtab_entry_t *cur = mtab_cache; - - while (cur) { - if (strcmp(cur->mountpt, match) == 0 || - strcmp(cur->device, match) == 0) { - if (which == MTAB_GETMOUNTPT) { - return cur->mountpt; - } else { -#if !defined BB_FEATURE_MTAB_SUPPORT - if (strcmp(cur->device, "/dev/root") == 0) { - /* Adjusts device to be the real root device, - * or leaves device alone if it can't find it */ - cur->device = find_real_root_device_name(cur->device); - } -#endif - return cur->device; - } - } - cur = cur->next; - } - return NULL; -} - -static char *mtab_next(void **iter) -{ - char *mp; - - if (iter == NULL || *iter == NULL) - return NULL; - mp = ((struct _mtab_entry_t *) (*iter))->mountpt; - *iter = (void *) ((struct _mtab_entry_t *) (*iter))->next; - return mp; -} - -static char *mtab_first(void **iter) -{ - struct _mtab_entry_t *mtab_iter; - - if (!iter) - return NULL; - mtab_iter = mtab_cache; - *iter = (void *) mtab_iter; - return mtab_next(iter); -} - -/* Don't bother to clean up, since exit() does that - * automagically, so we can save a few bytes */ -#ifdef BB_FEATURE_CLEAN_UP -static void mtab_free(void) -{ - struct _mtab_entry_t *this, *next; - - this = mtab_cache; - while (this) { - next = this->next; - if (this->device) - free(this->device); - if (this->mountpt) - free(this->mountpt); - free(this); - this = next; - } -} -#endif - -static int do_umount(const char *name) -{ - int status; - char *blockDevice = mtab_getinfo(name, MTAB_GETDEVICE); - - if (blockDevice && strcmp(blockDevice, name) == 0) - name = mtab_getinfo(blockDevice, MTAB_GETMOUNTPT); - - status = umount(name); - -#if defined BB_FEATURE_MOUNT_LOOP - if (freeLoop == TRUE && blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9)) - /* this was a loop device, delete it */ - del_loop(blockDevice); -#endif -#if defined BB_FEATURE_MOUNT_FORCE - if (status != 0 && doForce == TRUE) { - status = umount2(blockDevice, MNT_FORCE); - if (status != 0) { - error_msg_and_die("forced umount of %s failed!", blockDevice); - } - } -#endif - if (status != 0 && doRemount == TRUE && errno == EBUSY) { - status = mount(blockDevice, name, NULL, - MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL); - if (status == 0) { - error_msg("%s busy - remounted read-only", blockDevice); - } else { - error_msg("Cannot remount %s read-only", blockDevice); - } - } - if (status == 0) { -#if defined BB_FEATURE_MTAB_SUPPORT - if (useMtab == TRUE) - erase_mtab(name); -#endif - return (TRUE); - } - return (FALSE); -} - -static int umount_all(void) -{ - int status = TRUE; - char *mountpt; - void *iter; - - for (mountpt = mtab_first(&iter); mountpt; mountpt = mtab_next(&iter)) { - /* Never umount /proc on a umount -a */ - if (strstr(mountpt, "proc")!= NULL) - continue; - if (!do_umount(mountpt)) { - /* Don't bother retrying the umount on busy devices */ - if (errno == EBUSY) { - perror_msg("%s", mountpt); - status = FALSE; - continue; - } - if (!do_umount(mountpt)) { - printf("Couldn't umount %s on %s: %s\n", - mountpt, mtab_getinfo(mountpt, MTAB_GETDEVICE), - strerror(errno)); - status = FALSE; - } - } - } - return (status); -} - -extern int umount_main(int argc, char **argv) -{ - char path[PATH_MAX]; - - if (argc < 2) { - show_usage(); - } -#ifdef BB_FEATURE_CLEAN_UP - atexit(mtab_free); -#endif - - /* Parse any options */ - while (--argc > 0 && **(++argv) == '-') { - while (*++(*argv)) - switch (**argv) { - case 'a': - umountAll = TRUE; - break; -#if defined BB_FEATURE_MOUNT_LOOP - case 'l': - freeLoop = FALSE; - break; -#endif -#ifdef BB_FEATURE_MTAB_SUPPORT - case 'n': - useMtab = FALSE; - break; -#endif -#ifdef BB_FEATURE_MOUNT_FORCE - case 'f': - doForce = TRUE; - break; -#endif - case 'r': - doRemount = TRUE; - break; - case 'v': - break; /* ignore -v */ - default: - show_usage(); - } - } - - mtab_read(); - if (umountAll == TRUE) { - if (umount_all() == TRUE) - return EXIT_SUCCESS; - else - return EXIT_FAILURE; - } - if (realpath(*argv, path) == NULL) - perror_msg_and_die("%s", path); - if (do_umount(path) == TRUE) - return EXIT_SUCCESS; - perror_msg_and_die("%s", *argv); -} - diff --git a/busybox/uudecode.c b/busybox/uudecode.c deleted file mode 100644 index a4059ddfe..000000000 --- a/busybox/uudecode.c +++ /dev/null @@ -1,353 +0,0 @@ -/* uudecode.c -- uudecode utility. - * Copyright (C) 1994, 1995 Free Software Foundation, Inc. - * - * 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. - * - * 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. - * - * 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. - */ - - - -#include -#include -#include -#include -#include -#include "busybox.h" -#include "pwd_grp/pwd.h" -#include "pwd_grp/grp.h" - -/*struct passwd *getpwnam();*/ - -/* Single character decode. */ -#define DEC(Char) (((Char) - ' ') & 077) - -static int read_stduu (const char *inname) -{ - char buf[2 * BUFSIZ]; - - while (1) { - int n; - char *p; - - if (fgets (buf, sizeof(buf), stdin) == NULL) { - 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")) { - error_msg("%s: No `end' line", inname); - return FALSE; - } - - return TRUE; -} - -static int read_base64 (const char *inname) -{ - 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) { - error_msg("%s: Short file", inname); - return FALSE; - } - p = buf; - - if (memcmp (buf, "====", 4) == 0) - break; - if (last_data != 0) { - 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++ == '=') { - error_msg("%s: illegal line", inname); - return FALSE; - } - c2 = b64_tab[*p++]; - - while (b64_tab[*p] == '\177') - if (*p++ == '\n') { - 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') { - 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; -} - -static int decode (const char *inname, - const char *forced_outname) -{ - 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) { - 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') { - error_msg("%s: Illegal ~user", inname); - return FALSE; - } - *p++ = '\0'; - pw = getpwnam (buf + 1); - if (pw == NULL) { - 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)) - )) { - 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: - 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 { - perror_msg("%s", argv[optind]); - exit_status = EXIT_FAILURE; - } - optind++; - } - while (optind < argc); - } - return(exit_status); -} - -/* 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. - */ - - diff --git a/busybox/uuencode.c b/busybox/uuencode.c deleted file mode 100644 index fc037403a..000000000 --- a/busybox/uuencode.c +++ /dev/null @@ -1,180 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Copyright (C) 2000 by Glenn McGrath - * - * 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. - */ -#include -#include -#include -#include -#include -#include -#include "busybox.h" - -/* Conversion table. for base 64 */ -static char tbl_base64[64] = { - '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', '+', '/' -}; - -static char tbl_std[64] = { - '`', '!', '"', '#', '$', '%', '&', '\'', - '(', ')', '*', '+', ',', '-', '.', '/', - '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', '[', '\\', ']', '^', '_' -}; - -/* - * 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) = '='; - } - else if (i == length + 2) { - *(p - 1) = *(p - 2) = '='; - } - /* ...and zero-terminate it. */ - *p = '\0'; -} - -int uuencode_main(int argc, char **argv) -{ - const int src_buf_size = 60; // This *MUST* be a multiple of 3 - const int dst_buf_size = 4 * ((src_buf_size + 2) / 3); - RESERVE_BB_BUFFER(src_buf, src_buf_size + 1); - RESERVE_BB_BUFFER(dst_buf, dst_buf_size + 1); - struct stat stat_buf; - FILE *src_stream = stdin; - char *tbl = tbl_std; - size_t size; - mode_t mode; - int opt; - int column = 0; - int write_size = 0; - int remaining; - int buffer_offset = 0; - - while ((opt = getopt(argc, argv, "m")) != -1) { - switch (opt) { - case 'm': - tbl = tbl_base64; - break; - default: - show_usage(); - } - } - - switch (argc - optind) { - case 2: - src_stream = xfopen(argv[optind], "r"); - stat(argv[optind], &stat_buf); - mode = stat_buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); - if (src_stream == stdout) { - printf("NULL\n"); - } - break; - case 1: - mode = 0666 & ~umask(0666); - break; - default: - show_usage(); - } - - 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) { - /* Encode the buffer we just read in */ - uuencode(src_buf, dst_buf, size, tbl); - - /* Write the buffer to stdout, wrapping at 60 chars. - * This looks overly complex, but it gets tricky as - * the line has to continue to wrap correctly if we - * have to refill the buffer - * - * Improvments most welcome - */ - - /* Initialise values for the new buffer */ - remaining = 4 * ((size + 2) / 3); - buffer_offset = 0; - - /* Write the buffer to stdout, wrapping at 60 chars - * starting from the column the last buffer ran out - */ - do { - if (remaining > (60 - column)) { - write_size = 60 - column; - } - else if (remaining < 60) { - write_size = remaining; - } else { - write_size = 60; - } - - /* Setup a new row if required */ - if (column == 0) { - putchar('\n'); - if (tbl == tbl_std) { - putchar('M'); - } - } - /* Write to the 60th column */ - if (fwrite(&dst_buf[buffer_offset], 1, write_size, stdout) != write_size) { - perror("Couldnt finish writing"); - } - /* Update variables based on last write */ - buffer_offset += write_size; - remaining -= write_size; - column += write_size; - if (column % 60 == 0) { - column = 0; - } - } while (remaining > 0); - } - printf(tbl == tbl_std ? "\n`\nend\n" : "\n====\n"); - - return(EXIT_SUCCESS); -} diff --git a/busybox/vi.c b/busybox/vi.c deleted file mode 100644 index 8d7506d0f..000000000 --- a/busybox/vi.c +++ /dev/null @@ -1,3947 +0,0 @@ -/* vi: set sw=8 ts=8: */ -/* - * tiny vi.c: A small 'vi' clone - * Copyright (C) 2000, 2001 Sterling Huxley - * - * 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. - */ - -static const char vi_Version[] = - "$Id: vi.c,v 1.15 2001/08/02 05:26:41 andersen Exp $"; - -/* - * To compile for standalone use: - * gcc -Wall -Os -s -DSTANDALONE -o vi vi.c - * or - * gcc -Wall -Os -s -DSTANDALONE -DBB_FEATURE_VI_CRASHME -o vi vi.c # include testing features - * strip vi - */ - -/* - * Things To Do: - * EXINIT - * $HOME/.exrc and ./.exrc - * add magic to search /foo.*bar - * add :help command - * :map macros - * how about mode lines: vi: set sw=8 ts=8: - * if mark[] values were line numbers rather than pointers - * it would be easier to change the mark when add/delete lines - * More intelligence in refresh() - * ":r !cmd" and "!cmd" to filter text through an external command - * A true "undo" facility - * An "ex" line oriented mode- maybe using "cmdedit" - */ - -//---- Feature -------------- Bytes to immplement -#ifdef STANDALONE -#define vi_main main -#define BB_FEATURE_VI_COLON // 4288 -#define BB_FEATURE_VI_YANKMARK // 1408 -#define BB_FEATURE_VI_SEARCH // 1088 -#define BB_FEATURE_VI_USE_SIGNALS // 1056 -#define BB_FEATURE_VI_DOT_CMD // 576 -#define BB_FEATURE_VI_READONLY // 128 -#define BB_FEATURE_VI_SETOPTS // 576 -#define BB_FEATURE_VI_SET // 224 -#define BB_FEATURE_VI_WIN_RESIZE // 256 WIN_RESIZE -// To test editor using CRASHME: -// vi -C filename -// To stop testing, wait until all to text[] is deleted, or -// Ctrl-Z and kill -9 %1 -// while in the editor Ctrl-T will toggle the crashme function on and off. -//#define BB_FEATURE_VI_CRASHME // randomly pick commands to execute -#endif /* STANDALONE */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef STANDALONE -#include "busybox.h" -#endif /* STANDALONE */ - -#ifndef TRUE -#define TRUE ((int)1) -#define FALSE ((int)0) -#endif /* TRUE */ -#define MAX_SCR_COLS BUFSIZ - -// Misc. non-Ascii keys that report an escape sequence -#define VI_K_UP 128 // cursor key Up -#define VI_K_DOWN 129 // cursor key Down -#define VI_K_RIGHT 130 // Cursor Key Right -#define VI_K_LEFT 131 // cursor key Left -#define VI_K_HOME 132 // Cursor Key Home -#define VI_K_END 133 // Cursor Key End -#define VI_K_INSERT 134 // Cursor Key Insert -#define VI_K_PAGEUP 135 // Cursor Key Page Up -#define VI_K_PAGEDOWN 136 // Cursor Key Page Down -#define VI_K_FUN1 137 // Function Key F1 -#define VI_K_FUN2 138 // Function Key F2 -#define VI_K_FUN3 139 // Function Key F3 -#define VI_K_FUN4 140 // Function Key F4 -#define VI_K_FUN5 141 // Function Key F5 -#define VI_K_FUN6 142 // Function Key F6 -#define VI_K_FUN7 143 // Function Key F7 -#define VI_K_FUN8 144 // Function Key F8 -#define VI_K_FUN9 145 // Function Key F9 -#define VI_K_FUN10 146 // Function Key F10 -#define VI_K_FUN11 147 // Function Key F11 -#define VI_K_FUN12 148 // Function Key F12 - -static const int YANKONLY = FALSE; -static const int YANKDEL = TRUE; -static const int FORWARD = 1; // code depends on "1" for array index -static const int BACK = -1; // code depends on "-1" for array index -static const int LIMITED = 0; // how much of text[] in char_search -static const int FULL = 1; // how much of text[] in char_search - -static const int S_BEFORE_WS = 1; // used in skip_thing() for moving "dot" -static const int S_TO_WS = 2; // used in skip_thing() for moving "dot" -static const int S_OVER_WS = 3; // used in skip_thing() for moving "dot" -static const int S_END_PUNCT = 4; // used in skip_thing() for moving "dot" -static const int S_END_ALNUM = 5; // used in skip_thing() for moving "dot" - -typedef unsigned char Byte; - - -static int editing; // >0 while we are editing a file -static int cmd_mode; // 0=command 1=insert -static int file_modified; // buffer contents changed -static int err_method; // indicate error with beep or flash -static int fn_start; // index of first cmd line file name -static int save_argc; // how many file names on cmd line -static int cmdcnt; // repetition count -static fd_set rfds; // use select() for small sleeps -static struct timeval tv; // use select() for small sleeps -static char erase_char; // the users erase character -static int rows, columns; // the terminal screen is this size -static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset -static char *SOs, *SOn; // terminal standout start/normal ESC sequence -static char *bell; // terminal bell sequence -static char *Ceol, *Ceos; // Clear-end-of-line and Clear-end-of-screen ESC sequence -static char *CMrc; // Cursor motion arbitrary destination ESC sequence -static char *CMup, *CMdown; // Cursor motion up and down ESC sequence -static Byte *status_buffer; // mesages to the user -static Byte last_input_char; // last char read from user -static Byte last_forward_char; // last char searched for with 'f' -static Byte *cfn; // previous, current, and next file name -static Byte *text, *end, *textend; // pointers to the user data in memory -static Byte *screen; // pointer to the virtual screen buffer -static int screensize; // and its size -static Byte *screenbegin; // index into text[], of top line on the screen -static Byte *dot; // where all the action takes place -static int tabstop; -static struct termios term_orig, term_vi; // remember what the cooked mode was - -#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR -static int last_row; // where the cursor was last moved to -#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ -#ifdef BB_FEATURE_VI_USE_SIGNALS -static jmp_buf restart; // catch_sig() -#endif /* BB_FEATURE_VI_USE_SIGNALS */ -#ifdef BB_FEATURE_VI_WIN_RESIZE -static struct winsize winsize; // remember the window size -#endif /* BB_FEATURE_VI_WIN_RESIZE */ -#ifdef BB_FEATURE_VI_DOT_CMD -static int adding2q; // are we currently adding user input to q -static Byte *last_modifying_cmd; // last modifying cmd for "." -static Byte *ioq, *ioq_start; // pointer to string for get_one_char to "read" -#endif /* BB_FEATURE_VI_DOT_CMD */ -#if defined(BB_FEATURE_VI_DOT_CMD) || defined(BB_FEATURE_VI_YANKMARK) -static Byte *modifying_cmds; // cmds that modify text[] -#endif /* BB_FEATURE_VI_DOT_CMD || BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_READONLY -static int vi_readonly, readonly; -#endif /* BB_FEATURE_VI_READONLY */ -#ifdef BB_FEATURE_VI_SETOPTS -static int autoindent; -static int showmatch; -static int ignorecase; -#endif /* BB_FEATURE_VI_SETOPTS */ -#ifdef BB_FEATURE_VI_YANKMARK -static Byte *reg[28]; // named register a-z, "D", and "U" 0-25,26,27 -static int YDreg, Ureg; // default delete register and orig line for "U" -static Byte *mark[28]; // user marks points somewhere in text[]- a-z and previous context '' -static Byte *context_start, *context_end; -#endif /* BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_SEARCH -static Byte *last_search_pattern; // last pattern from a '/' or '?' search -#endif /* BB_FEATURE_VI_SEARCH */ - - -static void edit_file(Byte *); // edit one file -static void do_cmd(Byte); // execute a command -static void sync_cursor(Byte *, int *, int *); // synchronize the screen cursor to dot -static Byte *begin_line(Byte *); // return pointer to cur line B-o-l -static Byte *end_line(Byte *); // return pointer to cur line E-o-l -static Byte *dollar_line(Byte *); // return pointer to just before NL -static Byte *prev_line(Byte *); // return pointer to prev line B-o-l -static Byte *next_line(Byte *); // return pointer to next line B-o-l -static Byte *end_screen(void); // get pointer to last char on screen -static int count_lines(Byte *, Byte *); // count line from start to stop -static Byte *find_line(int); // find begining of line #li -static Byte *move_to_col(Byte *, int); // move "p" to column l -static int isblnk(Byte); // is the char a blank or tab -static void dot_left(void); // move dot left- dont leave line -static void dot_right(void); // move dot right- dont leave line -static void dot_begin(void); // move dot to B-o-l -static void dot_end(void); // move dot to E-o-l -static void dot_next(void); // move dot to next line B-o-l -static void dot_prev(void); // move dot to prev line B-o-l -static void dot_scroll(int, int); // move the screen up or down -static void dot_skip_over_ws(void); // move dot pat WS -static void dot_delete(void); // delete the char at 'dot' -static Byte *bound_dot(Byte *); // make sure text[0] <= P < "end" -static Byte *new_screen(int, int); // malloc virtual screen memory -static Byte *new_text(int); // malloc memory for text[] buffer -static Byte *char_insert(Byte *, Byte); // insert the char c at 'p' -static Byte *stupid_insert(Byte *, Byte); // stupidly insert the char c at 'p' -static Byte find_range(Byte **, Byte **, Byte); // return pointers for an object -static int st_test(Byte *, int, int, Byte *); // helper for skip_thing() -static Byte *skip_thing(Byte *, int, int, int); // skip some object -static Byte *find_pair(Byte *, Byte); // find matching pair () [] {} -static Byte *text_hole_delete(Byte *, Byte *); // at "p", delete a 'size' byte hole -static Byte *text_hole_make(Byte *, int); // at "p", make a 'size' byte hole -static Byte *yank_delete(Byte *, Byte *, int, int); // yank text[] into register then delete -static void show_help(void); // display some help info -static void print_literal(Byte *, Byte *); // copy s to buf, convert unprintable -static void rawmode(void); // set "raw" mode on tty -static void cookmode(void); // return to "cooked" mode on tty -static int mysleep(int); // sleep for 'h' 1/100 seconds -static Byte readit(void); // read (maybe cursor) key from stdin -static Byte get_one_char(void); // read 1 char from stdin -static int file_size(Byte *); // what is the byte size of "fn" -static int file_insert(Byte *, Byte *, int); -static int file_write(Byte *, Byte *, Byte *); -static void place_cursor(int, int, int); -static void screen_erase(); -static void clear_to_eol(void); -static void clear_to_eos(void); -static void standout_start(void); // send "start reverse video" sequence -static void standout_end(void); // send "end reverse video" sequence -static void flash(int); // flash the terminal screen -static void beep(void); // beep the terminal -static void indicate_error(char); // use flash or beep to indicate error -static void show_status_line(void); // put a message on the bottom line -static void psb(char *, ...); // Print Status Buf -static void psbs(char *, ...); // Print Status Buf in standout mode -static void ni(Byte *); // display messages -static void edit_status(void); // show file status on status line -static void redraw(int); // force a full screen refresh -static void format_line(Byte*, Byte*, int); -static void refresh(int); // update the terminal from screen[] - -#ifdef BB_FEATURE_VI_SEARCH -static Byte *char_search(Byte *, Byte *, int, int); // search for pattern starting at p -static int mycmp(Byte *, Byte *, int); // string cmp based in "ignorecase" -#endif /* BB_FEATURE_VI_SEARCH */ -#ifdef BB_FEATURE_VI_COLON -static void Hit_Return(void); -static Byte *get_one_address(Byte *, int *); // get colon addr, if present -static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present -static void colon(Byte *); // execute the "colon" mode cmds -#endif /* BB_FEATURE_VI_COLON */ -static Byte *get_input_line(Byte *); // get input line- use "status line" -#ifdef BB_FEATURE_VI_USE_SIGNALS -static void winch_sig(int); // catch window size changes -static void suspend_sig(int); // catch ctrl-Z -static void alarm_sig(int); // catch alarm time-outs -static void catch_sig(int); // catch ctrl-C -static void core_sig(int); // catch a core dump signal -#endif /* BB_FEATURE_VI_USE_SIGNALS */ -#ifdef BB_FEATURE_VI_DOT_CMD -static void start_new_cmd_q(Byte); // new queue for command -static void end_cmd_q(); // stop saving input chars -#else /* BB_FEATURE_VI_DOT_CMD */ -#define end_cmd_q() -#endif /* BB_FEATURE_VI_DOT_CMD */ -#ifdef BB_FEATURE_VI_WIN_RESIZE -static void window_size_get(int); // find out what size the window is -#endif /* BB_FEATURE_VI_WIN_RESIZE */ -#ifdef BB_FEATURE_VI_SETOPTS -static void showmatching(Byte *); // show the matching pair () [] {} -#endif /* BB_FEATURE_VI_SETOPTS */ -#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME) -static Byte *string_insert(Byte *, Byte *); // insert the string at 'p' -#endif /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */ -#ifdef BB_FEATURE_VI_YANKMARK -static Byte *text_yank(Byte *, Byte *, int); // save copy of "p" into a register -static Byte what_reg(void); // what is letter of current YDreg -static void check_context(Byte); // remember context for '' command -static Byte *swap_context(Byte *); // goto new context for '' command -#endif /* BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_CRASHME -static void crash_dummy(); -static void crash_test(); -static int crashme = 0; -#endif /* BB_FEATURE_VI_CRASHME */ - - -extern int vi_main(int argc, char **argv) -{ - int c; - -#ifdef BB_FEATURE_VI_YANKMARK - int i; -#endif /* BB_FEATURE_VI_YANKMARK */ - - CMrc= "\033[%d;%dH"; // Terminal Crusor motion ESC sequence - CMup= "\033[A"; // move cursor up one line, same col - CMdown="\n"; // move cursor down one line, same col - Ceol= "\033[0K"; // Clear from cursor to end of line - Ceos= "\033[0J"; // Clear from cursor to end of screen - SOs = "\033[7m"; // Terminal standout mode on - SOn = "\033[0m"; // Terminal standout mode off - bell= "\007"; // Terminal bell sequence -#ifdef BB_FEATURE_VI_CRASHME - (void) srand((long) getpid()); -#endif /* BB_FEATURE_VI_CRASHME */ - status_buffer = (Byte *) malloc(200); // hold messages to user -#ifdef BB_FEATURE_VI_READONLY - vi_readonly = readonly = FALSE; - if (strncmp(argv[0], "view", 4) == 0) { - readonly = TRUE; - vi_readonly = TRUE; - } -#endif /* BB_FEATURE_VI_READONLY */ -#ifdef BB_FEATURE_VI_SETOPTS - autoindent = 1; - ignorecase = 1; - showmatch = 1; -#endif /* BB_FEATURE_VI_SETOPTS */ -#ifdef BB_FEATURE_VI_YANKMARK - for (i = 0; i < 28; i++) { - reg[i] = 0; - } // init the yank regs -#endif /* BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_DOT_CMD - modifying_cmds = (Byte *) "aAcCdDiIJoOpPrRsxX<>~"; // cmds modifying text[] -#endif /* BB_FEATURE_VI_DOT_CMD */ - - // 1- process $HOME/.exrc file - // 2- process EXINIT variable from environment - // 3- process command line args - while ((c = getopt(argc, argv, "hCR")) != -1) { - switch (c) { -#ifdef BB_FEATURE_VI_CRASHME - case 'C': - crashme = 1; - break; -#endif /* BB_FEATURE_VI_CRASHME */ -#ifdef BB_FEATURE_VI_READONLY - case 'R': // Read-only flag - readonly = TRUE; - break; -#endif /* BB_FEATURE_VI_READONLY */ - //case 'r': // recover flag- ignore- we don't use tmp file - //case 'x': // encryption flag- ignore - //case 'c': // execute command first - //case 'h': // help -- just use default - default: - show_help(); - return 1; - } - } - - // The argv array can be used by the ":next" and ":rewind" commands - // save optind. - fn_start = optind; // remember first file name for :next and :rew - save_argc = argc; - - //----- This is the main file handling loop -------------- - if (optind >= argc) { - editing = 1; // 0= exit, 1= one file, 2= multiple files - edit_file(0); - } else { - for (; optind < argc; optind++) { - editing = 1; // 0=exit, 1=one file, 2+ =many files - if (cfn != 0) - free(cfn); - cfn = (Byte *) strdup(argv[optind]); - edit_file(cfn); - } - } - //----------------------------------------------------------- - - return (0); -} - -static void edit_file(Byte * fn) -{ - char c; - int cnt, size, ch; - -#ifdef BB_FEATURE_VI_USE_SIGNALS - char *msg; - int sig; -#endif /* BB_FEATURE_VI_USE_SIGNALS */ -#ifdef BB_FEATURE_VI_YANKMARK - static Byte *cur_line; -#endif /* BB_FEATURE_VI_YANKMARK */ - - rawmode(); - rows = 24; - columns = 80; - ch= -1; -#ifdef BB_FEATURE_VI_WIN_RESIZE - window_size_get(0); -#endif /* BB_FEATURE_VI_WIN_RESIZE */ - new_screen(rows, columns); // get memory for virtual screen - - cnt = file_size(fn); // file size - size = 2 * cnt; // 200% of file size - new_text(size); // get a text[] buffer - screenbegin = dot = end = text; - if (fn != 0) { - ch= file_insert(fn, text, cnt); - } - if (ch < 1) { - (void) char_insert(text, '\n'); // start empty buf with dummy line - } - file_modified = FALSE; -#ifdef BB_FEATURE_VI_YANKMARK - YDreg = 26; // default Yank/Delete reg - Ureg = 27; // hold orig line for "U" cmd - for (cnt = 0; cnt < 28; cnt++) { - mark[cnt] = 0; - } // init the marks - mark[26] = mark[27] = text; // init "previous context" -#endif /* BB_FEATURE_VI_YANKMARK */ - - err_method = 1; // flash - last_forward_char = last_input_char = '\0'; - crow = 0; - ccol = 0; - edit_status(); - -#ifdef BB_FEATURE_VI_USE_SIGNALS - signal(SIGHUP, catch_sig); - signal(SIGINT, catch_sig); - signal(SIGALRM, alarm_sig); - signal(SIGTERM, catch_sig); - signal(SIGQUIT, core_sig); - signal(SIGILL, core_sig); - signal(SIGTRAP, core_sig); - signal(SIGIOT, core_sig); - signal(SIGABRT, core_sig); - signal(SIGFPE, core_sig); - signal(SIGBUS, core_sig); - signal(SIGSEGV, core_sig); -#ifdef SIGSYS - signal(SIGSYS, core_sig); -#endif - signal(SIGWINCH, winch_sig); - signal(SIGTSTP, suspend_sig); - sig = setjmp(restart); - if (sig != 0) { - msg = ""; - if (sig == SIGWINCH) - msg = "(window resize)"; - if (sig == SIGHUP) - msg = "(hangup)"; - if (sig == SIGINT) - msg = "(interrupt)"; - if (sig == SIGTERM) - msg = "(terminate)"; - if (sig == SIGBUS) - msg = "(bus error)"; - if (sig == SIGSEGV) - msg = "(I tried to touch invalid memory)"; - if (sig == SIGALRM) - msg = "(alarm)"; - - psbs("-- caught signal %d %s--", sig, msg); - screenbegin = dot = text; - } -#endif /* BB_FEATURE_VI_USE_SIGNALS */ - - editing = 1; - cmd_mode = 0; // 0=command 1=insert 2='R'eplace - cmdcnt = 0; - tabstop = 8; - offset = 0; // no horizontal offset - c = '\0'; -#ifdef BB_FEATURE_VI_DOT_CMD - if (last_modifying_cmd != 0) - free(last_modifying_cmd); - if (ioq_start != NULL) - free(ioq_start); - ioq = ioq_start = last_modifying_cmd = 0; - adding2q = 0; -#endif /* BB_FEATURE_VI_DOT_CMD */ - redraw(FALSE); // dont force every col re-draw - show_status_line(); - - //------This is the main Vi cmd handling loop ----------------------- - while (editing > 0) { -#ifdef BB_FEATURE_VI_CRASHME - if (crashme > 0) { - if ((end - text) > 1) { - crash_dummy(); // generate a random command - } else { - crashme = 0; - dot = - string_insert(text, (Byte *) "\n\n##### Ran out of text to work on. #####\n\n"); // insert the string - refresh(FALSE); - } - } -#endif /* BB_FEATURE_VI_CRASHME */ - last_input_char = c = get_one_char(); // get a cmd from user -#ifdef BB_FEATURE_VI_YANKMARK - // save a copy of the current line- for the 'U" command - if (begin_line(dot) != cur_line) { - cur_line = begin_line(dot); - text_yank(begin_line(dot), end_line(dot), Ureg); - } -#endif /* BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_DOT_CMD - // These are commands that change text[]. - // Remember the input for the "." command - if (!adding2q && ioq_start == 0 - && strchr((char *) modifying_cmds, c) != NULL) { - start_new_cmd_q(c); - } -#endif /* BB_FEATURE_VI_DOT_CMD */ - do_cmd(c); // execute the user command - // - // poll to see if there is input already waiting. if we are - // not able to display output fast enough to keep up, skip - // the display update until we catch up with input. - if (mysleep(0) == 0) { - // no input pending- so update output - refresh(FALSE); - show_status_line(); - } -#ifdef BB_FEATURE_VI_CRASHME - if (crashme > 0) - crash_test(); // test editor variables -#endif /* BB_FEATURE_VI_CRASHME */ - } - //------------------------------------------------------------------- - - place_cursor(rows, 0, FALSE); // go to bottom of screen - clear_to_eol(); // Erase to end of line - cookmode(); -} - -static Byte readbuffer[BUFSIZ]; - -#ifdef BB_FEATURE_VI_CRASHME -static int totalcmds = 0; -static int Mp = 85; // Movement command Probability -static int Np = 90; // Non-movement command Probability -static int Dp = 96; // Delete command Probability -static int Ip = 97; // Insert command Probability -static int Yp = 98; // Yank command Probability -static int Pp = 99; // Put command Probability -static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0; -char chars[20] = "\t012345 abcdABCD-=.$"; -char *words[20] = { "this", "is", "a", "test", - "broadcast", "the", "emergency", "of", - "system", "quick", "brown", "fox", - "jumped", "over", "lazy", "dogs", - "back", "January", "Febuary", "March" -}; -char *lines[20] = { - "You should have received a copy of the GNU General Public License\n", - "char c, cm, *cmd, *cmd1;\n", - "generate a command by percentages\n", - "Numbers may be typed as a prefix to some commands.\n", - "Quit, discarding changes!\n", - "Forced write, if permission originally not valid.\n", - "In general, any ex or ed command (such as substitute or delete).\n", - "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n", - "Please get w/ me and I will go over it with you.\n", - "The following is a list of scheduled, committed changes.\n", - "1. Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n", - "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n", - "Any question about transactions please contact Sterling Huxley.\n", - "I will try to get back to you by Friday, December 31.\n", - "This Change will be implemented on Friday.\n", - "Let me know if you have problems accessing this;\n", - "Sterling Huxley recently added you to the access list.\n", - "Would you like to go to lunch?\n", - "The last command will be automatically run.\n", - "This is too much english for a computer geek.\n", -}; -char *multilines[20] = { - "You should have received a copy of the GNU General Public License\n", - "char c, cm, *cmd, *cmd1;\n", - "generate a command by percentages\n", - "Numbers may be typed as a prefix to some commands.\n", - "Quit, discarding changes!\n", - "Forced write, if permission originally not valid.\n", - "In general, any ex or ed command (such as substitute or delete).\n", - "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n", - "Please get w/ me and I will go over it with you.\n", - "The following is a list of scheduled, committed changes.\n", - "1. Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n", - "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n", - "Any question about transactions please contact Sterling Huxley.\n", - "I will try to get back to you by Friday, December 31.\n", - "This Change will be implemented on Friday.\n", - "Let me know if you have problems accessing this;\n", - "Sterling Huxley recently added you to the access list.\n", - "Would you like to go to lunch?\n", - "The last command will be automatically run.\n", - "This is too much english for a computer geek.\n", -}; - -// create a random command to execute -static void crash_dummy() -{ - static int sleeptime; // how long to pause between commands - char c, cm, *cmd, *cmd1; - int i, cnt, thing, rbi, startrbi, percent; - - // "dot" movement commands - cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL"; - - // is there already a command running? - if (strlen((char *) readbuffer) > 0) - goto cd1; - cd0: - startrbi = rbi = 0; - sleeptime = 0; // how long to pause between commands - memset(readbuffer, '\0', BUFSIZ - 1); // clear the read buffer - // generate a command by percentages - percent = (int) lrand48() % 100; // get a number from 0-99 - if (percent < Mp) { // Movement commands - // available commands - cmd = cmd1; - M++; - } else if (percent < Np) { // non-movement commands - cmd = "mz<>\'\""; // available commands - N++; - } else if (percent < Dp) { // Delete commands - cmd = "dx"; // available commands - D++; - } else if (percent < Ip) { // Inset commands - cmd = "iIaAsrJ"; // available commands - I++; - } else if (percent < Yp) { // Yank commands - cmd = "yY"; // available commands - Y++; - } else if (percent < Pp) { // Put commands - cmd = "pP"; // available commands - P++; - } else { - // We do not know how to handle this command, try again - U++; - goto cd0; - } - // randomly pick one of the available cmds from "cmd[]" - i = (int) lrand48() % strlen(cmd); - cm = cmd[i]; - if (strchr(":\024", cm)) - goto cd0; // dont allow colon or ctrl-T commands - readbuffer[rbi++] = cm; // put cmd into input buffer - - // now we have the command- - // there are 1, 2, and multi char commands - // find out which and generate the rest of command as necessary - if (strchr("dmryz<>\'\"", cm)) { // 2-char commands - cmd1 = " \n\r0$^-+wWeEbBhjklHL"; - if (cm == 'm' || cm == '\'' || cm == '\"') { // pick a reg[] - cmd1 = "abcdefghijklmnopqrstuvwxyz"; - } - thing = (int) lrand48() % strlen(cmd1); // pick a movement command - c = cmd1[thing]; - readbuffer[rbi++] = c; // add movement to input buffer - } - if (strchr("iIaAsc", cm)) { // multi-char commands - if (cm == 'c') { - // change some thing - thing = (int) lrand48() % strlen(cmd1); // pick a movement command - c = cmd1[thing]; - readbuffer[rbi++] = c; // add movement to input buffer - } - thing = (int) lrand48() % 4; // what thing to insert - cnt = (int) lrand48() % 10; // how many to insert - for (i = 0; i < cnt; i++) { - if (thing == 0) { // insert chars - readbuffer[rbi++] = chars[((int) lrand48() % strlen(chars))]; - } else if (thing == 1) { // insert words - strcat((char *) readbuffer, words[(int) lrand48() % 20]); - strcat((char *) readbuffer, " "); - sleeptime = 0; // how fast to type - } else if (thing == 2) { // insert lines - strcat((char *) readbuffer, lines[(int) lrand48() % 20]); - sleeptime = 0; // how fast to type - } else { // insert multi-lines - strcat((char *) readbuffer, multilines[(int) lrand48() % 20]); - sleeptime = 0; // how fast to type - } - } - strcat((char *) readbuffer, "\033"); - } - cd1: - totalcmds++; - if (sleeptime > 0) - (void) mysleep(sleeptime); // sleep 1/100 sec -} - -// test to see if there are any errors -static void crash_test() -{ - static time_t oldtim; - time_t tim; - char d[2], buf[BUFSIZ], msg[BUFSIZ]; - - msg[0] = '\0'; - if (end < text) { - strcat((char *) msg, "end textend) { - strcat((char *) msg, "end>textend "); - } - if (dot < text) { - strcat((char *) msg, "dot end) { - strcat((char *) msg, "dot>end "); - } - if (screenbegin < text) { - strcat((char *) msg, "screenbegin end - 1) { - strcat((char *) msg, "screenbegin>end-1 "); - } - - if (strlen(msg) > 0) { - alarm(0); - sprintf(buf, "\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s", - totalcmds, last_input_char, msg, SOs, SOn); - write(1, buf, strlen(buf)); - while (read(0, d, 1) > 0) { - if (d[0] == '\n' || d[0] == '\r') - break; - } - alarm(3); - } - tim = (time_t) time((time_t *) 0); - if (tim >= (oldtim + 3)) { - sprintf((char *) status_buffer, - "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d", - totalcmds, M, N, I, D, Y, P, U, end - text + 1); - oldtim = tim; - } - return; -} -#endif /* BB_FEATURE_VI_CRASHME */ - -//--------------------------------------------------------------------- -//----- the Ascii Chart ----------------------------------------------- -// -// 00 nul 01 soh 02 stx 03 etx 04 eot 05 enq 06 ack 07 bel -// 08 bs 09 ht 0a nl 0b vt 0c np 0d cr 0e so 0f si -// 10 dle 11 dc1 12 dc2 13 dc3 14 dc4 15 nak 16 syn 17 etb -// 18 can 19 em 1a sub 1b esc 1c fs 1d gs 1e rs 1f us -// 20 sp 21 ! 22 " 23 # 24 $ 25 % 26 & 27 ' -// 28 ( 29 ) 2a * 2b + 2c , 2d - 2e . 2f / -// 30 0 31 1 32 2 33 3 34 4 35 5 36 6 37 7 -// 38 8 39 9 3a : 3b ; 3c < 3d = 3e > 3f ? -// 40 @ 41 A 42 B 43 C 44 D 45 E 46 F 47 G -// 48 H 49 I 4a J 4b K 4c L 4d M 4e N 4f O -// 50 P 51 Q 52 R 53 S 54 T 55 U 56 V 57 W -// 58 X 59 Y 5a Z 5b [ 5c \ 5d ] 5e ^ 5f _ -// 60 ` 61 a 62 b 63 c 64 d 65 e 66 f 67 g -// 68 h 69 i 6a j 6b k 6c l 6d m 6e n 6f o -// 70 p 71 q 72 r 73 s 74 t 75 u 76 v 77 w -// 78 x 79 y 7a z 7b { 7c | 7d } 7e ~ 7f del -//--------------------------------------------------------------------- - -//----- Execute a Vi Command ----------------------------------- -static void do_cmd(Byte c) -{ - Byte c1, *p, *q, *msg, buf[9], *save_dot; - int cnt, i, j, dir, yf; - - c1 = c; // quiet the compiler - cnt = yf = dir = 0; // quiet the compiler - p = q = save_dot = msg = buf; // quiet the compiler - memset(buf, '\0', 9); // clear buf - if (cmd_mode == 2) { - // we are 'R'eplacing the current *dot with new char - if (*dot == '\n') { - // don't Replace past E-o-l - cmd_mode = 1; // convert to insert - } else { - if (1 <= c && c <= 127) { // only ASCII chars - if (c != 27) - dot = yank_delete(dot, dot, 0, YANKDEL); // delete char - dot = char_insert(dot, c); // insert new char - } - goto dc1; - } - } - if (cmd_mode == 1) { - // hitting "Insert" twice means "R" replace mode - if (c == VI_K_INSERT) goto dc5; - // insert the char c at "dot" - if (1 <= c && c <= 127) { - dot = char_insert(dot, c); // only ASCII chars - } - goto dc1; - } - - switch (c) { - //case 0x01: // soh - //case 0x09: // ht - //case 0x0b: // vt - //case 0x0e: // so - //case 0x0f: // si - //case 0x10: // dle - //case 0x11: // dc1 - //case 0x13: // dc3 -#ifdef BB_FEATURE_VI_CRASHME - case 0x14: // dc4 ctrl-T - crashme = (crashme == 0) ? 1 : 0; - break; -#endif /* BB_FEATURE_VI_CRASHME */ - //case 0x16: // syn - //case 0x17: // etb - //case 0x18: // can - //case 0x1c: // fs - //case 0x1d: // gs - //case 0x1e: // rs - //case 0x1f: // us - //case '!': // !- - //case '#': // #- - //case '&': // &- - //case '(': // (- - //case ')': // )- - //case '*': // *- - //case ',': // ,- - //case '=': // =- - //case '@': // @- - //case 'F': // F- - //case 'K': // K- - //case 'Q': // Q- - //case 'S': // S- - //case 'T': // T- - //case 'V': // V- - //case '[': // [- - //case '\\': // \- - //case ']': // ]- - //case '_': // _- - //case '`': // `- - //case 'g': // g- - //case 'u': // u- FIXME- there is no undo - //case 'v': // v- - default: // unrecognised command - buf[0] = c; - buf[1] = '\0'; - if (c <= ' ') { - buf[0] = '^'; - buf[1] = c + '@'; - buf[2] = '\0'; - } - ni((Byte *) buf); - end_cmd_q(); // stop adding to q - case 0x00: // nul- ignore - break; - case 2: // ctrl-B scroll up full screen - case VI_K_PAGEUP: // Cursor Key Page Up - dot_scroll(rows - 2, -1); - break; -#ifdef BB_FEATURE_VI_USE_SIGNALS - case 0x03: // ctrl-C interrupt - longjmp(restart, 1); - break; - case 26: // ctrl-Z suspend - suspend_sig(SIGTSTP); - break; -#endif /* BB_FEATURE_VI_USE_SIGNALS */ - case 4: // ctrl-D scroll down half screen - dot_scroll((rows - 2) / 2, 1); - break; - case 5: // ctrl-E scroll down one line - dot_scroll(1, 1); - break; - case 6: // ctrl-F scroll down full screen - case VI_K_PAGEDOWN: // Cursor Key Page Down - dot_scroll(rows - 2, 1); - break; - case 7: // ctrl-G show current status - edit_status(); - break; - case 'h': // h- move left - case VI_K_LEFT: // cursor key Left - case 8: // ctrl-H- move left (This may be ERASE char) - case 127: // DEL- move left (This may be ERASE char) - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dot_left(); - break; - case 10: // Newline ^J - case 'j': // j- goto next line, same col - case VI_K_DOWN: // cursor key Down - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dot_next(); // go to next B-o-l - dot = move_to_col(dot, ccol + offset); // try stay in same col - break; - case 12: // ctrl-L force redraw whole screen - case 18: // ctrl-R force redraw - place_cursor(0, 0, FALSE); // put cursor in correct place - clear_to_eos(); // tel terminal to erase display - (void) mysleep(10); - screen_erase(); // erase the internal screen buffer - refresh(TRUE); // this will redraw the entire display - break; - case 13: // Carriage Return ^M - case '+': // +- goto next line - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dot_next(); - dot_skip_over_ws(); - break; - case 21: // ctrl-U scroll up half screen - dot_scroll((rows - 2) / 2, -1); - break; - case 25: // ctrl-Y scroll up one line - dot_scroll(1, -1); - break; - case 27: // esc - if (cmd_mode == 0) - indicate_error(c); - cmd_mode = 0; // stop insrting - end_cmd_q(); - *status_buffer = '\0'; // clear status buffer - break; - case ' ': // move right - case 'l': // move right - case VI_K_RIGHT: // Cursor Key Right - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dot_right(); - break; -#ifdef BB_FEATURE_VI_YANKMARK - case '"': // "- name a register to use for Delete/Yank - c1 = get_one_char(); - c1 = tolower(c1); - if (islower(c1)) { - YDreg = c1 - 'a'; - } else { - indicate_error(c); - } - break; - case '\'': // '- goto a specific mark - c1 = get_one_char(); - c1 = tolower(c1); - if (islower(c1)) { - c1 = c1 - 'a'; - // get the b-o-l - q = mark[(int) c1]; - if (text <= q && q < end) { - dot = q; - dot_begin(); // go to B-o-l - dot_skip_over_ws(); - } - } else if (c1 == '\'') { // goto previous context - dot = swap_context(dot); // swap current and previous context - dot_begin(); // go to B-o-l - dot_skip_over_ws(); - } else { - indicate_error(c); - } - break; - case 'm': // m- Mark a line - // this is really stupid. If there are any inserts or deletes - // between text[0] and dot then this mark will not point to the - // correct location! It could be off by many lines! - // Well..., at least its quick and dirty. - c1 = get_one_char(); - c1 = tolower(c1); - if (islower(c1)) { - c1 = c1 - 'a'; - // remember the line - mark[(int) c1] = dot; - } else { - indicate_error(c); - } - break; - case 'P': // P- Put register before - case 'p': // p- put register after - p = reg[YDreg]; - if (p == 0) { - psbs("Nothing in register %c", what_reg()); - break; - } - // are we putting whole lines or strings - if (strchr((char *) p, '\n') != NULL) { - if (c == 'P') { - dot_begin(); // putting lines- Put above - } - if (c == 'p') { - // are we putting after very last line? - if (end_line(dot) == (end - 1)) { - dot = end; // force dot to end of text[] - } else { - dot_next(); // next line, then put before - } - } - } else { - if (c == 'p') - dot_right(); // move to right, can move to NL - } - dot = string_insert(dot, p); // insert the string - end_cmd_q(); // stop adding to q - break; - case 'U': // U- Undo; replace current line with original version - if (reg[Ureg] != 0) { - p = begin_line(dot); - q = end_line(dot); - p = text_hole_delete(p, q); // delete cur line - p = string_insert(p, reg[Ureg]); // insert orig line - dot = p; - dot_skip_over_ws(); - } - break; -#endif /* BB_FEATURE_VI_YANKMARK */ - case '$': // $- goto end of line - case VI_K_END: // Cursor Key End - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dot = end_line(dot + 1); - break; - case '%': // %- find matching char of pair () [] {} - for (q = dot; q < end && *q != '\n'; q++) { - if (strchr("()[]{}", *q) != NULL) { - // we found half of a pair - p = find_pair(q, *q); - if (p == NULL) { - indicate_error(c); - } else { - dot = p; - } - break; - } - } - if (*q == '\n') - indicate_error(c); - break; - case 'f': // f- forward to a user specified char - last_forward_char = get_one_char(); // get the search char - // - // dont seperate these two commands. 'f' depends on ';' - // - //**** fall thru to ... 'i' - case ';': // ;- look at rest of line for last forward char - if (cmdcnt-- > 1) { - do_cmd(';'); - } // repeat cnt - if (last_forward_char == 0) break; - q = dot + 1; - while (q < end - 1 && *q != '\n' && *q != last_forward_char) { - q++; - } - if (*q == last_forward_char) - dot = q; - break; - case '-': // -- goto prev line - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dot_prev(); - dot_skip_over_ws(); - break; -#ifdef BB_FEATURE_VI_DOT_CMD - case '.': // .- repeat the last modifying command - // Stuff the last_modifying_cmd back into stdin - // and let it be re-executed. - if (last_modifying_cmd != 0) { - ioq = ioq_start = (Byte *) strdup((char *) last_modifying_cmd); - } - break; -#endif /* BB_FEATURE_VI_DOT_CMD */ -#ifdef BB_FEATURE_VI_SEARCH - case '?': // /- search for a pattern - case '/': // /- search for a pattern - buf[0] = c; - buf[1] = '\0'; - q = get_input_line(buf); // get input line- use "status line" - if (strlen((char *) q) == 1) - goto dc3; // if no pat re-use old pat - if (strlen((char *) q) > 1) { // new pat- save it and find - // there is a new pat - if (last_search_pattern != 0) { - free(last_search_pattern); - } - last_search_pattern = (Byte *) strdup((char *) q); - goto dc3; // now find the pattern - } - // user changed mind and erased the "/"- do nothing - break; - case 'N': // N- backward search for last pattern - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dir = BACK; // assume BACKWARD search - p = dot - 1; - if (last_search_pattern[0] == '?') { - dir = FORWARD; - p = dot + 1; - } - goto dc4; // now search for pattern - break; - case 'n': // n- repeat search for last pattern - // search rest of text[] starting at next char - // if search fails return orignal "p" not the "p+1" address - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dc3: - if (last_search_pattern == 0) { - msg = (Byte *) "No previous regular expression"; - goto dc2; - } - if (last_search_pattern[0] == '/') { - dir = FORWARD; // assume FORWARD search - p = dot + 1; - } - if (last_search_pattern[0] == '?') { - dir = BACK; - p = dot - 1; - } - dc4: - q = char_search(p, last_search_pattern + 1, dir, FULL); - if (q != NULL) { - dot = q; // good search, update "dot" - msg = (Byte *) ""; - goto dc2; - } - // no pattern found between "dot" and "end"- continue at top - p = text; - if (dir == BACK) { - p = end - 1; - } - q = char_search(p, last_search_pattern + 1, dir, FULL); - if (q != NULL) { // found something - dot = q; // found new pattern- goto it - msg = (Byte *) "search hit BOTTOM, continuing at TOP"; - if (dir == BACK) { - msg = (Byte *) "search hit TOP, continuing at BOTTOM"; - } - } else { - msg = (Byte *) "Pattern not found"; - } - dc2: - psbs("%s", msg); - break; - case '{': // {- move backward paragraph - q = char_search(dot, (Byte *) "\n\n", BACK, FULL); - if (q != NULL) { // found blank line - dot = next_line(q); // move to next blank line - } - break; - case '}': // }- move forward paragraph - q = char_search(dot, (Byte *) "\n\n", FORWARD, FULL); - if (q != NULL) { // found blank line - dot = next_line(q); // move to next blank line - } - break; -#endif /* BB_FEATURE_VI_SEARCH */ - case '0': // 0- goto begining of line - case '1': // 1- - case '2': // 2- - case '3': // 3- - case '4': // 4- - case '5': // 5- - case '6': // 6- - case '7': // 7- - case '8': // 8- - case '9': // 9- - if (c == '0' && cmdcnt < 1) { - dot_begin(); // this was a standalone zero - } else { - cmdcnt = cmdcnt * 10 + (c - '0'); // this 0 is part of a number - } - break; - case ':': // :- the colon mode commands - p = get_input_line((Byte *) ":"); // get input line- use "status line" -#ifdef BB_FEATURE_VI_COLON - colon(p); // execute the command -#else /* BB_FEATURE_VI_COLON */ - if (*p == ':') - p++; // move past the ':' - cnt = strlen((char *) p); - if (cnt <= 0) - break; - if (strncasecmp((char *) p, "quit", cnt) == 0 || - strncasecmp((char *) p, "q!", cnt) == 0) { // delete lines - if (file_modified == TRUE && p[1] != '!') { - psbs("No write since last change (:quit! overrides)"); - } else { - editing = 0; - } - } else if (strncasecmp((char *) p, "write", cnt) == 0 || - strncasecmp((char *) p, "wq", cnt) == 0) { - cnt = file_write(cfn, text, end - 1); - file_modified = FALSE; - psb("\"%s\" %dL, %dC", cfn, count_lines(text, end - 1), cnt); - if (p[1] == 'q') { - editing = 0; - } - } else if (strncasecmp((char *) p, "file", cnt) == 0 ) { - edit_status(); // show current file status - } else if (sscanf((char *) p, "%d", &j) > 0) { - dot = find_line(j); // go to line # j - dot_skip_over_ws(); - } else { // unrecognised cmd - ni((Byte *) p); - } -#endif /* BB_FEATURE_VI_COLON */ - break; - case '<': // <- Left shift something - case '>': // >- Right shift something - cnt = count_lines(text, dot); // remember what line we are on - c1 = get_one_char(); // get the type of thing to delete - find_range(&p, &q, c1); - (void) yank_delete(p, q, 1, YANKONLY); // save copy before change - p = begin_line(p); - q = end_line(q); - i = count_lines(p, q); // # of lines we are shifting - for ( ; i > 0; i--, p = next_line(p)) { - if (c == '<') { - // shift left- remove tab or 8 spaces - if (*p == '\t') { - // shrink buffer 1 char - (void) text_hole_delete(p, p); - } else if (*p == ' ') { - // we should be calculating columns, not just SPACE - for (j = 0; *p == ' ' && j < tabstop; j++) { - (void) text_hole_delete(p, p); - } - } - } else if (c == '>') { - // shift right -- add tab or 8 spaces - (void) char_insert(p, '\t'); - } - } - dot = find_line(cnt); // what line were we on - dot_skip_over_ws(); - end_cmd_q(); // stop adding to q - break; - case 'A': // A- append at e-o-l - dot_end(); // go to e-o-l - //**** fall thru to ... 'a' - case 'a': // a- append after current char - if (*dot != '\n') - dot++; - goto dc_i; - break; - case 'B': // B- back a blank-delimited Word - case 'E': // E- end of a blank-delimited word - case 'W': // W- forward a blank-delimited word - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dir = FORWARD; - if (c == 'B') - dir = BACK; - if (c == 'W' || isspace(dot[dir])) { - dot = skip_thing(dot, 1, dir, S_TO_WS); - dot = skip_thing(dot, 2, dir, S_OVER_WS); - } - if (c != 'W') - dot = skip_thing(dot, 1, dir, S_BEFORE_WS); - break; - case 'C': // C- Change to e-o-l - case 'D': // D- delete to e-o-l - save_dot = dot; - dot = dollar_line(dot); // move to before NL - // copy text into a register and delete - dot = yank_delete(save_dot, dot, 0, YANKDEL); // delete to e-o-l - if (c == 'C') - goto dc_i; // start inserting -#ifdef BB_FEATURE_VI_DOT_CMD - if (c == 'D') - end_cmd_q(); // stop adding to q -#endif /* BB_FEATURE_VI_DOT_CMD */ - break; - case 'G': // G- goto to a line number (default= E-O-F) - dot = end - 1; // assume E-O-F - if (cmdcnt > 0) { - dot = find_line(cmdcnt); // what line is #cmdcnt - } - dot_skip_over_ws(); - break; - case 'H': // H- goto top line on screen - dot = screenbegin; - if (cmdcnt > (rows - 1)) { - cmdcnt = (rows - 1); - } - if (cmdcnt-- > 1) { - do_cmd('+'); - } // repeat cnt - dot_skip_over_ws(); - break; - case 'I': // I- insert before first non-blank - dot_begin(); // 0 - dot_skip_over_ws(); - //**** fall thru to ... 'i' - case 'i': // i- insert before current char - case VI_K_INSERT: // Cursor Key Insert - dc_i: - cmd_mode = 1; // start insrting - psb("-- Insert --"); - break; - case 'J': // J- join current and next lines together - if (cmdcnt-- > 2) { - do_cmd(c); - } // repeat cnt - dot_end(); // move to NL - if (dot < end - 1) { // make sure not last char in text[] - *dot++ = ' '; // replace NL with space - while (isblnk(*dot)) { // delete leading WS - dot_delete(); - } - } - end_cmd_q(); // stop adding to q - break; - case 'L': // L- goto bottom line on screen - dot = end_screen(); - if (cmdcnt > (rows - 1)) { - cmdcnt = (rows - 1); - } - if (cmdcnt-- > 1) { - do_cmd('-'); - } // repeat cnt - dot_begin(); - dot_skip_over_ws(); - break; - case 'M': // M- goto middle line on screen - dot = screenbegin; - for (cnt = 0; cnt < (rows-1) / 2; cnt++) - dot = next_line(dot); - break; - case 'O': // O- open a empty line above - // 0i\n ESC -i - p = begin_line(dot); - if (p[-1] == '\n') { - dot_prev(); - case 'o': // o- open a empty line below; Yes, I know it is in the middle of the "if (..." - dot_end(); - dot = char_insert(dot, '\n'); - } else { - dot_begin(); // 0 - dot = char_insert(dot, '\n'); // i\n ESC - dot_prev(); // - - } - goto dc_i; - break; - case 'R': // R- continuous Replace char - dc5: - cmd_mode = 2; - psb("-- Replace --"); - break; - case 'X': // X- delete char before dot - case 'x': // x- delete the current char - case 's': // s- substitute the current char - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dir = 0; - if (c == 'X') - dir = -1; - if (dot[dir] != '\n') { - if (c == 'X') - dot--; // delete prev char - dot = yank_delete(dot, dot, 0, YANKDEL); // delete char - } - if (c == 's') - goto dc_i; // start insrting - end_cmd_q(); // stop adding to q - break; - case 'Z': // Z- if modified, {write}; exit - // ZZ means to save file (if necessary), then exit - c1 = get_one_char(); - if (c1 != 'Z') { - indicate_error(c); - break; - } - if (file_modified == TRUE -#ifdef BB_FEATURE_VI_READONLY - && vi_readonly == FALSE - && readonly == FALSE -#endif /* BB_FEATURE_VI_READONLY */ - ) { - cnt = file_write(cfn, text, end - 1); - if (cnt == (end - 1 - text + 1)) { - editing = 0; - } - } else { - editing = 0; - } - break; - case '^': // ^- move to first non-blank on line - dot_begin(); - dot_skip_over_ws(); - break; - case 'b': // b- back a word - case 'e': // e- end of word - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dir = FORWARD; - if (c == 'b') - dir = BACK; - if ((dot + dir) < text || (dot + dir) > end - 1) - break; - dot += dir; - if (isspace(*dot)) { - dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS); - } - if (isalnum(*dot) || *dot == '_') { - dot = skip_thing(dot, 1, dir, S_END_ALNUM); - } else if (ispunct(*dot)) { - dot = skip_thing(dot, 1, dir, S_END_PUNCT); - } - break; - case 'c': // c- change something - case 'd': // d- delete something -#ifdef BB_FEATURE_VI_YANKMARK - case 'y': // y- yank something - case 'Y': // Y- Yank a line -#endif /* BB_FEATURE_VI_YANKMARK */ - yf = YANKDEL; // assume either "c" or "d" -#ifdef BB_FEATURE_VI_YANKMARK - if (c == 'y' || c == 'Y') - yf = YANKONLY; -#endif /* BB_FEATURE_VI_YANKMARK */ - c1 = 'y'; - if (c != 'Y') - c1 = get_one_char(); // get the type of thing to delete - find_range(&p, &q, c1); - if (c1 == 27) { // ESC- user changed mind and wants out - c = c1 = 27; // Escape- do nothing - } else if (strchr("wW", c1)) { - if (c == 'c') { - // don't include trailing WS as part of word - while (isblnk(*q)) { - if (q <= text || q[-1] == '\n') - break; - q--; - } - } - dot = yank_delete(p, q, 0, yf); // delete word - } else if (strchr("^0bBeEft$", c1)) { - // single line copy text into a register and delete - dot = yank_delete(p, q, 0, yf); // delete word - } else if (strchr("cdykjHL%+-{}\r\n", c1)) { - // multiple line copy text into a register and delete - dot = yank_delete(p, q, 1, yf); // delete lines - if (c == 'c') { - dot = char_insert(dot, '\n'); - // on the last line of file don't move to prev line - if (dot != (end-1)) { - dot_prev(); - } - } else if (c == 'd') { - dot_begin(); - dot_skip_over_ws(); - } - } else { - // could not recognize object - c = c1 = 27; // error- - indicate_error(c); - } - if (c1 != 27) { - // if CHANGING, not deleting, start inserting after the delete - if (c == 'c') { - strcpy((char *) buf, "Change"); - goto dc_i; // start inserting - } - if (c == 'd') { - strcpy((char *) buf, "Delete"); - } -#ifdef BB_FEATURE_VI_YANKMARK - if (c == 'y' || c == 'Y') { - strcpy((char *) buf, "Yank"); - } - p = reg[YDreg]; - q = p + strlen((char *) p); - for (cnt = 0; p <= q; p++) { - if (*p == '\n') - cnt++; - } - psb("%s %d lines (%d chars) using [%c]", - buf, cnt, strlen((char *) reg[YDreg]), what_reg()); -#endif /* BB_FEATURE_VI_YANKMARK */ - end_cmd_q(); // stop adding to q - } - break; - case 'k': // k- goto prev line, same col - case VI_K_UP: // cursor key Up - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - dot_prev(); - dot = move_to_col(dot, ccol + offset); // try stay in same col - break; - case 'r': // r- replace the current char with user input - c1 = get_one_char(); // get the replacement char - if (*dot != '\n') { - *dot = c1; - file_modified = TRUE; // has the file been modified - } - end_cmd_q(); // stop adding to q - break; - case 't': // t- move to char prior to next x - last_forward_char = get_one_char(); - do_cmd(';'); - if (*dot == last_forward_char) - dot_left(); - last_forward_char= 0; - break; - case 'w': // w- forward a word - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - if (isalnum(*dot) || *dot == '_') { // we are on ALNUM - dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); - } else if (ispunct(*dot)) { // we are on PUNCT - dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT); - } - if (dot < end - 1) - dot++; // move over word - if (isspace(*dot)) { - dot = skip_thing(dot, 2, FORWARD, S_OVER_WS); - } - break; - case 'z': // z- - c1 = get_one_char(); // get the replacement char - cnt = 0; - if (c1 == '.') - cnt = (rows - 2) / 2; // put dot at center - if (c1 == '-') - cnt = rows - 2; // put dot at bottom - screenbegin = begin_line(dot); // start dot at top - dot_scroll(cnt, -1); - break; - case '|': // |- move to column "cmdcnt" - dot = move_to_col(dot, cmdcnt - 1); // try to move to column - break; - case '~': // ~- flip the case of letters a-z -> A-Z - if (cmdcnt-- > 1) { - do_cmd(c); - } // repeat cnt - if (islower(*dot)) { - *dot = toupper(*dot); - file_modified = TRUE; // has the file been modified - } else if (isupper(*dot)) { - *dot = tolower(*dot); - file_modified = TRUE; // has the file been modified - } - dot_right(); - end_cmd_q(); // stop adding to q - break; - //----- The Cursor and Function Keys ----------------------------- - case VI_K_HOME: // Cursor Key Home - dot_begin(); - break; - // The Fn keys could point to do_macro which could translate them - case VI_K_FUN1: // Function Key F1 - case VI_K_FUN2: // Function Key F2 - case VI_K_FUN3: // Function Key F3 - case VI_K_FUN4: // Function Key F4 - case VI_K_FUN5: // Function Key F5 - case VI_K_FUN6: // Function Key F6 - case VI_K_FUN7: // Function Key F7 - case VI_K_FUN8: // Function Key F8 - case VI_K_FUN9: // Function Key F9 - case VI_K_FUN10: // Function Key F10 - case VI_K_FUN11: // Function Key F11 - case VI_K_FUN12: // Function Key F12 - break; - } - - dc1: - // if text[] just became empty, add back an empty line - if (end == text) { - (void) char_insert(text, '\n'); // start empty buf with dummy line - dot = text; - } - // it is OK for dot to exactly equal to end, otherwise check dot validity - if (dot != end) { - dot = bound_dot(dot); // make sure "dot" is valid - } -#ifdef BB_FEATURE_VI_YANKMARK - check_context(c); // update the current context -#endif /* BB_FEATURE_VI_YANKMARK */ - - if (!isdigit(c)) - cmdcnt = 0; // cmd was not a number, reset cmdcnt - cnt = dot - begin_line(dot); - // Try to stay off of the Newline - if (*dot == '\n' && cnt > 0 && cmd_mode == 0) - dot--; -} - -//----- The Colon commands ------------------------------------- -#ifdef BB_FEATURE_VI_COLON -static Byte *get_one_address(Byte * p, int *addr) // get colon addr, if present -{ - int st; - Byte *q; - -#ifdef BB_FEATURE_VI_YANKMARK - Byte c; -#endif /* BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_SEARCH - Byte *pat, buf[BUFSIZ]; -#endif /* BB_FEATURE_VI_SEARCH */ - - *addr = -1; // assume no addr - if (*p == '.') { // the current line - p++; - q = begin_line(dot); - *addr = count_lines(text, q); -#ifdef BB_FEATURE_VI_YANKMARK - } else if (*p == '\'') { // is this a mark addr - p++; - c = tolower(*p); - p++; - if (c >= 'a' && c <= 'z') { - // we have a mark - c = c - 'a'; - q = mark[(int) c]; - if (q != NULL) { // is mark valid - *addr = count_lines(text, q); // count lines - } - } -#endif /* BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_SEARCH - } else if (*p == '/') { // a search pattern - q = buf; - for (p++; *p; p++) { - if (*p == '/') - break; - *q++ = *p; - *q = '\0'; - } - pat = (Byte *) strdup((char *) buf); // save copy of pattern - if (*p == '/') - p++; - q = char_search(dot, pat, FORWARD, FULL); - if (q != NULL) { - *addr = count_lines(text, q); - } - free(pat); -#endif /* BB_FEATURE_VI_SEARCH */ - } else if (*p == '$') { // the last line in file - p++; - q = begin_line(end - 1); - *addr = count_lines(text, q); - } else if (isdigit(*p)) { // specific line number - sscanf((char *) p, "%d%n", addr, &st); - p += st; - } else { // I don't reconise this - // unrecognised address- assume -1 - *addr = -1; - } - return (p); -} - -static Byte *get_address(Byte *p, int *b, int *e) // get two colon addrs, if present -{ - //----- get the address' i.e., 1,3 'a,'b ----- - // get FIRST addr, if present - while (isblnk(*p)) - p++; // skip over leading spaces - if (*p == '%') { // alias for 1,$ - p++; - *b = 1; - *e = count_lines(text, end-1); - goto ga0; - } - p = get_one_address(p, b); - while (isblnk(*p)) - p++; - if (*p == ',') { // is there a address seperator - p++; - while (isblnk(*p)) - p++; - // get SECOND addr, if present - p = get_one_address(p, e); - } -ga0: - while (isblnk(*p)) - p++; // skip over trailing spaces - return (p); -} - -static void colon(Byte * buf) -{ - Byte c, *orig_buf, *buf1, *q, *r; - Byte *fn, cmd[BUFSIZ], args[BUFSIZ]; - int i, l, li, ch, st, b, e; - int useforce, forced; - struct stat st_buf; - - // :3154 // if (-e line 3154) goto it else stay put - // :4,33w! foo // write a portion of buffer to file "foo" - // :w // write all of buffer to current file - // :q // quit - // :q! // quit- dont care about modified file - // :'a,'z!sort -u // filter block through sort - // :'f // goto mark "f" - // :'fl // list literal the mark "f" line - // :.r bar // read file "bar" into buffer before dot - // :/123/,/abc/d // delete lines from "123" line to "abc" line - // :/xyz/ // goto the "xyz" line - // :s/find/replace/ // substitute pattern "find" with "replace" - // :! // run then return - // - if (strlen((char *) buf) <= 0) - goto vc1; - if (*buf == ':') - buf++; // move past the ':' - - forced = useforce = FALSE; - li = st = ch = i = 0; - b = e = -1; - q = text; // assume 1,$ for the range - r = end - 1; - li = count_lines(text, end - 1); - fn = cfn; // default to current file - memset(cmd, '\0', BUFSIZ); // clear cmd[] - memset(args, '\0', BUFSIZ); // clear args[] - - // look for optional address(es) :. :1 :1,9 :'q,'a :% - buf = get_address(buf, &b, &e); - - // remember orig command line - orig_buf = buf; - - // get the COMMAND into cmd[] - buf1 = cmd; - while (*buf != '\0') { - if (isspace(*buf)) - break; - *buf1++ = *buf++; - } - // get any ARGuments - while (isblnk(*buf)) - buf++; - strcpy((char *) args, (char *) buf); - buf1 = last_char_is((char *)cmd, '!'); - if (buf1) { - useforce = TRUE; - *buf1 = '\0'; // get rid of ! - } - if (b >= 0) { - // if there is only one addr, then the addr - // is the line number of the single line the - // user wants. So, reset the end - // pointer to point at end of the "b" line - q = find_line(b); // what line is #b - r = end_line(q); - li = 1; - } - if (e >= 0) { - // we were given two addrs. change the - // end pointer to the addr given by user. - r = find_line(e); // what line is #e - r = end_line(r); - li = e - b + 1; - } - // ------------ now look for the command ------------ - i = strlen((char *) cmd); - if (i == 0) { // :123CR goto line #123 - if (b >= 0) { - dot = find_line(b); // what line is #b - dot_skip_over_ws(); - } - } else if (strncmp((char *) cmd, "!", 1) == 0) { // run a cmd - // :!ls run the - (void) alarm(0); // wait for input- no alarms - place_cursor(rows - 1, 0, FALSE); // go to Status line - clear_to_eol(); // clear the line - cookmode(); - system(orig_buf+1); // run the cmd - rawmode(); - Hit_Return(); // let user see results - (void) alarm(3); // done waiting for input - } else if (strncmp((char *) cmd, "=", i) == 0) { // where is the address - if (b < 0) { // no addr given- use defaults - b = e = count_lines(text, dot); - } - psb("%d", b); - } else if (strncasecmp((char *) cmd, "delete", i) == 0) { // delete lines - if (b < 0) { // no addr given- use defaults - q = begin_line(dot); // assume .,. for the range - r = end_line(dot); - } - dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines - dot_skip_over_ws(); - } else if (strncasecmp((char *) cmd, "edit", i) == 0) { // Edit a file - int sr; - sr= 0; - // don't edit, if the current file has been modified - if (file_modified == TRUE && useforce != TRUE) { - psbs("No write since last change (:edit! overrides)"); - goto vc1; - } - if (strlen(args) > 0) { - // the user supplied a file name - fn= args; - } else if (cfn != 0 && strlen(cfn) > 0) { - // no user supplied name- use the current filename - fn= cfn; - goto vc5; - } else { - // no user file name, no current name- punt - psbs("No current filename"); - goto vc1; - } - - // see if file exists- if not, its just a new file request - if ((sr=stat((char*)fn, &st_buf)) < 0) { - // This is just a request for a new file creation. - // The file_insert below will fail but we get - // an empty buffer with a file name. Then the "write" - // command can do the create. - } else { - if ((st_buf.st_mode & (S_IFREG)) == 0) { - // This is not a regular file - psbs("\"%s\" is not a regular file", fn); - goto vc1; - } - if ((st_buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) { - // dont have any read permissions - psbs("\"%s\" is not readable", fn); - goto vc1; - } - } - - // There is a read-able regular file - // make this the current file - q = (Byte *) strdup((char *) fn); // save the cfn - if (cfn != 0) - free(cfn); // free the old name - cfn = q; // remember new cfn - - vc5: - // delete all the contents of text[] - new_text(2 * file_size(fn)); - screenbegin = dot = end = text; - - // insert new file - ch = file_insert(fn, text, file_size(fn)); - - if (ch < 1) { - // start empty buf with dummy line - (void) char_insert(text, '\n'); - ch= 1; - } - file_modified = FALSE; -#ifdef BB_FEATURE_VI_YANKMARK - if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { - free(reg[Ureg]); // free orig line reg- for 'U' - reg[Ureg]= 0; - } - if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) { - free(reg[YDreg]); // free default yank/delete register - reg[YDreg]= 0; - } - for (li = 0; li < 28; li++) { - mark[li] = 0; - } // init the marks -#endif /* BB_FEATURE_VI_YANKMARK */ - // how many lines in text[]? - li = count_lines(text, end - 1); - psb("\"%s\"%s" -#ifdef BB_FEATURE_VI_READONLY - "%s" -#endif /* BB_FEATURE_VI_READONLY */ - " %dL, %dC", cfn, - (sr < 0 ? " [New file]" : ""), -#ifdef BB_FEATURE_VI_READONLY - ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""), -#endif /* BB_FEATURE_VI_READONLY */ - li, ch); - } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this - if (b != -1 || e != -1) { - ni((Byte *) "No address allowed on this command"); - goto vc1; - } - if (strlen((char *) args) > 0) { - // user wants a new filename - if (cfn != NULL) - free(cfn); - cfn = (Byte *) strdup((char *) args); - } else { - // user wants file status info - edit_status(); - } - } else if (strncasecmp((char *) cmd, "features", i) == 0) { // what features are available - // print out values of all features - place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen - clear_to_eol(); // clear the line - cookmode(); - show_help(); - rawmode(); - Hit_Return(); - } else if (strncasecmp((char *) cmd, "list", i) == 0) { // literal print line - if (b < 0) { // no addr given- use defaults - q = begin_line(dot); // assume .,. for the range - r = end_line(dot); - } - place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen - clear_to_eol(); // clear the line - write(1, "\r\n", 2); - for (; q <= r; q++) { - c = *q; - if (c > '~') - standout_start(); - if (c == '\n') { - write(1, "$\r", 2); - } else if (*q < ' ') { - write(1, "^", 1); - c += '@'; - } - write(1, &c, 1); - if (c > '~') - standout_end(); - } -#ifdef BB_FEATURE_VI_SET - vc2: -#endif /* BB_FEATURE_VI_SET */ - Hit_Return(); - } else if ((strncasecmp((char *) cmd, "quit", i) == 0) || // Quit - (strncasecmp((char *) cmd, "next", i) == 0)) { // edit next file - if (useforce == TRUE) { - // force end of argv list - if (*cmd == 'q') { - optind = save_argc; - } - editing = 0; - goto vc1; - } - // don't exit if the file been modified - if (file_modified == TRUE) { - psbs("No write since last change (:%s! overrides)", - (*cmd == 'q' ? "quit" : "next")); - goto vc1; - } - // are there other file to edit - if (*cmd == 'q' && optind < save_argc - 1) { - psbs("%d more file to edit", (save_argc - optind - 1)); - goto vc1; - } - if (*cmd == 'n' && optind >= save_argc - 1) { - psbs("No more files to edit"); - goto vc1; - } - editing = 0; - } else if (strncasecmp((char *) cmd, "read", i) == 0) { // read file into text[] - fn = args; - if (strlen((char *) fn) <= 0) { - psbs("No filename given"); - goto vc1; - } - if (b < 0) { // no addr given- use defaults - q = begin_line(dot); // assume "dot" - } - // read after current line- unless user said ":0r foo" - if (b != 0) - q = next_line(q); -#ifdef BB_FEATURE_VI_READONLY - l= readonly; // remember current files' status -#endif - ch = file_insert(fn, q, file_size(fn)); -#ifdef BB_FEATURE_VI_READONLY - readonly= l; -#endif - if (ch < 0) - goto vc1; // nothing was inserted - // how many lines in text[]? - li = count_lines(q, q + ch - 1); - psb("\"%s\"" -#ifdef BB_FEATURE_VI_READONLY - "%s" -#endif /* BB_FEATURE_VI_READONLY */ - " %dL, %dC", fn, -#ifdef BB_FEATURE_VI_READONLY - ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""), -#endif /* BB_FEATURE_VI_READONLY */ - li, ch); - if (ch > 0) { - // if the insert is before "dot" then we need to update - if (q <= dot) - dot += ch; - file_modified = TRUE; - } - } else if (strncasecmp((char *) cmd, "rewind", i) == 0) { // rewind cmd line args - if (file_modified == TRUE && useforce != TRUE) { - psbs("No write since last change (:rewind! overrides)"); - } else { - // reset the filenames to edit - optind = fn_start - 1; - editing = 0; - } -#ifdef BB_FEATURE_VI_SET - } else if (strncasecmp((char *) cmd, "set", i) == 0) { // set or clear features - i = 0; // offset into args - if (strlen((char *) args) == 0) { - // print out values of all options - place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen - clear_to_eol(); // clear the line - printf("----------------------------------------\r\n"); -#ifdef BB_FEATURE_VI_SETOPTS - if (!autoindent) - printf("no"); - printf("autoindent "); - if (!err_method) - printf("no"); - printf("flash "); - if (!ignorecase) - printf("no"); - printf("ignorecase "); - if (!showmatch) - printf("no"); - printf("showmatch "); - printf("tabstop=%d ", tabstop); -#endif /* BB_FEATURE_VI_SETOPTS */ - printf("\r\n"); - goto vc2; - } - if (strncasecmp((char *) args, "no", 2) == 0) - i = 2; // ":set noautoindent" -#ifdef BB_FEATURE_VI_SETOPTS - if (strncasecmp((char *) args + i, "autoindent", 10) == 0 || - strncasecmp((char *) args + i, "ai", 2) == 0) { - autoindent = (i == 2) ? 0 : 1; - } - if (strncasecmp((char *) args + i, "flash", 5) == 0 || - strncasecmp((char *) args + i, "fl", 2) == 0) { - err_method = (i == 2) ? 0 : 1; - } - if (strncasecmp((char *) args + i, "ignorecase", 10) == 0 || - strncasecmp((char *) args + i, "ic", 2) == 0) { - ignorecase = (i == 2) ? 0 : 1; - } - if (strncasecmp((char *) args + i, "showmatch", 9) == 0 || - strncasecmp((char *) args + i, "sm", 2) == 0) { - showmatch = (i == 2) ? 0 : 1; - } - if (strncasecmp((char *) args + i, "tabstop", 7) == 0) { - sscanf(strchr((char *) args + i, '='), "=%d", &ch); - if (ch > 0 && ch < columns - 1) - tabstop = ch; - } -#endif /* BB_FEATURE_VI_SETOPTS */ -#endif /* BB_FEATURE_VI_SET */ -#ifdef BB_FEATURE_VI_SEARCH - } else if (strncasecmp((char *) cmd, "s", 1) == 0) { // substitute a pattern with a replacement pattern - Byte *ls, *F, *R; - int gflag; - - // F points to the "find" pattern - // R points to the "replace" pattern - // replace the cmd line delimiters "/" with NULLs - gflag = 0; // global replace flag - c = orig_buf[1]; // what is the delimiter - F = orig_buf + 2; // start of "find" - R = (Byte *) strchr((char *) F, c); // middle delimiter - if (!R) goto colon_s_fail; - *R++ = '\0'; // terminate "find" - buf1 = (Byte *) strchr((char *) R, c); - if (!buf1) goto colon_s_fail; - *buf1++ = '\0'; // terminate "replace" - if (*buf1 == 'g') { // :s/foo/bar/g - buf1++; - gflag++; // turn on gflag - } - q = begin_line(q); - if (b < 0) { // maybe :s/foo/bar/ - q = begin_line(dot); // start with cur line - b = count_lines(text, q); // cur line number - } - if (e < 0) - e = b; // maybe :.s/foo/bar/ - for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 - ls = q; // orig line start - vc4: - buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" - if (buf1 != NULL) { - // we found the "find" pattern- delete it - (void) text_hole_delete(buf1, buf1 + strlen((char *) F) - 1); - // inset the "replace" patern - (void) string_insert(buf1, R); // insert the string - // check for "global" :s/foo/bar/g - if (gflag == 1) { - if ((buf1 + strlen((char *) R)) < end_line(ls)) { - q = buf1 + strlen((char *) R); - goto vc4; // don't let q move past cur line - } - } - } - q = next_line(ls); - } -#endif /* BB_FEATURE_VI_SEARCH */ - } else if (strncasecmp((char *) cmd, "version", i) == 0) { // show software version - psb("%s", vi_Version); - } else if ((strncasecmp((char *) cmd, "write", i) == 0) || // write text to file - (strncasecmp((char *) cmd, "wq", i) == 0)) { // write text to file - // is there a file name to write to? - if (strlen((char *) args) > 0) { - fn = args; - } -#ifdef BB_FEATURE_VI_READONLY - if ((vi_readonly == TRUE || readonly == TRUE) && useforce == FALSE) { - psbs("\"%s\" File is read only", fn); - goto vc3; - } -#endif /* BB_FEATURE_VI_READONLY */ - // how many lines in text[]? - li = count_lines(q, r); - ch = r - q + 1; - // see if file exists- if not, its just a new file request - if (useforce == TRUE) { - // if "fn" is not write-able, chmod u+w - // sprintf(syscmd, "chmod u+w %s", fn); - // system(syscmd); - forced = TRUE; - } - l = file_write(fn, q, r); - if (useforce == TRUE && forced == TRUE) { - // chmod u-w - // sprintf(syscmd, "chmod u-w %s", fn); - // system(syscmd); - forced = FALSE; - } - psb("\"%s\" %dL, %dC", fn, li, l); - if (q == text && r == end - 1 && l == ch) - file_modified = FALSE; - if (cmd[1] == 'q' && l == ch) { - editing = 0; - } -#ifdef BB_FEATURE_VI_READONLY - vc3:; -#endif /* BB_FEATURE_VI_READONLY */ -#ifdef BB_FEATURE_VI_YANKMARK - } else if (strncasecmp((char *) cmd, "yank", i) == 0) { // yank lines - if (b < 0) { // no addr given- use defaults - q = begin_line(dot); // assume .,. for the range - r = end_line(dot); - } - text_yank(q, r, YDreg); - li = count_lines(q, r); - psb("Yank %d lines (%d chars) into [%c]", - li, strlen((char *) reg[YDreg]), what_reg()); -#endif /* BB_FEATURE_VI_YANKMARK */ - } else { - // cmd unknown - ni((Byte *) cmd); - } - vc1: - dot = bound_dot(dot); // make sure "dot" is valid - return; -#ifdef BB_FEATURE_VI_SEARCH -colon_s_fail: - psb(":s expression missing delimiters"); - return; -#endif - -} - -static void Hit_Return(void) -{ - char c; - - standout_start(); // start reverse video - write(1, "[Hit return to continue]", 24); - standout_end(); // end reverse video - while ((c = get_one_char()) != '\n' && c != '\r') /*do nothing */ - ; - redraw(TRUE); // force redraw all -} -#endif /* BB_FEATURE_VI_COLON */ - -//----- Synchronize the cursor to Dot -------------------------- -static void sync_cursor(Byte * d, int *row, int *col) -{ - Byte *beg_cur, *end_cur; // begin and end of "d" line - Byte *beg_scr, *end_scr; // begin and end of screen - Byte *tp; - int cnt, ro, co; - - beg_cur = begin_line(d); // first char of cur line - end_cur = end_line(d); // last char of cur line - - beg_scr = end_scr = screenbegin; // first char of screen - end_scr = end_screen(); // last char of screen - - if (beg_cur < screenbegin) { - // "d" is before top line on screen - // how many lines do we have to move - cnt = count_lines(beg_cur, screenbegin); - sc1: - screenbegin = beg_cur; - if (cnt > (rows - 1) / 2) { - // we moved too many lines. put "dot" in middle of screen - for (cnt = 0; cnt < (rows - 1) / 2; cnt++) { - screenbegin = prev_line(screenbegin); - } - } - } else if (beg_cur > end_scr) { - // "d" is after bottom line on screen - // how many lines do we have to move - cnt = count_lines(end_scr, beg_cur); - if (cnt > (rows - 1) / 2) - goto sc1; // too many lines - for (ro = 0; ro < cnt - 1; ro++) { - // move screen begin the same amount - screenbegin = next_line(screenbegin); - // now, move the end of screen - end_scr = next_line(end_scr); - end_scr = end_line(end_scr); - } - } - // "d" is on screen- find out which row - tp = screenbegin; - for (ro = 0; ro < rows - 1; ro++) { // drive "ro" to correct row - if (tp == beg_cur) - break; - tp = next_line(tp); - } - - // find out what col "d" is on - co = 0; - do { // drive "co" to correct column - if (*tp == '\n' || *tp == '\0') - break; - if (*tp == '\t') { - // 7 - (co % 8 ) - co += ((tabstop - 1) - (co % tabstop)); - } else if (*tp < ' ') { - co++; // display as ^X, use 2 columns - } - } while (tp++ < d && ++co); - - // "co" is the column where "dot" is. - // The screen has "columns" columns. - // The currently displayed columns are 0+offset -- columns+ofset - // |-------------------------------------------------------------| - // ^ ^ ^ - // offset | |------- columns ----------------| - // - // If "co" is already in this range then we do not have to adjust offset - // but, we do have to subtract the "offset" bias from "co". - // If "co" is outside this range then we have to change "offset". - // If the first char of a line is a tab the cursor will try to stay - // in column 7, but we have to set offset to 0. - - if (co < 0 + offset) { - offset = co; - } - if (co >= columns + offset) { - offset = co - columns + 1; - } - // if the first char of the line is a tab, and "dot" is sitting on it - // force offset to 0. - if (d == beg_cur && *d == '\t') { - offset = 0; - } - co -= offset; - - *row = ro; - *col = co; -} - -//----- Text Movement Routines --------------------------------- -static Byte *begin_line(Byte * p) // return pointer to first char cur line -{ - while (p > text && p[-1] != '\n') - p--; // go to cur line B-o-l - return (p); -} - -static Byte *end_line(Byte * p) // return pointer to NL of cur line line -{ - while (p < end - 1 && *p != '\n') - p++; // go to cur line E-o-l - return (p); -} - -static Byte *dollar_line(Byte * p) // return pointer to just before NL line -{ - while (p < end - 1 && *p != '\n') - p++; // go to cur line E-o-l - // Try to stay off of the Newline - if (*p == '\n' && (p - begin_line(p)) > 0) - p--; - return (p); -} - -static Byte *prev_line(Byte * p) // return pointer first char prev line -{ - p = begin_line(p); // goto begining of cur line - if (p[-1] == '\n' && p > text) - p--; // step to prev line - p = begin_line(p); // goto begining of prev line - return (p); -} - -static Byte *next_line(Byte * p) // return pointer first char next line -{ - p = end_line(p); - if (*p == '\n' && p < end - 1) - p++; // step to next line - return (p); -} - -//----- Text Information Routines ------------------------------ -static Byte *end_screen(void) -{ - Byte *q; - int cnt; - - // find new bottom line - q = screenbegin; - for (cnt = 0; cnt < rows - 2; cnt++) - q = next_line(q); - q = end_line(q); - return (q); -} - -static int count_lines(Byte * start, Byte * stop) // count line from start to stop -{ - Byte *q; - int cnt; - - if (stop < start) { // start and stop are backwards- reverse them - q = start; - start = stop; - stop = q; - } - cnt = 0; - stop = end_line(stop); // get to end of this line - for (q = start; q <= stop && q <= end - 1; q++) { - if (*q == '\n') - cnt++; - } - return (cnt); -} - -static Byte *find_line(int li) // find begining of line #li -{ - Byte *q; - - for (q = text; li > 1; li--) { - q = next_line(q); - } - return (q); -} - -//----- Dot Movement Routines ---------------------------------- -static void dot_left(void) -{ - if (dot > text && dot[-1] != '\n') - dot--; -} - -static void dot_right(void) -{ - if (dot < end - 1 && *dot != '\n') - dot++; -} - -static void dot_begin(void) -{ - dot = begin_line(dot); // return pointer to first char cur line -} - -static void dot_end(void) -{ - dot = end_line(dot); // return pointer to last char cur line -} - -static Byte *move_to_col(Byte * p, int l) -{ - int co; - - p = begin_line(p); - co = 0; - do { - if (*p == '\n' || *p == '\0') - break; - if (*p == '\t') { - // 7 - (co % 8 ) - co += ((tabstop - 1) - (co % tabstop)); - } else if (*p < ' ') { - co++; // display as ^X, use 2 columns - } - } while (++co <= l && p++ < end); - return (p); -} - -static void dot_next(void) -{ - dot = next_line(dot); -} - -static void dot_prev(void) -{ - dot = prev_line(dot); -} - -static void dot_scroll(int cnt, int dir) -{ - Byte *q; - - for (; cnt > 0; cnt--) { - if (dir < 0) { - // scroll Backwards - // ctrl-Y scroll up one line - screenbegin = prev_line(screenbegin); - } else { - // scroll Forwards - // ctrl-E scroll down one line - screenbegin = next_line(screenbegin); - } - } - // make sure "dot" stays on the screen so we dont scroll off - if (dot < screenbegin) - dot = screenbegin; - q = end_screen(); // find new bottom line - if (dot > q) - dot = begin_line(q); // is dot is below bottom line? - dot_skip_over_ws(); -} - -static void dot_skip_over_ws(void) -{ - // skip WS - while (isspace(*dot) && *dot != '\n' && dot < end - 1) - dot++; -} - -static void dot_delete(void) // delete the char at 'dot' -{ - (void) text_hole_delete(dot, dot); -} - -static Byte *bound_dot(Byte * p) // make sure text[0] <= P < "end" -{ - if (p >= end && end > text) { - p = end - 1; - indicate_error('1'); - } - if (p < text) { - p = text; - indicate_error('2'); - } - return (p); -} - -//----- Helper Utility Routines -------------------------------- - -//---------------------------------------------------------------- -//----- Char Routines -------------------------------------------- -/* Chars that are part of a word- - * 0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz - * Chars that are Not part of a word (stoppers) - * !"#$%&'()*+,-./:;<=>?@[\]^`{|}~ - * Chars that are WhiteSpace - * TAB NEWLINE VT FF RETURN SPACE - * DO NOT COUNT NEWLINE AS WHITESPACE - */ - -static Byte *new_screen(int ro, int co) -{ - int li; - - if (screen != 0) - free(screen); - screensize = ro * co + 8; - screen = (Byte *) malloc(screensize); - // initialize the new screen. assume this will be a empty file. - screen_erase(); - // non-existant text[] lines start with a tilde (~). - for (li = 1; li < ro - 1; li++) { - screen[(li * co) + 0] = '~'; - } - return (screen); -} - -static Byte *new_text(int size) -{ - if (size < 10240) - size = 10240; // have a minimum size for new files - if (text != 0) { - //text -= 4; - free(text); - } - text = (Byte *) malloc(size + 8); - memset(text, '\0', size); // clear new text[] - //text += 4; // leave some room for "oops" - textend = text + size - 1; - //textend -= 4; // leave some root for "oops" - return (text); -} - -#ifdef BB_FEATURE_VI_SEARCH -static int mycmp(Byte * s1, Byte * s2, int len) -{ - int i; - - i = strncmp((char *) s1, (char *) s2, len); -#ifdef BB_FEATURE_VI_SETOPTS - if (ignorecase) { - i = strncasecmp((char *) s1, (char *) s2, len); - } -#endif /* BB_FEATURE_VI_SETOPTS */ - return (i); -} - -static Byte *char_search(Byte * p, Byte * pat, int dir, int range) // search for pattern starting at p -{ -#ifndef REGEX_SEARCH - Byte *start, *stop; - int len; - - len = strlen((char *) pat); - if (dir == FORWARD) { - stop = end - 1; // assume range is p - end-1 - if (range == LIMITED) - stop = next_line(p); // range is to next line - for (start = p; start < stop; start++) { - if (mycmp(start, pat, len) == 0) { - return (start); - } - } - } else if (dir == BACK) { - stop = text; // assume range is text - p - if (range == LIMITED) - stop = prev_line(p); // range is to prev line - for (start = p - len; start >= stop; start--) { - if (mycmp(start, pat, len) == 0) { - return (start); - } - } - } - // pattern not found - return (NULL); -#else /*REGEX_SEARCH */ - char *q; - struct re_pattern_buffer preg; - int i; - int size, range; - - re_syntax_options = RE_SYNTAX_POSIX_EXTENDED; - preg.translate = 0; - preg.fastmap = 0; - preg.buffer = 0; - preg.allocated = 0; - - // assume a LIMITED forward search - q = next_line(p); - q = end_line(q); - q = end - 1; - if (dir == BACK) { - q = prev_line(p); - q = text; - } - // count the number of chars to search over, forward or backward - size = q - p; - if (size < 0) - size = p - q; - // RANGE could be negative if we are searching backwards - range = q - p; - - q = (char *) re_compile_pattern(pat, strlen((char *) pat), &preg); - if (q != 0) { - // The pattern was not compiled - psbs("bad search pattern: \"%s\": %s", pat, q); - i = 0; // return p if pattern not compiled - goto cs1; - } - - q = p; - if (range < 0) { - q = p - size; - if (q < text) - q = text; - } - // search for the compiled pattern, preg, in p[] - // range < 0- search backward - // range > 0- search forward - // 0 < start < size - // re_search() < 0 not found or error - // re_search() > 0 index of found pattern - // struct pattern char int int int struct reg - // re_search (*pattern_buffer, *string, size, start, range, *regs) - i = re_search(&preg, q, size, 0, range, 0); - if (i == -1) { - p = 0; - i = 0; // return NULL if pattern not found - } - cs1: - if (dir == FORWARD) { - p = p + i; - } else { - p = p - i; - } - return (p); -#endif /*REGEX_SEARCH */ -} -#endif /* BB_FEATURE_VI_SEARCH */ - -static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p' -{ - if (c == 22) { // Is this an ctrl-V? - p = stupid_insert(p, '^'); // use ^ to indicate literal next - p--; // backup onto ^ - refresh(FALSE); // show the ^ - c = get_one_char(); - *p = c; - p++; - file_modified = TRUE; // has the file been modified - } else if (c == 27) { // Is this an ESC? - cmd_mode = 0; - cmdcnt = 0; - end_cmd_q(); // stop adding to q - strcpy((char *) status_buffer, " "); // clear the status buffer - if ((p[-1] != '\n') && (dot>text)) { - p--; - } - } else if (c == erase_char) { // Is this a BS - // 123456789 - if ((p[-1] != '\n') && (dot>text)) { - p--; - p = text_hole_delete(p, p); // shrink buffer 1 char -#ifdef BB_FEATURE_VI_DOT_CMD - // also rmove char from last_modifying_cmd - if (strlen((char *) last_modifying_cmd) > 0) { - Byte *q; - - q = last_modifying_cmd; - q[strlen((char *) q) - 1] = '\0'; // erase BS - q[strlen((char *) q) - 1] = '\0'; // erase prev char - } -#endif /* BB_FEATURE_VI_DOT_CMD */ - } - } else { - // insert a char into text[] - Byte *sp; // "save p" - - if (c == 13) - c = '\n'; // translate \r to \n - sp = p; // remember addr of insert - p = stupid_insert(p, c); // insert the char -#ifdef BB_FEATURE_VI_SETOPTS - if (showmatch && strchr(")]}", *sp) != NULL) { - showmatching(sp); - } - if (autoindent && c == '\n') { // auto indent the new line - Byte *q; - - q = prev_line(p); // use prev line as templet - for (; isblnk(*q); q++) { - p = stupid_insert(p, *q); // insert the char - } - } -#endif /* BB_FEATURE_VI_SETOPTS */ - } - return (p); -} - -static Byte *stupid_insert(Byte * p, Byte c) // stupidly insert the char c at 'p' -{ - p = text_hole_make(p, 1); - if (p != 0) { - *p = c; - file_modified = TRUE; // has the file been modified - p++; - } - return (p); -} - -static Byte find_range(Byte ** start, Byte ** stop, Byte c) -{ - Byte *save_dot, *p, *q; - int cnt; - - save_dot = dot; - p = q = dot; - - if (strchr("cdy><", c)) { - // these cmds operate on whole lines - p = q = begin_line(p); - for (cnt = 1; cnt < cmdcnt; cnt++) { - q = next_line(q); - } - q = end_line(q); - } else if (strchr("^%$0bBeEft", c)) { - // These cmds operate on char positions - do_cmd(c); // execute movement cmd - q = dot; - } else if (strchr("wW", c)) { - do_cmd(c); // execute movement cmd - if (dot > text) - dot--; // move back off of next word - if (dot > text && *dot == '\n') - dot--; // stay off NL - q = dot; - } else if (strchr("H-k{", c)) { - // these operate on multi-lines backwards - q = end_line(dot); // find NL - do_cmd(c); // execute movement cmd - dot_begin(); - p = dot; - } else if (strchr("L+j}\r\n", c)) { - // these operate on multi-lines forwards - p = begin_line(dot); - do_cmd(c); // execute movement cmd - dot_end(); // find NL - q = dot; - } else { - c = 27; // error- return an ESC char - //break; - } - *start = p; - *stop = q; - if (q < p) { - *start = q; - *stop = p; - } - dot = save_dot; - return (c); -} - -static int st_test(Byte * p, int type, int dir, Byte * tested) -{ - Byte c, c0, ci; - int test, inc; - - inc = dir; - c = c0 = p[0]; - ci = p[inc]; - test = 0; - - if (type == S_BEFORE_WS) { - c = ci; - test = ((!isspace(c)) || c == '\n'); - } - if (type == S_TO_WS) { - c = c0; - test = ((!isspace(c)) || c == '\n'); - } - if (type == S_OVER_WS) { - c = c0; - test = ((isspace(c))); - } - if (type == S_END_PUNCT) { - c = ci; - test = ((ispunct(c))); - } - if (type == S_END_ALNUM) { - c = ci; - test = ((isalnum(c)) || c == '_'); - } - *tested = c; - return (test); -} - -static Byte *skip_thing(Byte * p, int linecnt, int dir, int type) -{ - Byte c; - - while (st_test(p, type, dir, &c)) { - // make sure we limit search to correct number of lines - if (c == '\n' && --linecnt < 1) - break; - if (dir >= 0 && p >= end - 1) - break; - if (dir < 0 && p <= text) - break; - p += dir; // move to next char - } - return (p); -} - -// find matching char of pair () [] {} -static Byte *find_pair(Byte * p, Byte c) -{ - Byte match, *q; - int dir, level; - - match = ')'; - level = 1; - dir = 1; // assume forward - switch (c) { - case '(': - match = ')'; - break; - case '[': - match = ']'; - break; - case '{': - match = '}'; - break; - case ')': - match = '('; - dir = -1; - break; - case ']': - match = '['; - dir = -1; - break; - case '}': - match = '{'; - dir = -1; - break; - } - for (q = p + dir; text <= q && q < end; q += dir) { - // look for match, count levels of pairs (( )) - if (*q == c) - level++; // increase pair levels - if (*q == match) - level--; // reduce pair level - if (level == 0) - break; // found matching pair - } - if (level != 0) - q = NULL; // indicate no match - return (q); -} - -#ifdef BB_FEATURE_VI_SETOPTS -// show the matching char of a pair, () [] {} -static void showmatching(Byte * p) -{ - Byte *q, *save_dot; - - // we found half of a pair - q = find_pair(p, *p); // get loc of matching char - if (q == NULL) { - indicate_error('3'); // no matching char - } else { - // "q" now points to matching pair - save_dot = dot; // remember where we are - dot = q; // go to new loc - refresh(FALSE); // let the user see it - (void) mysleep(40); // give user some time - dot = save_dot; // go back to old loc - refresh(FALSE); - } -} -#endif /* BB_FEATURE_VI_SETOPTS */ - -// open a hole in text[] -static Byte *text_hole_make(Byte * p, int size) // at "p", make a 'size' byte hole -{ - Byte *src, *dest; - int cnt; - - if (size <= 0) - goto thm0; - src = p; - dest = p + size; - cnt = end - src; // the rest of buffer - if (memmove(dest, src, cnt) != dest) { - psbs("can't create room for new characters"); - } - memset(p, ' ', size); // clear new hole - end = end + size; // adjust the new END - file_modified = TRUE; // has the file been modified - thm0: - return (p); -} - -// close a hole in text[] -static Byte *text_hole_delete(Byte * p, Byte * q) // delete "p" thru "q", inclusive -{ - Byte *src, *dest; - int cnt, hole_size; - - // move forwards, from beginning - // assume p <= q - src = q + 1; - dest = p; - if (q < p) { // they are backward- swap them - src = p + 1; - dest = q; - } - hole_size = q - p + 1; - cnt = end - src; - if (src < text || src > end) - goto thd0; - if (dest < text || dest >= end) - goto thd0; - if (src >= end) - goto thd_atend; // just delete the end of the buffer - if (memmove(dest, src, cnt) != dest) { - psbs("can't delete the character"); - } - thd_atend: - end = end - hole_size; // adjust the new END - if (dest >= end) - dest = end - 1; // make sure dest in below end-1 - if (end <= text) - dest = end = text; // keep pointers valid - file_modified = TRUE; // has the file been modified - thd0: - return (dest); -} - -// copy text into register, then delete text. -// if dist <= 0, do not include, or go past, a NewLine -// -static Byte *yank_delete(Byte * start, Byte * stop, int dist, int yf) -{ - Byte *p; - - // make sure start <= stop - if (start > stop) { - // they are backwards, reverse them - p = start; - start = stop; - stop = p; - } - if (dist <= 0) { - // we can not cross NL boundaries - p = start; - if (*p == '\n') - return (p); - // dont go past a NewLine - for (; p + 1 <= stop; p++) { - if (p[1] == '\n') { - stop = p; // "stop" just before NewLine - break; - } - } - } - p = start; -#ifdef BB_FEATURE_VI_YANKMARK - text_yank(start, stop, YDreg); -#endif /* BB_FEATURE_VI_YANKMARK */ - if (yf == YANKDEL) { - p = text_hole_delete(start, stop); - } // delete lines - return (p); -} - -static void show_help(void) -{ - puts("These features are available:" -#ifdef BB_FEATURE_VI_SEARCH - "\n\tPattern searches with / and ?" -#endif /* BB_FEATURE_VI_SEARCH */ -#ifdef BB_FEATURE_VI_DOT_CMD - "\n\tLast command repeat with \'.\'" -#endif /* BB_FEATURE_VI_DOT_CMD */ -#ifdef BB_FEATURE_VI_YANKMARK - "\n\tLine marking with 'x" - "\n\tNamed buffers with \"x" -#endif /* BB_FEATURE_VI_YANKMARK */ -#ifdef BB_FEATURE_VI_READONLY - "\n\tReadonly if vi is called as \"view\"" - "\n\tReadonly with -R command line arg" -#endif /* BB_FEATURE_VI_READONLY */ -#ifdef BB_FEATURE_VI_SET - "\n\tSome colon mode commands with \':\'" -#endif /* BB_FEATURE_VI_SET */ -#ifdef BB_FEATURE_VI_SETOPTS - "\n\tSettable options with \":set\"" -#endif /* BB_FEATURE_VI_SETOPTS */ -#ifdef BB_FEATURE_VI_USE_SIGNALS - "\n\tSignal catching- ^C" - "\n\tJob suspend and resume with ^Z" -#endif /* BB_FEATURE_VI_USE_SIGNALS */ -#ifdef BB_FEATURE_VI_WIN_RESIZE - "\n\tAdapt to window re-sizes" -#endif /* BB_FEATURE_VI_WIN_RESIZE */ - ); -} - -static void print_literal(Byte * buf, Byte * s) // copy s to buf, convert unprintable -{ - Byte c, b[2]; - - b[1] = '\0'; - strcpy((char *) buf, ""); // init buf - if (strlen((char *) s) <= 0) - s = (Byte *) "(NULL)"; - for (; *s > '\0'; s++) { - c = *s; - if (*s > '~') { - strcat((char *) buf, SOs); - c = *s - 128; - } - if (*s < ' ') { - strcat((char *) buf, "^"); - c += '@'; - } - b[0] = c; - strcat((char *) buf, (char *) b); - if (*s > '~') - strcat((char *) buf, SOn); - if (*s == '\n') { - strcat((char *) buf, "$"); - } - } -} - -#ifdef BB_FEATURE_VI_DOT_CMD -static void start_new_cmd_q(Byte c) -{ - // release old cmd - if (last_modifying_cmd != 0) - free(last_modifying_cmd); - // get buffer for new cmd - last_modifying_cmd = (Byte *) malloc(BUFSIZ); - memset(last_modifying_cmd, '\0', BUFSIZ); // clear new cmd queue - // if there is a current cmd count put it in the buffer first - if (cmdcnt > 0) - sprintf((char *) last_modifying_cmd, "%d", cmdcnt); - // save char c onto queue - last_modifying_cmd[strlen((char *) last_modifying_cmd)] = c; - adding2q = 1; - return; -} - -static void end_cmd_q() -{ -#ifdef BB_FEATURE_VI_YANKMARK - YDreg = 26; // go back to default Yank/Delete reg -#endif /* BB_FEATURE_VI_YANKMARK */ - adding2q = 0; - return; -} -#endif /* BB_FEATURE_VI_DOT_CMD */ - -#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME) -static Byte *string_insert(Byte * p, Byte * s) // insert the string at 'p' -{ - int cnt, i; - - i = strlen((char *) s); - p = text_hole_make(p, i); - strncpy((char *) p, (char *) s, i); - for (cnt = 0; *s != '\0'; s++) { - if (*s == '\n') - cnt++; - } -#ifdef BB_FEATURE_VI_YANKMARK - psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); -#endif /* BB_FEATURE_VI_YANKMARK */ - return (p); -} -#endif /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */ - -#ifdef BB_FEATURE_VI_YANKMARK -static Byte *text_yank(Byte * p, Byte * q, int dest) // copy text into a register -{ - Byte *t; - int cnt; - - if (q < p) { // they are backwards- reverse them - t = q; - q = p; - p = t; - } - cnt = q - p + 1; - t = reg[dest]; - if (t != 0) { // if already a yank register - free(t); // free it - } - t = (Byte *) malloc(cnt + 1); // get a new register - memset(t, '\0', cnt + 1); // clear new text[] - strncpy((char *) t, (char *) p, cnt); // copy text[] into bufer - reg[dest] = t; - return (p); -} - -static Byte what_reg(void) -{ - Byte c; - int i; - - i = 0; - c = 'D'; // default to D-reg - if (0 <= YDreg && YDreg <= 25) - c = 'a' + (Byte) YDreg; - if (YDreg == 26) - c = 'D'; - if (YDreg == 27) - c = 'U'; - return (c); -} - -static void check_context(Byte cmd) -{ - // A context is defined to be "modifying text" - // Any modifying command establishes a new context. - - if (dot < context_start || dot > context_end) { - if (strchr((char *) modifying_cmds, cmd) != NULL) { - // we are trying to modify text[]- make this the current context - mark[27] = mark[26]; // move cur to prev - mark[26] = dot; // move local to cur - context_start = prev_line(prev_line(dot)); - context_end = next_line(next_line(dot)); - //loiter= start_loiter= now; - } - } - return; -} - -static Byte *swap_context(Byte * p) // goto new context for '' command make this the current context -{ - Byte *tmp; - - // the current context is in mark[26] - // the previous context is in mark[27] - // only swap context if other context is valid - if (text <= mark[27] && mark[27] <= end - 1) { - tmp = mark[27]; - mark[27] = mark[26]; - mark[26] = tmp; - p = mark[26]; // where we are going- previous context - context_start = prev_line(prev_line(prev_line(p))); - context_end = next_line(next_line(next_line(p))); - } - return (p); -} -#endif /* BB_FEATURE_VI_YANKMARK */ - -static int isblnk(Byte c) // is the char a blank or tab -{ - return (c == ' ' || c == '\t'); -} - -//----- Set terminal attributes -------------------------------- -static void rawmode(void) -{ - tcgetattr(0, &term_orig); - term_vi = term_orig; - term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's - term_vi.c_iflag &= (~IXON & ~ICRNL); - term_vi.c_oflag &= (~ONLCR); -#ifndef linux - term_vi.c_cc[VMIN] = 1; - term_vi.c_cc[VTIME] = 0; -#endif - erase_char = term_vi.c_cc[VERASE]; - tcsetattr(0, TCSANOW, &term_vi); -} - -static void cookmode(void) -{ - tcsetattr(0, TCSANOW, &term_orig); -} - -#ifdef BB_FEATURE_VI_WIN_RESIZE -//----- See what the window size currently is -------------------- -static void window_size_get(int sig) -{ - int i; - - i = ioctl(0, TIOCGWINSZ, &winsize); - if (i != 0) { - // force 24x80 - winsize.ws_row = 24; - winsize.ws_col = 80; - } - if (winsize.ws_row <= 1) { - winsize.ws_row = 24; - } - if (winsize.ws_col <= 1) { - winsize.ws_col = 80; - } - rows = (int) winsize.ws_row; - columns = (int) winsize.ws_col; -} -#endif /* BB_FEATURE_VI_WIN_RESIZE */ - -//----- Come here when we get a window resize signal --------- -#ifdef BB_FEATURE_VI_USE_SIGNALS -static void winch_sig(int sig) -{ - signal(SIGWINCH, winch_sig); -#ifdef BB_FEATURE_VI_WIN_RESIZE - window_size_get(0); -#endif /* BB_FEATURE_VI_WIN_RESIZE */ - new_screen(rows, columns); // get memory for virtual screen - redraw(TRUE); // re-draw the screen -} - -//----- Come here when we get a continue signal ------------------- -static void cont_sig(int sig) -{ - rawmode(); // terminal to "raw" - *status_buffer = '\0'; // clear the status buffer - redraw(TRUE); // re-draw the screen - - signal(SIGTSTP, suspend_sig); - signal(SIGCONT, SIG_DFL); - kill(getpid(), SIGCONT); -} - -//----- Come here when we get a Suspend signal ------------------- -static void suspend_sig(int sig) -{ - place_cursor(rows - 1, 0, FALSE); // go to bottom of screen - clear_to_eol(); // Erase to end of line - cookmode(); // terminal to "cooked" - - signal(SIGCONT, cont_sig); - signal(SIGTSTP, SIG_DFL); - kill(getpid(), SIGTSTP); -} - -//----- Come here when we get a signal --------------------------- -static void catch_sig(int sig) -{ - signal(SIGHUP, catch_sig); - signal(SIGINT, catch_sig); - signal(SIGTERM, catch_sig); - longjmp(restart, sig); -} - -static void alarm_sig(int sig) -{ - signal(SIGALRM, catch_sig); - longjmp(restart, sig); -} - -//----- Come here when we get a core dump signal ----------------- -static void core_sig(int sig) -{ - signal(SIGQUIT, core_sig); - signal(SIGILL, core_sig); - signal(SIGTRAP, core_sig); - signal(SIGIOT, core_sig); - signal(SIGABRT, core_sig); - signal(SIGFPE, core_sig); - signal(SIGBUS, core_sig); - signal(SIGSEGV, core_sig); -#ifdef SIGSYS - signal(SIGSYS, core_sig); -#endif - - dot = bound_dot(dot); // make sure "dot" is valid - - longjmp(restart, sig); -} -#endif /* BB_FEATURE_VI_USE_SIGNALS */ - -static int mysleep(int hund) // sleep for 'h' 1/100 seconds -{ - // Don't hang- Wait 5/100 seconds- 1 Sec= 1000000 - FD_ZERO(&rfds); - FD_SET(0, &rfds); - tv.tv_sec = 0; - tv.tv_usec = hund * 10000; - select(1, &rfds, NULL, NULL, &tv); - return (FD_ISSET(0, &rfds)); -} - -//----- IO Routines -------------------------------------------- -static Byte readit(void) // read (maybe cursor) key from stdin -{ - Byte c; - int i, bufsiz, cnt, cmdindex; - struct esc_cmds { - Byte *seq; - Byte val; - }; - - static struct esc_cmds esccmds[] = { - {(Byte *) "OA", (Byte) VI_K_UP}, // cursor key Up - {(Byte *) "OB", (Byte) VI_K_DOWN}, // cursor key Down - {(Byte *) "OC", (Byte) VI_K_RIGHT}, // Cursor Key Right - {(Byte *) "OD", (Byte) VI_K_LEFT}, // cursor key Left - {(Byte *) "OH", (Byte) VI_K_HOME}, // Cursor Key Home - {(Byte *) "OF", (Byte) VI_K_END}, // Cursor Key End - {(Byte *) "", (Byte) VI_K_UP}, // cursor key Up - {(Byte *) "", (Byte) VI_K_DOWN}, // cursor key Down - {(Byte *) "", (Byte) VI_K_RIGHT}, // Cursor Key Right - {(Byte *) "", (Byte) VI_K_LEFT}, // cursor key Left - {(Byte *) "", (Byte) VI_K_HOME}, // Cursor Key Home - {(Byte *) "", (Byte) VI_K_END}, // Cursor Key End - {(Byte *) "[2~", (Byte) VI_K_INSERT}, // Cursor Key Insert - {(Byte *) "[5~", (Byte) VI_K_PAGEUP}, // Cursor Key Page Up - {(Byte *) "[6~", (Byte) VI_K_PAGEDOWN}, // Cursor Key Page Down - {(Byte *) "OP", (Byte) VI_K_FUN1}, // Function Key F1 - {(Byte *) "OQ", (Byte) VI_K_FUN2}, // Function Key F2 - {(Byte *) "OR", (Byte) VI_K_FUN3}, // Function Key F3 - {(Byte *) "OS", (Byte) VI_K_FUN4}, // Function Key F4 - {(Byte *) "[15~", (Byte) VI_K_FUN5}, // Function Key F5 - {(Byte *) "[17~", (Byte) VI_K_FUN6}, // Function Key F6 - {(Byte *) "[18~", (Byte) VI_K_FUN7}, // Function Key F7 - {(Byte *) "[19~", (Byte) VI_K_FUN8}, // Function Key F8 - {(Byte *) "[20~", (Byte) VI_K_FUN9}, // Function Key F9 - {(Byte *) "[21~", (Byte) VI_K_FUN10}, // Function Key F10 - {(Byte *) "[23~", (Byte) VI_K_FUN11}, // Function Key F11 - {(Byte *) "[24~", (Byte) VI_K_FUN12}, // Function Key F12 - {(Byte *) "[11~", (Byte) VI_K_FUN1}, // Function Key F1 - {(Byte *) "[12~", (Byte) VI_K_FUN2}, // Function Key F2 - {(Byte *) "[13~", (Byte) VI_K_FUN3}, // Function Key F3 - {(Byte *) "[14~", (Byte) VI_K_FUN4}, // Function Key F4 - }; - -#define ESCCMDS_COUNT (sizeof(esccmds)/sizeof(struct esc_cmds)) - - (void) alarm(0); // turn alarm OFF while we wait for input - // get input from User- are there already input chars in Q? - bufsiz = strlen((char *) readbuffer); - if (bufsiz <= 0) { - ri0: - // the Q is empty, wait for a typed char - bufsiz = read(0, readbuffer, BUFSIZ - 1); - if (bufsiz < 0) { - if (errno == EINTR) - goto ri0; // interrupted sys call - if (errno == EBADF) - editing = 0; - if (errno == EFAULT) - editing = 0; - if (errno == EINVAL) - editing = 0; - if (errno == EIO) - editing = 0; - errno = 0; - bufsiz = 0; - } - readbuffer[bufsiz] = '\0'; - } - // return char if it is not part of ESC sequence - if (readbuffer[0] != 27) - goto ri1; - - // This is an ESC char. Is this Esc sequence? - // Could be bare Esc key. See if there are any - // more chars to read after the ESC. This would - // be a Function or Cursor Key sequence. - FD_ZERO(&rfds); - FD_SET(0, &rfds); - tv.tv_sec = 0; - tv.tv_usec = 50000; // Wait 5/100 seconds- 1 Sec=1000000 - - // keep reading while there are input chars and room in buffer - while (select(1, &rfds, NULL, NULL, &tv) > 0 && bufsiz <= (BUFSIZ - 5)) { - // read the rest of the ESC string - i = read(0, (void *) (readbuffer + bufsiz), BUFSIZ - bufsiz); - if (i > 0) { - bufsiz += i; - readbuffer[bufsiz] = '\0'; // Terminate the string - } - } - // Maybe cursor or function key? - for (cmdindex = 0; cmdindex < ESCCMDS_COUNT; cmdindex++) { - cnt = strlen((char *) esccmds[cmdindex].seq); - i = strncmp((char *) esccmds[cmdindex].seq, (char *) readbuffer, cnt); - if (i == 0) { - // is a Cursor key- put derived value back into Q - readbuffer[0] = esccmds[cmdindex].val; - // squeeze out the ESC sequence - for (i = 1; i < cnt; i++) { - memmove(readbuffer + 1, readbuffer + 2, BUFSIZ - 2); - readbuffer[BUFSIZ - 1] = '\0'; - } - break; - } - } - ri1: - c = readbuffer[0]; - // remove one char from Q - memmove(readbuffer, readbuffer + 1, BUFSIZ - 1); - readbuffer[BUFSIZ - 1] = '\0'; - (void) alarm(3); // we are done waiting for input, turn alarm ON - return (c); -} - -//----- IO Routines -------------------------------------------- -static Byte get_one_char() -{ - static Byte c; - -#ifdef BB_FEATURE_VI_DOT_CMD - // ! adding2q && ioq == 0 read() - // ! adding2q && ioq != 0 *ioq - // adding2q *last_modifying_cmd= read() - if (!adding2q) { - // we are not adding to the q. - // but, we may be reading from a q - if (ioq == 0) { - // there is no current q, read from STDIN - c = readit(); // get the users input - } else { - // there is a queue to get chars from first - c = *ioq++; - if (c == '\0') { - // the end of the q, read from STDIN - free(ioq_start); - ioq_start = ioq = 0; - c = readit(); // get the users input - } - } - } else { - // adding STDIN chars to q - c = readit(); // get the users input - if (last_modifying_cmd != 0) { - // add new char to q - last_modifying_cmd[strlen((char *) last_modifying_cmd)] = c; - } - } -#else /* BB_FEATURE_VI_DOT_CMD */ - c = readit(); // get the users input -#endif /* BB_FEATURE_VI_DOT_CMD */ - return (c); // return the char, where ever it came from -} - -static Byte *get_input_line(Byte * prompt) // get input line- use "status line" -{ - Byte buf[BUFSIZ]; - Byte c; - int i; - static Byte *obufp = NULL; - - strcpy((char *) buf, (char *) prompt); - *status_buffer = '\0'; // clear the status buffer - place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen - clear_to_eol(); // clear the line - write(1, prompt, strlen((char *) prompt)); // write out the :, /, or ? prompt - - for (i = strlen((char *) buf); i < BUFSIZ;) { - c = get_one_char(); // read user input - if (c == '\n' || c == '\r' || c == 27) - break; // is this end of input - if (c == erase_char) { // user wants to erase prev char - i--; // backup to prev char - buf[i] = '\0'; // erase the char - buf[i + 1] = '\0'; // null terminate buffer - write(1, " ", 3); // erase char on screen - if (i <= 0) { // user backs up before b-o-l, exit - break; - } - } else { - buf[i] = c; // save char in buffer - buf[i + 1] = '\0'; // make sure buffer is null terminated - write(1, buf + i, 1); // echo the char back to user - i++; - } - } - refresh(FALSE); - if (obufp != NULL) - free(obufp); - obufp = (Byte *) strdup((char *) buf); - return (obufp); -} - -static int file_size(Byte * fn) // what is the byte size of "fn" -{ - struct stat st_buf; - int cnt, sr; - - if (fn == 0 || strlen(fn) <= 0) - return (-1); - cnt = -1; - sr = stat((char *) fn, &st_buf); // see if file exists - if (sr >= 0) { - cnt = (int) st_buf.st_size; - } - return (cnt); -} - -static int file_insert(Byte * fn, Byte * p, int size) -{ - int fd, cnt; - - cnt = -1; -#ifdef BB_FEATURE_VI_READONLY - readonly = FALSE; -#endif /* BB_FEATURE_VI_READONLY */ - if (fn == 0 || strlen((char*) fn) <= 0) { - psbs("No filename given"); - goto fi0; - } - if (size == 0) { - // OK- this is just a no-op - cnt = 0; - goto fi0; - } - if (size < 0) { - psbs("Trying to insert a negative number (%d) of characters", size); - goto fi0; - } - if (p < text || p > end) { - psbs("Trying to insert file outside of memory"); - goto fi0; - } - - // see if we can open the file -#ifdef BB_FEATURE_VI_READONLY - if (vi_readonly == TRUE) goto fi1; // do not try write-mode -#endif - fd = open((char *) fn, O_RDWR); // assume read & write - if (fd < 0) { - // could not open for writing- maybe file is read only -#ifdef BB_FEATURE_VI_READONLY - fi1: -#endif - fd = open((char *) fn, O_RDONLY); // try read-only - if (fd < 0) { - psbs("\"%s\" %s", fn, "could not open file"); - goto fi0; - } -#ifdef BB_FEATURE_VI_READONLY - // got the file- read-only - readonly = TRUE; -#endif /* BB_FEATURE_VI_READONLY */ - } - p = text_hole_make(p, size); - cnt = read(fd, p, size); - close(fd); - if (cnt < 0) { - cnt = -1; - p = text_hole_delete(p, p + size - 1); // un-do buffer insert - psbs("could not read file \"%s\"", fn); - } else if (cnt < size) { - // There was a partial read, shrink unused space text[] - p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert - psbs("could not read all of file \"%s\"", fn); - } - if (cnt >= size) - file_modified = TRUE; - fi0: - return (cnt); -} - -static int file_write(Byte * fn, Byte * first, Byte * last) -{ - int fd, cnt, charcnt; - - if (fn == 0) { - psbs("No current filename"); - return (-1); - } - charcnt = 0; - // FIXIT- use the correct umask() - fd = open((char *) fn, (O_WRONLY | O_CREAT | O_TRUNC), 0664); - if (fd < 0) - return (-1); - cnt = last - first + 1; - charcnt = write(fd, first, cnt); - if (charcnt == cnt) { - // good write - //file_modified= FALSE; // the file has not been modified - } else { - charcnt = 0; - } - close(fd); - return (charcnt); -} - -//----- Terminal Drawing --------------------------------------- -// The terminal is made up of 'rows' line of 'columns' columns. -// classicly this would be 24 x 80. -// screen coordinates -// 0,0 ... 0,79 -// 1,0 ... 1,79 -// . ... . -// . ... . -// 22,0 ... 22,79 -// 23,0 ... 23,79 status line -// - -//----- Move the cursor to row x col (count from 0, not 1) ------- -static void place_cursor(int row, int col, int opti) -{ - char cm1[BUFSIZ]; - char *cm; - int l; -#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR - char cm2[BUFSIZ]; - Byte *screenp; - // char cm3[BUFSIZ]; - int Rrow= last_row; -#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ - - memset(cm1, '\0', BUFSIZ - 1); // clear the buffer - - if (row < 0) row = 0; - if (row >= rows) row = rows - 1; - if (col < 0) col = 0; - if (col >= columns) col = columns - 1; - - //----- 1. Try the standard terminal ESC sequence - sprintf((char *) cm1, CMrc, row + 1, col + 1); - cm= cm1; - if (opti == FALSE) goto pc0; - -#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR - //----- find the minimum # of chars to move cursor ------------- - //----- 2. Try moving with discreet chars (Newline, [back]space, ...) - memset(cm2, '\0', BUFSIZ - 1); // clear the buffer - - // move to the correct row - while (row < Rrow) { - // the cursor has to move up - strcat(cm2, CMup); - Rrow--; - } - while (row > Rrow) { - // the cursor has to move down - strcat(cm2, CMdown); - Rrow++; - } - - // now move to the correct column - strcat(cm2, "\r"); // start at col 0 - // just send out orignal source char to get to correct place - screenp = &screen[row * columns]; // start of screen line - strncat(cm2, screenp, col); - - //----- 3. Try some other way of moving cursor - //--------------------------------------------- - - // pick the shortest cursor motion to send out - cm= cm1; - if (strlen(cm2) < strlen(cm)) { - cm= cm2; - } /* else if (strlen(cm3) < strlen(cm)) { - cm= cm3; - } */ -#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ - pc0: - l= strlen(cm); - if (l) write(1, cm, l); // move the cursor -} - -//----- Erase from cursor to end of line ----------------------- -static void clear_to_eol() -{ - write(1, Ceol, strlen(Ceol)); // Erase from cursor to end of line -} - -//----- Erase from cursor to end of screen ----------------------- -static void clear_to_eos() -{ - write(1, Ceos, strlen(Ceos)); // Erase from cursor to end of screen -} - -//----- Start standout mode ------------------------------------ -static void standout_start() // send "start reverse video" sequence -{ - write(1, SOs, strlen(SOs)); // Start reverse video mode -} - -//----- End standout mode -------------------------------------- -static void standout_end() // send "end reverse video" sequence -{ - write(1, SOn, strlen(SOn)); // End reverse video mode -} - -//----- Flash the screen -------------------------------------- -static void flash(int h) -{ - standout_start(); // send "start reverse video" sequence - redraw(TRUE); - (void) mysleep(h); - standout_end(); // send "end reverse video" sequence - redraw(TRUE); -} - -static void beep() -{ - write(1, bell, strlen(bell)); // send out a bell character -} - -static void indicate_error(char c) -{ -#ifdef BB_FEATURE_VI_CRASHME - if (crashme > 0) - return; // generate a random command -#endif /* BB_FEATURE_VI_CRASHME */ - if (err_method == 0) { - beep(); - } else { - flash(10); - } -} - -//----- Screen[] Routines -------------------------------------- -//----- Erase the Screen[] memory ------------------------------ -static void screen_erase() -{ - memset(screen, ' ', screensize); // clear new screen -} - -//----- Draw the status line at bottom of the screen ------------- -static void show_status_line(void) -{ - static int last_cksum; - int l, cnt, cksum; - - cnt = strlen((char *) status_buffer); - for (cksum= l= 0; l < cnt; l++) { cksum += (int)(status_buffer[l]); } - // don't write the status line unless it changes - if (cnt > 0 && last_cksum != cksum) { - last_cksum= cksum; // remember if we have seen this line - place_cursor(rows - 1, 0, FALSE); // put cursor on status line - write(1, status_buffer, cnt); - clear_to_eol(); - place_cursor(crow, ccol, FALSE); // put cursor back in correct place - } -} - -//----- format the status buffer, the bottom line of screen ------ -// print status buffer, with STANDOUT mode -static void psbs(char *format, ...) -{ - va_list args; - - va_start(args, format); - strcpy((char *) status_buffer, SOs); // Terminal standout mode on - vsprintf((char *) status_buffer + strlen((char *) status_buffer), format, - args); - strcat((char *) status_buffer, SOn); // Terminal standout mode off - va_end(args); - - return; -} - -// print status buffer -static void psb(char *format, ...) -{ - va_list args; - - va_start(args, format); - vsprintf((char *) status_buffer, format, args); - va_end(args); - return; -} - -static void ni(Byte * s) // display messages -{ - Byte buf[BUFSIZ]; - - print_literal(buf, s); - psbs("\'%s\' is not implemented", buf); -} - -static void edit_status(void) // show file status on status line -{ - int cur, tot, percent; - - cur = count_lines(text, dot); - tot = count_lines(text, end - 1); - // current line percent - // ------------- ~~ ---------- - // total lines 100 - if (tot > 0) { - percent = (100 * cur) / tot; - } else { - cur = tot = 0; - percent = 100; - } - psb("\"%s\"" -#ifdef BB_FEATURE_VI_READONLY - "%s" -#endif /* BB_FEATURE_VI_READONLY */ - "%s line %d of %d --%d%%--", - (cfn != 0 ? (char *) cfn : "No file"), -#ifdef BB_FEATURE_VI_READONLY - ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""), -#endif /* BB_FEATURE_VI_READONLY */ - (file_modified == TRUE ? " [modified]" : ""), - cur, tot, percent); -} - -//----- Force refresh of all Lines ----------------------------- -static void redraw(int full_screen) -{ - place_cursor(0, 0, FALSE); // put cursor in correct place - clear_to_eos(); // tel terminal to erase display - screen_erase(); // erase the internal screen buffer - refresh(full_screen); // this will redraw the entire display -} - -//----- Format a text[] line into a buffer --------------------- -static void format_line(Byte *dest, Byte *src, int li) -{ - int co; - Byte c; - - for (co= 0; co < MAX_SCR_COLS; co++) { - c= ' '; // assume blank - if (li > 0 && co == 0) { - c = '~'; // not first line, assume Tilde - } - // are there chars in text[] and have we gone past the end - if (text < end && src < end) { - c = *src++; - } - if (c == '\n') - break; - if (c < ' ' || c > '~') { - if (c == '\t') { - c = ' '; - // co % 8 != 7 - for (; (co % tabstop) != (tabstop - 1); co++) { - dest[co] = c; - } - } else { - dest[co++] = '^'; - c |= '@'; // make it visible - c &= 0x7f; // get rid of hi bit - } - } - // the co++ is done here so that the column will - // not be overwritten when we blank-out the rest of line - dest[co] = c; - if (src >= end) - break; - } -} - -//----- Refresh the changed screen lines ----------------------- -// Copy the source line from text[] into the buffer and note -// if the current screenline is different from the new buffer. -// If they differ then that line needs redrawing on the terminal. -// -static void refresh(int full_screen) -{ - static int old_offset; - int li, changed; - Byte buf[MAX_SCR_COLS]; - Byte *tp, *sp; // pointer into text[] and screen[] -#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR - int last_li= -2; // last line that changed- for optimizing cursor movement -#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ - -#ifdef BB_FEATURE_VI_WIN_RESIZE - window_size_get(0); -#endif /* BB_FEATURE_VI_WIN_RESIZE */ - sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot") - tp = screenbegin; // index into text[] of top line - - // compare text[] to screen[] and mark screen[] lines that need updating - for (li = 0; li < rows - 1; li++) { - int cs, ce; // column start & end - memset(buf, ' ', MAX_SCR_COLS); // blank-out the buffer - buf[MAX_SCR_COLS-1] = 0; // NULL terminate the buffer - // format current text line into buf - format_line(buf, tp, li); - - // skip to the end of the current text[] line - while (tp < end && *tp++ != '\n') /*no-op*/ ; - - // see if there are any changes between vitual screen and buf - changed = FALSE; // assume no change - cs= 0; - ce= columns-1; - sp = &screen[li * columns]; // start of screen line - if (full_screen == TRUE) { - // force re-draw of every single column from 0 - columns-1 - goto re0; - } - // compare newly formatted buffer with virtual screen - // look forward for first difference between buf and screen - for ( ; cs <= ce; cs++) { - if (buf[cs + offset] != sp[cs]) { - changed = TRUE; // mark for redraw - break; - } - } - - // look backward for last difference between buf and screen - for ( ; ce >= cs; ce--) { - if (buf[ce + offset] != sp[ce]) { - changed = TRUE; // mark for redraw - break; - } - } - // now, cs is index of first diff, and ce is index of last diff - - // if horz offset has changed, force a redraw - if (offset != old_offset) { - re0: - changed = TRUE; - } - - // make a sanity check of columns indexes - if (cs < 0) cs= 0; - if (ce > columns-1) ce= columns-1; - if (cs > ce) { cs= 0; ce= columns-1; } - // is there a change between vitual screen and buf - if (changed == TRUE) { - // copy changed part of buffer to virtual screen - memmove(sp+cs, buf+(cs+offset), ce-cs+1); - - // move cursor to column of first change - if (offset != old_offset) { - // opti_cur_move is still too stupid - // to handle offsets correctly - place_cursor(li, cs, FALSE); - } else { -#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR - // if this just the next line - // try to optimize cursor movement - // otherwise, use standard ESC sequence - place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE); - last_li= li; -#else /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ - place_cursor(li, cs, FALSE); // use standard ESC sequence -#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ - } - - // write line out to terminal - write(1, sp+cs, ce-cs+1); -#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR - last_row = li; -#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ - } - } - -#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR - place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE); - last_row = crow; -#else - place_cursor(crow, ccol, FALSE); -#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ - - if (offset != old_offset) - old_offset = offset; -} diff --git a/busybox/watchdog.c b/busybox/watchdog.c deleted file mode 100644 index f0b0ebd0e..000000000 --- a/busybox/watchdog.c +++ /dev/null @@ -1,49 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini watchdog implementation for busybox - * - * Copyright (C) 2000 spoon . - * - * 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 - * - */ - -/* getopt not needed */ - -#include -#include -#include -#include -#include "busybox.h" - -extern int watchdog_main(int argc, char **argv) -{ - int fd; - - if (argc != 2) { - show_usage(); - } - - if ((fd=open(argv[1], O_WRONLY)) == -1) { - perror_msg_and_die(argv[1]); - } - - while (1) { - sleep(30); - write(fd, "\0", 1); - } - - return EXIT_FAILURE; -} diff --git a/busybox/wc.c b/busybox/wc.c deleted file mode 100644 index 695e7e7d4..000000000 --- a/busybox/wc.c +++ /dev/null @@ -1,156 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini wc implementation for busybox - * - * 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 - * - */ - -#include -#include -#include -#include -#include "busybox.h" - -static int total_lines, total_words, total_chars, max_length; -static int print_lines, print_words, print_chars, print_length; - -static void print_counts(int lines, int words, int chars, int length, - const char *name) -{ - char const *space = ""; - - if (print_lines) { - printf("%7d", lines); - space = " "; - } - if (print_words) { - printf("%s%7d", space, words); - space = " "; - } - if (print_chars) { - printf("%s%7d", space, chars); - space = " "; - } - if (print_length) - printf("%s%7d", space, length); - if (*name) - printf(" %s", name); - putchar('\n'); -} - -static void wc_file(FILE * file, const char *name) -{ - int lines, words, chars, length; - int in_word = 0, linepos = 0; - int c; - - lines = words = chars = length = 0; - while ((c = getc(file)) != EOF) { - chars++; - switch (c) { - case '\n': - lines++; - case '\r': - case '\f': - if (linepos > length) - length = linepos; - linepos = 0; - goto word_separator; - case '\t': - linepos += 8 - (linepos % 8); - goto word_separator; - case ' ': - linepos++; - case '\v': - word_separator: - if (in_word) { - in_word = 0; - words++; - } - break; - default: - linepos++; - in_word = 1; - break; - } - } - if (linepos > length) - length = linepos; - if (in_word) - words++; - print_counts(lines, words, chars, length, name); - total_lines += lines; - total_words += words; - total_chars += chars; - if (length > max_length) - max_length = length; - fclose(file); - fflush(stdout); -} - -int wc_main(int argc, char **argv) -{ - FILE *file; - unsigned int num_files_counted = 0; - int opt, status = EXIT_SUCCESS; - - total_lines = total_words = total_chars = max_length = 0; - print_lines = print_words = print_chars = print_length = 0; - - while ((opt = getopt(argc, argv, "clLw")) > 0) { - switch (opt) { - case 'c': - print_chars = 1; - break; - case 'l': - print_lines = 1; - break; - case 'L': - print_length = 1; - break; - case 'w': - print_words = 1; - break; - default: - show_usage(); - } - } - - if (!print_lines && !print_words && !print_chars && !print_length) - print_lines = print_words = print_chars = 1; - - if (argv[optind] == NULL || strcmp(argv[optind], "-") == 0) { - wc_file(stdin, ""); - return EXIT_SUCCESS; - } else { - while (optind < argc) { - if ((file = wfopen(argv[optind], "r")) != NULL) - wc_file(file, argv[optind]); - else - status = EXIT_FAILURE; - num_files_counted++; - optind++; - } - } - - if (num_files_counted > 1) - print_counts(total_lines, total_words, total_chars, - max_length, "total"); - - return status; -} diff --git a/busybox/wget.c b/busybox/wget.c deleted file mode 100644 index 59373d1d9..000000000 --- a/busybox/wget.c +++ /dev/null @@ -1,834 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * wget - retrieve a file using HTTP or FTP - * - * Chip Rosenthal Covad Communications - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include - -#include "busybox.h" - -/* Stupid libc5 doesn't define this... */ -#ifndef timersub -#define timersub(a, b, result) \ - do { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ - --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ - } \ - } while (0) -#endif - -struct host_info { - char *host; - int port; - char *path; - int is_ftp; - char *user; -}; - -static void parse_url(char *url, struct host_info *h); -static FILE *open_socket(char *host, int port); -static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc); -static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf); - -/* Globals (can be accessed from signal handlers */ -static off_t filesize = 0; /* content-length of the file */ -static int chunked = 0; /* chunked transfer encoding */ -#ifdef BB_FEATURE_WGET_STATUSBAR -static void progressmeter(int flag); -static char *curfile; /* Name of current file being transferred. */ -static struct timeval start; /* Time a transfer started. */ -static volatile unsigned long statbytes = 0; /* Number of bytes transferred so far. */ -/* For progressmeter() -- number of seconds before xfer considered "stalled" */ -static const int STALLTIME = 5; -#endif - -static void close_and_delete_outfile(FILE* output, char *fname_out, int do_continue) -{ - if (output != stdout && do_continue==0) { - fclose(output); - unlink(fname_out); - } -} - -/* Read NMEMB elements of SIZE bytes into PTR from STREAM. Returns the - * number of elements read, and a short count if an eof or non-interrupt - * error is encountered. */ -static size_t safe_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) -{ - size_t ret = 0; - - do { - clearerr(stream); - ret += fread((char *)ptr + (ret * size), size, nmemb - ret, stream); - } while (ret < nmemb && ferror(stream) && errno == EINTR); - - return ret; -} - -/* Write NMEMB elements of SIZE bytes from PTR to STREAM. Returns the - * number of elements written, and a short count if an eof or non-interrupt - * error is encountered. */ -static size_t safe_fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream) -{ - size_t ret = 0; - - do { - clearerr(stream); - ret += fwrite((char *)ptr + (ret * size), size, nmemb - ret, stream); - } while (ret < nmemb && ferror(stream) && errno == EINTR); - - return ret; -} - -/* Read a line or SIZE - 1 bytes into S, whichever is less, from STREAM. - * Returns S, or NULL if an eof or non-interrupt error is encountered. */ -static char *safe_fgets(char *s, int size, FILE *stream) -{ - char *ret; - - do { - clearerr(stream); - ret = fgets(s, size, stream); - } while (ret == NULL && ferror(stream) && errno == EINTR); - - return ret; -} - -#define close_delete_and_die(s...) { \ - close_and_delete_outfile(output, fname_out, do_continue); \ - error_msg_and_die(s); } - - -#ifdef BB_FEATURE_WGET_AUTHENTICATION -/* - * Base64-encode character string - * oops... isn't something similar in uuencode.c? - * It would be better to use already existing code - */ -char *base64enc(char *p, char *buf, int len) { - - char al[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - char *s = buf; - - while(*p) { - if (s >= buf+len-4) - error_msg_and_die("buffer overflow"); - *(s++) = al[(*p >> 2) & 0x3F]; - *(s++) = al[((*p << 4) & 0x30) | ((*(p+1) >> 4) & 0x0F)]; - *s = *(s+1) = '='; - *(s+2) = 0; - if (! *(++p)) break; - *(s++) = al[((*p << 2) & 0x3C) | ((*(p+1) >> 6) & 0x03)]; - if (! *(++p)) break; - *(s++) = al[*(p++) & 0x3F]; - } - - return buf; -} -#endif - -int wget_main(int argc, char **argv) -{ - int n, try=5, status; - int port; - char *proxy; - char *dir_prefix=NULL; - char *s, buf[512]; - struct stat sbuf; - char extra_headers[1024]; - char *extra_headers_ptr = extra_headers; - int extra_headers_left = sizeof(extra_headers); - int which_long_opt = 0, option_index = -1; - struct host_info server, target; - - FILE *sfp = NULL; /* socket to web/ftp server */ - FILE *dfp = NULL; /* socket to ftp server (data) */ - char *fname_out = NULL; /* where to direct output (-O) */ - int do_continue = 0; /* continue a prev transfer (-c) */ - long beg_range = 0L; /* range at which continue begins */ - int got_clen = 0; /* got content-length: from server */ - FILE *output; /* socket to web server */ - int quiet_flag = FALSE; /* Be verry, verry quiet... */ - -#define LONG_HEADER 1 - struct option long_options[] = { - { "continue", 0, NULL, 'c' }, - { "quiet", 0, NULL, 'q' }, - { "output-document", 1, NULL, 'O' }, - { "header", 1, &which_long_opt, LONG_HEADER }, - { 0, 0, 0, 0 } - }; - /* - * Crack command line. - */ - while ((n = getopt_long(argc, argv, "cqO:P:", long_options, &option_index)) != EOF) { - switch (n) { - case 'c': - ++do_continue; - break; - case 'P': - dir_prefix = optarg; - break; - case 'q': - quiet_flag = TRUE; - break; - case 'O': - /* can't set fname_out to NULL if outputting to stdout, because - * this gets interpreted as the auto-gen output filename - * case below - tausq@debian.org - */ - fname_out = optarg; - break; - case 0: - switch (which_long_opt) { - case LONG_HEADER: { - int arglen = strlen(optarg); - if(extra_headers_left - arglen - 2 <= 0) - error_msg_and_die("extra_headers buffer too small(need %i)", extra_headers_left - arglen); - strcpy(extra_headers_ptr, optarg); - extra_headers_ptr += arglen; - extra_headers_left -= ( arglen + 2 ); - *extra_headers_ptr++ = '\r'; - *extra_headers_ptr++ = '\n'; - *(extra_headers_ptr + 1) = 0; - break; - } - } - break; - default: - show_usage(); - } - } - - if (argc - optind != 1) - show_usage(); - - parse_url(argv[optind], &target); - server.host = target.host; - server.port = target.port; - - /* - * Use the proxy if necessary. - */ - proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy"); - if (proxy) - parse_url(xstrdup(proxy), &server); - - /* Guess an output filename */ - if (!fname_out) { - fname_out = -#ifdef BB_FEATURE_WGET_STATUSBAR - curfile = -#endif - get_last_path_component(target.path); - if (fname_out==NULL || strlen(fname_out)<1) { - fname_out = -#ifdef BB_FEATURE_WGET_STATUSBAR - curfile = -#endif - "index.html"; - } - if (dir_prefix != NULL) - fname_out = concat_path_file(dir_prefix, fname_out); -#ifdef BB_FEATURE_WGET_STATUSBAR - } else { - curfile = get_last_path_component(fname_out); -#endif - } - if (do_continue && !fname_out) - error_msg_and_die("cannot specify continue (-c) without a filename (-O)"); - - - /* - * Open the output file stream. - */ - if (strcmp(fname_out, "-") == 0) { - output = stdout; - quiet_flag = TRUE; - } else { - output = xfopen(fname_out, (do_continue ? "a" : "w")); - } - - /* - * Determine where to start transfer. - */ - if (do_continue) { - if (fstat(fileno(output), &sbuf) < 0) - perror_msg_and_die("fstat()"); - if (sbuf.st_size > 0) - beg_range = sbuf.st_size; - else - do_continue = 0; - } - - if (proxy || !target.is_ftp) { - /* - * HTTP session - */ - do { - if (! --try) - close_delete_and_die("too many redirections"); - - /* - * Open socket to http server - */ - if (sfp) fclose(sfp); - sfp = open_socket(server.host, server.port); - - /* - * Send HTTP request. - */ - if (proxy) { - fprintf(sfp, "GET %stp://%s:%d/%s HTTP/1.1\r\n", - target.is_ftp ? "f" : "ht", target.host, - target.port, target.path); - } else { - fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); - } - - fprintf(sfp, "Host: %s\r\nUser-Agent: Wget\r\n", target.host); - -#ifdef BB_FEATURE_WGET_AUTHENTICATION - if (target.user) { - fprintf(sfp, "Authorization: Basic %s\r\n", - base64enc(target.user, buf, sizeof(buf))); - } - if (proxy && server.user) { - fprintf(sfp, "Proxy-Authorization: Basic %s\r\n", - base64enc(server.user, buf, sizeof(buf))); - } -#endif - - if (do_continue) - fprintf(sfp, "Range: bytes=%ld-\r\n", beg_range); - if(extra_headers_left < sizeof(extra_headers)) - fputs(extra_headers,sfp); - fprintf(sfp,"Connection: close\r\n\r\n"); - - /* - * Retrieve HTTP response line and check for "200" status code. - */ -read_response: if (fgets(buf, sizeof(buf), sfp) == NULL) - close_delete_and_die("no response from server"); - - for (s = buf ; *s != '\0' && !isspace(*s) ; ++s) - ; - for ( ; isspace(*s) ; ++s) - ; - switch (status = atoi(s)) { - case 0: - case 100: - while (gethdr(buf, sizeof(buf), sfp, &n) != NULL); - goto read_response; - case 200: - if (do_continue && output != stdout) - output = freopen(fname_out, "w", output); - do_continue = 0; - break; - case 300: /* redirection */ - case 301: - case 302: - case 303: - break; - case 206: - if (do_continue) - break; - /*FALLTHRU*/ - default: - chomp(buf); - close_delete_and_die("server returned error %d: %s", atoi(s), buf); - } - - /* - * Retrieve HTTP headers. - */ - while ((s = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) { - if (strcasecmp(buf, "content-length") == 0) { - filesize = atol(s); - got_clen = 1; - continue; - } - if (strcasecmp(buf, "transfer-encoding") == 0) { - if (strcasecmp(s, "chunked") == 0) { - chunked = got_clen = 1; - } else { - close_delete_and_die("server wants to do %s transfer encoding", s); - } - } - if (strcasecmp(buf, "location") == 0) { - if (s[0] == '/') - target.path = xstrdup(s+1); - else { - parse_url(xstrdup(s), &target); - if (!proxy) { - server.host = target.host; - server.port = target.port; - } - } - } - } - } while(status >= 300); - - dfp = sfp; - } - else - { - /* - * FTP session - */ - if (! target.user) - target.user = xstrdup("anonymous:busybox@"); - - sfp = open_socket(server.host, server.port); - if (ftpcmd(NULL, NULL, sfp, buf) != 220) - close_delete_and_die("%s", buf+4); - - /* - * Splitting username:password pair, - * trying to log in - */ - s = strchr(target.user, ':'); - if (s) - *(s++) = '\0'; - switch(ftpcmd("USER ", target.user, sfp, buf)) { - case 230: - break; - case 331: - if (ftpcmd("PASS ", s, sfp, buf) == 230) - break; - /* FALLTHRU (failed login) */ - default: - close_delete_and_die("ftp login: %s", buf+4); - } - - ftpcmd("CDUP", NULL, sfp, buf); - ftpcmd("TYPE I", NULL, sfp, buf); - - /* - * Querying file size - */ - if (ftpcmd("SIZE /", target.path, sfp, buf) == 213) { - filesize = atol(buf+4); - got_clen = 1; - } - - /* - * Entering passive mode - */ - if (ftpcmd("PASV", NULL, sfp, buf) != 227) - close_delete_and_die("PASV: %s", buf+4); - s = strrchr(buf, ','); - *s = 0; - port = atoi(s+1); - s = strrchr(buf, ','); - port += atoi(s+1) * 256; - dfp = open_socket(server.host, port); - - if (do_continue) { - sprintf(buf, "REST %ld", beg_range); - if (ftpcmd(buf, NULL, sfp, buf) != 350) { - if (output != stdout) - output = freopen(fname_out, "w", output); - do_continue = 0; - } else - filesize -= beg_range; - } - - if (ftpcmd("RETR /", target.path, sfp, buf) > 150) - close_delete_and_die("RETR: %s", buf+4); - - } - - - /* - * Retrieve file - */ - if (chunked) { - fgets(buf, sizeof(buf), dfp); - filesize = strtol(buf, (char **) NULL, 16); - } -#ifdef BB_FEATURE_WGET_STATUSBAR - if (quiet_flag==FALSE) - progressmeter(-1); -#endif - do { - while ((filesize > 0 || !got_clen) && (n = safe_fread(buf, 1, chunked ? (filesize > sizeof(buf) ? sizeof(buf) : filesize) : sizeof(buf), dfp)) > 0) { - safe_fwrite(buf, 1, n, output); -#ifdef BB_FEATURE_WGET_STATUSBAR - statbytes+=n; -#endif - if (got_clen) - filesize -= n; - } - - if (chunked) { - safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */ - safe_fgets(buf, sizeof(buf), dfp); - filesize = strtol(buf, (char **) NULL, 16); - if (filesize==0) chunked = 0; /* all done! */ - } - - if (n == 0 && ferror(dfp)) - perror_msg_and_die("network read error"); - } while (chunked); -#ifdef BB_FEATURE_WGET_STATUSBAR - if (quiet_flag==FALSE) - progressmeter(1); -#endif - if (!proxy && target.is_ftp) { - fclose(dfp); - if (ftpcmd(NULL, NULL, sfp, buf) != 226) - error_msg_and_die("ftp error: %s", buf+4); - ftpcmd("QUIT", NULL, sfp, buf); - } - exit(EXIT_SUCCESS); -} - - -void parse_url(char *url, struct host_info *h) -{ - char *cp, *sp, *up; - - if (strncmp(url, "http://", 7) == 0) { - h->port = 80; - h->host = url + 7; - h->is_ftp = 0; - } else if (strncmp(url, "ftp://", 6) == 0) { - h->port = 21; - h->host = url + 6; - h->is_ftp = 1; - } else - error_msg_and_die("not an http or ftp url: %s", url); - - sp = strchr(h->host, '/'); - if (sp != NULL) { - *sp++ = '\0'; - h->path = sp; - } else - h->path = ""; - - up = strrchr(h->host, '@'); - if (up != NULL) { - h->user = h->host; - *up++ = '\0'; - h->host = up; - } else - h->user = NULL; - - cp = strchr(h->host, ':'); - if (cp != NULL) { - *cp++ = '\0'; - h->port = atoi(cp); - } - -} - - -FILE *open_socket(char *host, int port) -{ - struct sockaddr_in s_in; - struct hostent *hp; - int fd; - FILE *fp; - - memset(&s_in, 0, sizeof(s_in)); - s_in.sin_family = AF_INET; - hp = xgethostbyname(host); - memcpy(&s_in.sin_addr, hp->h_addr_list[0], hp->h_length); - s_in.sin_port = htons(port); - - /* - * Get the server onto a stdio stream. - */ - if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) - perror_msg_and_die("socket()"); - if (connect(fd, (struct sockaddr *) &s_in, sizeof(s_in)) < 0) - perror_msg_and_die("connect(%s)", host); - if ((fp = fdopen(fd, "r+")) == NULL) - perror_msg_and_die("fdopen()"); - - return fp; -} - - -char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc) -{ - char *s, *hdrval; - int c; - - *istrunc = 0; - - /* retrieve header line */ - if (fgets(buf, bufsiz, fp) == NULL) - return NULL; - - /* see if we are at the end of the headers */ - for (s = buf ; *s == '\r' ; ++s) - ; - if (s[0] == '\n') - return NULL; - - /* convert the header name to lower case */ - for (s = buf ; isalnum(*s) || *s == '-' ; ++s) - *s = tolower(*s); - - /* verify we are at the end of the header name */ - if (*s != ':') - error_msg_and_die("bad header line: %s", buf); - - /* locate the start of the header value */ - for (*s++ = '\0' ; *s == ' ' || *s == '\t' ; ++s) - ; - hdrval = s; - - /* locate the end of header */ - while (*s != '\0' && *s != '\r' && *s != '\n') - ++s; - - /* end of header found */ - if (*s != '\0') { - *s = '\0'; - return hdrval; - } - - /* Rats! The buffer isn't big enough to hold the entire header value. */ - while (c = getc(fp), c != EOF && c != '\n') - ; - *istrunc = 1; - return hdrval; -} - -static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf) -{ - char *p; - - if (s1) { - if (!s2) s2=""; - fprintf(fp, "%s%s\n", s1, s2); - fflush(fp); - } - - do { - p = fgets(buf, 510, fp); - if (!p) - perror_msg_and_die("fgets()"); - } while (! isdigit(buf[0]) || buf[3] != ' '); - - return atoi(buf); -} - -#ifdef BB_FEATURE_WGET_STATUSBAR -/* Stuff below is from BSD rcp util.c, as added to openshh. - * Original copyright notice is retained at the end of this file. - * - */ - - -static int -getttywidth(void) -{ - struct winsize winsize; - - if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1) - return (winsize.ws_col ? winsize.ws_col : 80); - else - return (80); -} - -static void -updateprogressmeter(int ignore) -{ - int save_errno = errno; - - progressmeter(0); - errno = save_errno; -} - -static void -alarmtimer(int wait) -{ - struct itimerval itv; - - itv.it_value.tv_sec = wait; - itv.it_value.tv_usec = 0; - itv.it_interval = itv.it_value; - setitimer(ITIMER_REAL, &itv, NULL); -} - - -static void -progressmeter(int flag) -{ - static const char prefixes[] = " KMGTP"; - static struct timeval lastupdate; - static off_t lastsize, totalsize; - struct timeval now, td, wait; - off_t cursize, abbrevsize; - double elapsed; - int ratio, barlength, i, remaining; - char buf[256]; - - if (flag == -1) { - (void) gettimeofday(&start, (struct timezone *) 0); - lastupdate = start; - lastsize = 0; - totalsize = filesize; /* as filesize changes.. */ - } - - (void) gettimeofday(&now, (struct timezone *) 0); - cursize = statbytes; - if (totalsize != 0 && !chunked) { - ratio = 100.0 * cursize / totalsize; - ratio = MAX(ratio, 0); - ratio = MIN(ratio, 100); - } else - ratio = 100; - - snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ", curfile, ratio); - - barlength = getttywidth() - 51; - if (barlength > 0) { - i = barlength * ratio / 100; - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - "|%.*s%*s|", i, - "*****************************************************************************" - "*****************************************************************************", - barlength - i, ""); - } - i = 0; - abbrevsize = cursize; - while (abbrevsize >= 100000 && i < sizeof(prefixes)) { - i++; - abbrevsize >>= 10; - } - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5d %c%c ", - (int) abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' : - 'B'); - - timersub(&now, &lastupdate, &wait); - if (cursize > lastsize) { - lastupdate = now; - lastsize = cursize; - if (wait.tv_sec >= STALLTIME) { - start.tv_sec += wait.tv_sec; - start.tv_usec += wait.tv_usec; - } - wait.tv_sec = 0; - } - timersub(&now, &start, &td); - elapsed = td.tv_sec + (td.tv_usec / 1000000.0); - - if (wait.tv_sec >= STALLTIME) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - " - stalled -"); - } else if (statbytes <= 0 || elapsed <= 0.0 || cursize > totalsize || chunked) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - " --:-- ETA"); - } else { - remaining = (int) (totalsize / (statbytes / elapsed) - elapsed); - i = remaining / 3600; - if (i) - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - "%2d:", i); - else - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - " "); - i = remaining % 3600; - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - "%02d:%02d ETA", i / 60, i % 60); - } - write(fileno(stderr), buf, strlen(buf)); - - if (flag == -1) { - struct sigaction sa; - sa.sa_handler = updateprogressmeter; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sigaction(SIGALRM, &sa, NULL); - alarmtimer(1); - } else if (flag == 1) { - alarmtimer(0); - statbytes = 0; - putc('\n', stderr); - } -} -#endif - -/* Original copyright notice which applies to the BB_FEATURE_WGET_STATUSBAR stuff, - * much of which was blatently stolen from openssh. */ - -/*- - * Copyright (c) 1992, 1993 - * The 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. - * - * $Id: wget.c,v 1.45 2001/07/19 22:28:01 andersen Exp $ - */ - - - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ - - - diff --git a/busybox/which.c b/busybox/which.c deleted file mode 100644 index c460ffdd1..000000000 --- a/busybox/which.c +++ /dev/null @@ -1,80 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Which implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written 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 - * - */ - -/* getopt not needed */ -#include -#include -#include -#include "busybox.h" - -extern int which_main(int argc, char **argv) -{ - char *path_list, *path_n; - struct stat filestat; - int i, count=1, found, status = EXIT_SUCCESS; - - if (argc <= 1 || **(argv + 1) == '-') - show_usage(); - argc--; - - path_list = getenv("PATH"); - if (!path_list) - path_list = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin"; - - /* Replace colons with zeros in path_parsed and count them */ - for(i=strlen(path_list); i > 0; i--) - if (path_list[i]==':') { - path_list[i]=0; - count++; - } - - while(argc-- > 0) { - path_n = path_list; - argv++; - found = 0; - for (i = 0; i < count; i++) { - char *buf; - buf = concat_path_file(path_n, *argv); - if (stat (buf, &filestat) == 0 - && filestat.st_mode & S_IXUSR) - { - puts(buf); - found = 1; - break; - } - free(buf); - path_n += (strlen(path_n) + 1); - } - if (!found) - status = EXIT_FAILURE; - } - return status; -} - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/ diff --git a/busybox/whoami.c b/busybox/whoami.c deleted file mode 100644 index c3b1140e6..000000000 --- a/busybox/whoami.c +++ /dev/null @@ -1,44 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini whoami implementation for busybox - * - * 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 - * - */ - -/* getopt not needed */ - -#include -#include -#include -#include "busybox.h" - -extern int whoami_main(int argc, char **argv) -{ - char user[9]; - uid_t uid = geteuid(); - - if (argc > 1) - show_usage(); - - my_getpwuid(user, uid); - if (*user) { - puts(user); - return EXIT_SUCCESS; - } - error_msg_and_die("cannot find username for UID %u", (unsigned) uid); -} diff --git a/busybox/xargs.c b/busybox/xargs.c deleted file mode 100644 index 48adae90a..000000000 --- a/busybox/xargs.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Mini xargs implementation for busybox - * - * Copyright (C) 1999,2000,2001 by Lineo, inc. - * Written by Erik Andersen , - * Remixed 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 - * - */ - -#include -#include -#include -#include "busybox.h" - -int xargs_main(int argc, char **argv) -{ - char *cmd_to_be_executed = NULL; - char *file_to_act_on = NULL; - - /* - * No options are supported in this version of xargs; no getopt. - * - * Re: The missing -t flag: Most programs that produce output also print - * the filename, so xargs doesn't really need to do it again. Supporting - * the -t flag =greatly= bloats up the size of this app and the memory it - * uses because you have to buffer all the input file strings in memory. If - * you really want to see the filenames that xargs will act on, just run it - * once with no args and xargs will echo the filename. Simple. - */ - - /* Store the command to be executed (taken from the command line) */ - if (argc == 1) { - /* default behavior is to echo all the filenames */ - cmd_to_be_executed = xstrdup("/bin/echo "); - } else { - /* concatenate all the arguments passed to xargs together */ - int i; - int len = 1; /* for the '\0' */ - for (i = 1; i < argc; i++) { - len += strlen(argv[i]); - len += 1; /* for the space between the args */ - cmd_to_be_executed = xrealloc(cmd_to_be_executed, len); - strcat(cmd_to_be_executed, argv[i]); - strcat(cmd_to_be_executed, " "); - } - } - - /* Now, read in one line at a time from stdin, and store this - * line to be used later as an argument to the command */ - while ((file_to_act_on = get_line_from_file(stdin)) !=NULL) { - - FILE *cmd_output = NULL; - char *output_line = NULL; - char *execstr = NULL; - - /* eat the newline off the filename. */ - chomp(file_to_act_on); - - /* eat blank lines */ - if (strlen(file_to_act_on) == 0) - continue; - - /* assemble the command and execute it */ - execstr = xcalloc(strlen(cmd_to_be_executed) + - strlen(file_to_act_on) + 1, sizeof(char)); - strcat(execstr, cmd_to_be_executed); - strcat(execstr, file_to_act_on); - cmd_output = popen(execstr, "r"); - if (cmd_output == NULL) - perror_msg_and_die("popen"); - - /* harvest the output */ - while ((output_line = get_line_from_file(cmd_output)) != NULL) { - fputs(output_line, stdout); - free(output_line); - } - - /* clean up */ - pclose(cmd_output); - free(execstr); - free(file_to_act_on); - } - -#ifdef BB_FEATURE_CLEAN_UP - free(cmd_to_be_executed); -#endif - - return 0; -} - -/* vi: set sw=4 ts=4: */ diff --git a/busybox/yes.c b/busybox/yes.c deleted file mode 100644 index 7d9596d0b..000000000 --- a/busybox/yes.c +++ /dev/null @@ -1,53 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Mini yes implementation for busybox - * - * 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 - * - */ - -/* getopt not needed */ - -#include -#include -#include "busybox.h" - -extern int yes_main(int argc, char **argv) -{ - int i; - - if (argc >= 2 && *argv[1] == '-') - show_usage(); - - if (argc == 1) { - while (1) - if (puts("y") == EOF) { - perror("yes"); - return EXIT_FAILURE; - } - } - - while (1) - for (i = 1; i < argc; i++) - if (fputs(argv[i], stdout) == EOF - || putchar(i == argc - 1 ? '\n' : ' ') == EOF) { - perror("yes"); - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} diff --git a/cat.c b/cat.c new file mode 100644 index 000000000..820b6342e --- /dev/null +++ b/cat.c @@ -0,0 +1,53 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini Cat implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include "busybox.h" + +extern int cat_main(int argc, char **argv) +{ + int status = EXIT_SUCCESS; + + if (argc == 1) { + print_file(stdin); + return status; + } + + while (--argc > 0) { + if(!(strcmp(*++argv, "-"))) { + print_file(stdin); + } else if (print_file_by_name(*argv) == FALSE) { + status = EXIT_FAILURE; + } + } + return status; +} + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/chgrp.c b/chgrp.c new file mode 100644 index 000000000..b8ec8fd6c --- /dev/null +++ b/chgrp.c @@ -0,0 +1,91 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini chown/chmod/chgrp implementation for busybox + * + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include +#include +#include "busybox.h" + +/* Don't use lchown for libc5 or glibc older then 2.1.x */ +#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1) +#define lchown chown +#endif + + +static long gid; + +static int fileAction(const char *fileName, struct stat *statbuf, void* junk) +{ + if (lchown(fileName, statbuf->st_uid, (gid == -1) ? statbuf->st_gid : gid) == 0) { + return (TRUE); + } + perror(fileName); + return (FALSE); +} + +int chgrp_main(int argc, char **argv) +{ + int opt; + int recursiveFlag = FALSE; + char *p=NULL; + + /* do normal option parsing */ + while ((opt = getopt(argc, argv, "R")) > 0) { + switch (opt) { + case 'R': + recursiveFlag = TRUE; + break; + default: + show_usage(); + } + } + + if (argc > optind && argc > 2 && argv[optind]) { + /* Find the selected group */ + gid = strtoul(argv[optind], &p, 10); /* maybe it's already numeric */ + if (argv[optind] == p) + gid = my_getgrnam(argv[optind]); + } else { + error_msg_and_die(too_few_args); + } + + /* Ok, ready to do the deed now */ + while (++optind < argc) { + if (recursive_action (argv[optind], recursiveFlag, FALSE, FALSE, + fileAction, fileAction, NULL) == FALSE) { + return EXIT_FAILURE; + } + } + return EXIT_SUCCESS; + +} + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/chmod.c b/chmod.c new file mode 100644 index 000000000..1d3f33b64 --- /dev/null +++ b/chmod.c @@ -0,0 +1,97 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini chown/chmod/chgrp implementation for busybox + * + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include +#include +#include +#include "busybox.h" + +static int fileAction(const char *fileName, struct stat *statbuf, void* junk) +{ + if (!parse_mode((char *)junk, &(statbuf->st_mode))) + error_msg_and_die("internal error"); + if (chmod(fileName, statbuf->st_mode) == 0) + return (TRUE); + perror(fileName); + return (FALSE); +} + +int chmod_main(int argc, char **argv) +{ + int i; + int opt; + int recursiveFlag = FALSE; + int opt_eq_modeFlag = FALSE; + + /* do normal option parsing */ + while ((opt = getopt(argc, argv, "Rrwxst")) > 0) { + switch (opt) { + case 'R': + recursiveFlag = TRUE; + break; + case 'r': + case 'w': + case 'x': + case 's': + case 't': + opt_eq_modeFlag = TRUE; + break; + default: + show_usage(); + } + } + + if (opt_eq_modeFlag == TRUE) { + optind--; + } + + if (argc > optind && argc > 2 && argv[optind]) { + /* Parse the specified mode */ + mode_t mode; + if (parse_mode(argv[optind], &mode) == FALSE) { + error_msg_and_die( "unknown mode: %s", argv[optind]); + } + } else { + error_msg_and_die(too_few_args); + } + + /* Ok, ready to do the deed now */ + for (i = optind + 1; i < argc; i++) { + if (recursive_action (argv[i], recursiveFlag, FALSE, FALSE, fileAction, + fileAction, argv[optind]) == FALSE) { + return EXIT_FAILURE; + } + } + return EXIT_SUCCESS; +} + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/chown.c b/chown.c new file mode 100644 index 000000000..ae41ec047 --- /dev/null +++ b/chown.c @@ -0,0 +1,113 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini chown/chmod/chgrp implementation for busybox + * + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include +#include +#include "busybox.h" + +/* Don't use lchown for libc5 or 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); + } + perror(fileName); + return (FALSE); +} + +int chown_main(int argc, char **argv) +{ + int opt; + int recursiveFlag = FALSE, + noderefFlag = FALSE; + char *groupName=NULL; + char *p=NULL; + + /* do normal option parsing */ + while ((opt = getopt(argc, argv, "Rh")) > 0) { + switch (opt) { + case 'R': + recursiveFlag = TRUE; + break; + case 'h': + noderefFlag = TRUE; + break; + default: + show_usage(); + } + } + + if (noderefFlag) chown_func = lchown; + + if (argc > optind && argc > 2 && argv[optind]) { + /* First, check if there is a group name here */ + groupName = strchr(argv[optind], '.'); + if (groupName == NULL) + groupName = strchr(argv[optind], ':'); + if (groupName) { + *groupName++ = '\0'; + gid = strtoul(groupName, &p, 10); + if (groupName == p) + gid = my_getgrnam(groupName); + } else { + gid = -1; + } + /* Now check for the username */ + uid = strtoul(argv[optind], &p, 10); /* Is is numeric? */ + if (argv[optind] == p) { + uid = my_getpwnam(argv[optind]); + } + } else { + error_msg_and_die(too_few_args); + } + + /* Ok, ready to do the deed now */ + while (++optind < argc) { + if (recursive_action (argv[optind], recursiveFlag, FALSE, FALSE, + fileAction, fileAction, NULL) == FALSE) { + return EXIT_FAILURE; + } + } + return EXIT_SUCCESS; + +} + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/chroot.c b/chroot.c new file mode 100644 index 000000000..338d9f4af --- /dev/null +++ b/chroot.c @@ -0,0 +1,75 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini chroot implementation for busybox + * + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include +#include +#include "busybox.h" + +int chroot_main(int argc, char **argv) +{ + char *prog; + + if ((argc < 2) || (**(argv + 1) == '-')) { + show_usage(); + } + argc--; + argv++; + + if (chroot(*argv) || (chdir("/"))) { + perror_msg_and_die("cannot change root directory to %s", *argv); + } + + argc--; + argv++; + if (argc >= 1) { + prog = *argv; + execvp(*argv, argv); + } else { +#if defined shell_main && defined BB_FEATURE_SH_STANDALONE_SHELL + char shell[] = "/bin/sh"; + char *shell_argv[2] = { shell, NULL }; + applet_name = shell; + shell_main(1, shell_argv); + return EXIT_SUCCESS; +#else + prog = getenv("SHELL"); + if (!prog) + prog = "/bin/sh"; + execlp(prog, prog, NULL); +#endif + } + perror_msg_and_die("cannot execute %s", prog); + +} + + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/chvt.c b/chvt.c new file mode 100644 index 000000000..8136f1c15 --- /dev/null +++ b/chvt.c @@ -0,0 +1,43 @@ +/* vi: set sw=4 ts=4: */ +/* + * chvt.c - aeb - 940227 - Change virtual terminal + * + * busyboxed by Erik Andersen + */ + +/* getopt not needed */ + +#include +#include +#include +#include +#include +#include "busybox.h" + +/* From */ +static const int VT_ACTIVATE = 0x5606; /* make vt active */ +static const int VT_WAITACTIVE = 0x5607; /* wait for vt active */ + +int chvt_main(int argc, char **argv) +{ + int fd, num; + + if ((argc != 2) || (**(argv + 1) == '-')) + show_usage(); + fd = get_console_fd(); + num = atoi(argv[1]); + if (ioctl(fd, VT_ACTIVATE, num)) + perror_msg_and_die("VT_ACTIVATE"); + if (ioctl(fd, VT_WAITACTIVE, num)) + perror_msg_and_die("VT_WAITACTIVE"); + return EXIT_SUCCESS; +} + + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/clear.c b/clear.c new file mode 100644 index 000000000..ac32c3230 --- /dev/null +++ b/clear.c @@ -0,0 +1,34 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini clear implementation for busybox + * + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include "busybox.h" + + +extern int clear_main(int argc, char **argv) +{ + printf("\033[H\033[J"); + return EXIT_SUCCESS; +} diff --git a/cmdedit.c b/cmdedit.c new file mode 100644 index 000000000..d0dff11ab --- /dev/null +++ b/cmdedit.c @@ -0,0 +1,1657 @@ +/* vi: set sw=4 ts=4: */ +/* + * Termios command line History and Editting. + * + * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license. + * Written by: Vladimir Oleynik + * + * Used ideas: + * Adam Rogoyski + * Dave Cinege + * Jakub Jelinek (c) 1995 + * Erik Andersen (Majorly adjusted for busybox) + * + * This code is 'as is' with no warranty. + * + * + */ + +/* + Usage and Known bugs: + Terminal key codes are not extensive, and more will probably + need to be added. This version was created on Debian GNU/Linux 2.x. + Delete, Backspace, Home, End, and the arrow keys were tested + to work in an Xterm and console. Ctrl-A also works as Home. + Ctrl-E also works as End. + + Small bugs (simple effect): + - not true viewing if terminal size (x*y symbols) less + size (prompt + editor`s line + 2 symbols) + - not true viewing if length prompt less terminal width + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "busybox.h" + + +#define BB_FEATURE_COMMAND_SAVEHISTORY +#define BB_FEATURE_COMMAND_HISTORY 15 + + +#ifdef BB_LOCALE_SUPPORT +#define Isprint(c) isprint((c)) +#else +#define Isprint(c) ( (c) >= ' ' && (c) != ((unsigned char)'\233') ) +#endif + +#ifndef TEST +#define D(x) +#else +/* pretect redefined for test */ +#define BB_FEATURE_COMMAND_EDITING +#define BB_FEATURE_COMMAND_TAB_COMPLETION +#define BB_FEATURE_COMMAND_USERNAME_COMPLETION +#define BB_FEATURE_NONPRINTABLE_INVERSE_PUT +#define BB_FEATURE_CLEAN_UP +#define D(x) x +#endif /* TEST */ + +#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION +#include +#include +#endif + +#ifdef BB_FEATURE_COMMAND_EDITING + +#ifndef BB_FEATURE_COMMAND_TAB_COMPLETION +#undef BB_FEATURE_COMMAND_USERNAME_COMPLETION +#endif + +#if defined(BB_FEATURE_COMMAND_USERNAME_COMPLETION) || defined(BB_FEATURE_SH_FANCY_PROMPT) +#define BB_FEATURE_GETUSERNAME_AND_HOMEDIR +#endif + +#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR +# ifndef TEST +# include "pwd_grp/pwd.h" +# else +# include +# endif /* TEST */ +#endif /* advanced FEATURES */ + + +/* Maximum length of the linked list for the command line history */ +#ifndef BB_FEATURE_COMMAND_HISTORY +#define MAX_HISTORY 15 +#else +#define MAX_HISTORY BB_FEATURE_COMMAND_HISTORY +#endif + +#if MAX_HISTORY < 1 +#warning cmdedit: You set MAX_HISTORY < 1. The history algorithm switched off. +#else +static char *history[MAX_HISTORY+1]; /* history + current */ +/* saved history lines */ +static int n_history; +/* current pointer to history line */ +static int cur_history; +#endif + +#include +#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp) +#define getTermSettings(fd,argp) tcgetattr(fd, argp); + +/* Current termio and the previous termio before starting sh */ +static struct termios initial_settings, new_settings; + + +static +volatile int cmdedit_termw = 80; /* actual terminal width */ +static +volatile int handlers_sets = 0; /* Set next bites: */ + +enum { + SET_ATEXIT = 1, /* when atexit() has been called + and get euid,uid,gid to fast compare */ + SET_WCHG_HANDLERS = 2, /* winchg signal handler */ + SET_RESET_TERM = 4, /* if the terminal needs to be reset upon exit */ +}; + + +static int cmdedit_x; /* real x terminal position */ +static int cmdedit_y; /* pseudoreal y terminal position */ +static int cmdedit_prmt_len; /* lenght prompt without colores string */ + +static int cursor; /* required global for signal handler */ +static int len; /* --- "" - - "" - -"- --""-- --""--- */ +static char *command_ps; /* --- "" - - "" - -"- --""-- --""--- */ +static +#ifndef BB_FEATURE_SH_FANCY_PROMPT + const +#endif +char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */ + +#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR +static char *user_buf = ""; +static char *home_pwd_buf = ""; +static int my_euid; +#endif + +#ifdef BB_FEATURE_SH_FANCY_PROMPT +static char *hostname_buf; +static int num_ok_lines = 1; +#endif + + +#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION + +#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR +static int my_euid; +#endif + +static int my_uid; +static int my_gid; + +#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ + +static void cmdedit_setwidth(int w, int redraw_flg); + +/* It is perfectly ok to pass in a NULL for either width or for + * height, in which case that value will not be set. It is also + * perfectly ok to have CONFIG_FEATURE_AUTOWIDTH disabled, in + * which case you will always get 80x24 */ +void get_terminal_width_height(int fd, int *width, int *height) +{ + struct winsize win = { 0, 0, 0, 0 }; +#ifdef CONFIG_FEATURE_AUTOWIDTH + if (ioctl(0, TIOCGWINSZ, &win) != 0) { + win.ws_row = 24; + win.ws_col = 80; + } +#endif + if (win.ws_row <= 1) { + win.ws_row = 24; + } + if (win.ws_col <= 1) { + win.ws_col = 80; + } + if (height) { + *height = (int) win.ws_row; + } + if (width) { + *width = (int) win.ws_col; + } +} + +static void win_changed(int nsig) +{ + static sighandler_t previous_SIGWINCH_handler; /* for reset */ + + /* emulate || signal call */ + if (nsig == -SIGWINCH || nsig == SIGWINCH) { + int width = 0; + get_terminal_width_height(0, &width, NULL); + cmdedit_setwidth(width, nsig == SIGWINCH); + } + /* Unix not all standart in recall signal */ + + if (nsig == -SIGWINCH) /* save previous handler */ + previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); + else if (nsig == SIGWINCH) /* signaled called handler */ + signal(SIGWINCH, win_changed); /* set for next call */ + else /* nsig == 0 */ + /* set previous handler */ + signal(SIGWINCH, previous_SIGWINCH_handler); /* reset */ +} + +static void cmdedit_reset_term(void) +{ + if ((handlers_sets & SET_RESET_TERM) != 0) { +/* sparc and other have broken termios support: use old termio handling. */ + setTermSettings(fileno(stdin), (void *) &initial_settings); + handlers_sets &= ~SET_RESET_TERM; + } + if ((handlers_sets & SET_WCHG_HANDLERS) != 0) { + /* reset SIGWINCH handler to previous (default) */ + win_changed(0); + handlers_sets &= ~SET_WCHG_HANDLERS; + } + fflush(stdout); +} + + +/* special for recount position for scroll and remove terminal margin effect */ +static void cmdedit_set_out_char(int next_char) +{ + + int c = (int)((unsigned char) command_ps[cursor]); + + if (c == 0) + c = ' '; /* destroy end char? */ +#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT + if (!Isprint(c)) { /* Inverse put non-printable characters */ + if (c >= 128) + c -= 128; + if (c < ' ') + c += '@'; + if (c == 127) + c = '?'; + printf("\033[7m%c\033[0m", c); + } else +#endif + putchar(c); + if (++cmdedit_x >= cmdedit_termw) { + /* terminal is scrolled down */ + cmdedit_y++; + cmdedit_x = 0; + + if (!next_char) + next_char = ' '; + /* destroy "(auto)margin" */ + putchar(next_char); + putchar('\b'); + } + cursor++; +} + +/* Move to end line. Bonus: rewrite line from cursor */ +static void input_end(void) +{ + while (cursor < len) + cmdedit_set_out_char(0); +} + +/* Go to the next line */ +static void goto_new_line(void) +{ + input_end(); + if (cmdedit_x) + putchar('\n'); +} + + +static inline void out1str(const char *s) +{ + if ( s ) + fputs(s, stdout); +} + +static inline void beep(void) +{ + putchar('\007'); +} + +/* Move back one charactor */ +/* special for slow terminal */ +static void input_backward(int num) +{ + if (num > cursor) + num = cursor; + cursor -= num; /* new cursor (in command, not terminal) */ + + if (cmdedit_x >= num) { /* no to up line */ + cmdedit_x -= num; + if (num < 4) + while (num-- > 0) + putchar('\b'); + + else + printf("\033[%dD", num); + } else { + int count_y; + + if (cmdedit_x) { + putchar('\r'); /* back to first terminal pos. */ + num -= cmdedit_x; /* set previous backward */ + } + count_y = 1 + num / cmdedit_termw; + printf("\033[%dA", count_y); + cmdedit_y -= count_y; + /* require forward after uping */ + cmdedit_x = cmdedit_termw * count_y - num; + printf("\033[%dC", cmdedit_x); /* set term cursor */ + } +} + +static void put_prompt(void) +{ + out1str(cmdedit_prompt); + cmdedit_x = cmdedit_prmt_len; /* count real x terminal position */ + cursor = 0; + cmdedit_y = 0; /* new quasireal y */ +} + +#ifndef BB_FEATURE_SH_FANCY_PROMPT +static void parse_prompt(const char *prmt_ptr) +{ + cmdedit_prompt = prmt_ptr; + cmdedit_prmt_len = strlen(prmt_ptr); + put_prompt(); +} +#else +char bb_process_escape_sequence(const char **ptr) +{ + static const char charmap[] = { + 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', 0, + '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' }; + + const char *p; + const char *q; + unsigned int num_digits; + unsigned int r; + unsigned int n; + + n = 0; + q = *ptr; + + num_digits = 0; + do { + if (((unsigned int)(*q - '0')) <= 7) { + r = n * 8 + (*q - '0'); + if (r <= UCHAR_MAX) { + n = r; + ++q; + if (++num_digits < 3) { + continue; + } + } + } + break; + } while (1); + + if (num_digits == 0) { /* mnemonic escape sequence? */ + p = charmap; + do { + if (*p == *q) { + q++; + break; + } + } while (*++p); + n = *(p+(sizeof(charmap)/2)); + } + + *ptr = q; + return (char) n; +} + +static void parse_prompt(const char *prmt_ptr) +{ + int prmt_len = 0; + int sub_len = 0; + char flg_not_length = '['; + char *prmt_mem_ptr = xcalloc(1, 1); + char *pwd_buf = xgetcwd(0); + char buf2[PATH_MAX + 1]; + char buf[2]; + char c; + char *pbuf; + + if (!pwd_buf) { + pwd_buf=(char *)unknown; + } + + while (*prmt_ptr) { + pbuf = buf; + pbuf[1] = 0; + c = *prmt_ptr++; + if (c == '\\') { + const char *cp = prmt_ptr; + int l; + + c = bb_process_escape_sequence(&prmt_ptr); + if(prmt_ptr==cp) { + if (*cp == 0) + break; + c = *prmt_ptr++; + switch (c) { +#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR + case 'u': + pbuf = user_buf; + break; +#endif + case 'h': + pbuf = hostname_buf; + if (pbuf == 0) { + pbuf = xcalloc(256, 1); + if (gethostname(pbuf, 255) < 0) { + strcpy(pbuf, "?"); + } else { + char *s = strchr(pbuf, '.'); + + if (s) + *s = 0; + } + hostname_buf = pbuf; + } + break; + case '$': + c = my_euid == 0 ? '#' : '$'; + break; +#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR + case 'w': + pbuf = pwd_buf; + l = strlen(home_pwd_buf); + if (home_pwd_buf[0] != 0 && + strncmp(home_pwd_buf, pbuf, l) == 0 && + (pbuf[l]=='/' || pbuf[l]=='\0') && + strlen(pwd_buf+l) UCHAR_MAX || (pbuf - buf2) < l) { + l--; + break; + } + prmt_ptr++; + } + buf2[l] = 0; + c = (char)strtol(buf2, 0, 16); + if(c==0) + c = '?'; + pbuf = buf; + break; + case '[': case ']': + if (c == flg_not_length) { + flg_not_length = flg_not_length == '[' ? ']' : '['; + continue; + } + break; + } + } + } + if(pbuf == buf) + *pbuf = c; + prmt_len += strlen(pbuf); + prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf); + if (flg_not_length == ']') + sub_len++; + } + if(pwd_buf!=(char *)unknown) + free(pwd_buf); + cmdedit_prompt = prmt_mem_ptr; + cmdedit_prmt_len = prmt_len - sub_len; + put_prompt(); +} +#endif + + +/* draw promt, editor line, and clear tail */ +static void redraw(int y, int back_cursor) +{ + if (y > 0) /* up to start y */ + printf("\033[%dA", y); + putchar('\r'); + put_prompt(); + input_end(); /* rewrite */ + printf("\033[J"); /* destroy tail after cursor */ + input_backward(back_cursor); +} + +/* Delete the char in front of the cursor */ +static void input_delete(void) +{ + int j = cursor; + + if (j == len) + return; + + strcpy(command_ps + j, command_ps + j + 1); + len--; + input_end(); /* rewtite new line */ + cmdedit_set_out_char(0); /* destroy end char */ + input_backward(cursor - j); /* back to old pos cursor */ +} + +/* Delete the char in back of the cursor */ +static void input_backspace(void) +{ + if (cursor > 0) { + input_backward(1); + input_delete(); + } +} + + +/* Move forward one charactor */ +static void input_forward(void) +{ + if (cursor < len) + cmdedit_set_out_char(command_ps[cursor + 1]); +} + + +static void cmdedit_setwidth(int w, int redraw_flg) +{ + cmdedit_termw = cmdedit_prmt_len + 2; + if (w <= cmdedit_termw) { + cmdedit_termw = cmdedit_termw % w; + } + if (w > cmdedit_termw) { + cmdedit_termw = w; + + if (redraw_flg) { + /* new y for current cursor */ + int new_y = (cursor + cmdedit_prmt_len) / w; + + /* redraw */ + redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor); + fflush(stdout); + } + } +} + +static void cmdedit_init(void) +{ + cmdedit_prmt_len = 0; + if ((handlers_sets & SET_WCHG_HANDLERS) == 0) { + /* emulate usage handler to set handler and call yours work */ + win_changed(-SIGWINCH); + handlers_sets |= SET_WCHG_HANDLERS; + } + + if ((handlers_sets & SET_ATEXIT) == 0) { +#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR + struct passwd *entry; + + my_euid = geteuid(); + entry = getpwuid(my_euid); + if (entry) { + user_buf = xstrdup(entry->pw_name); + home_pwd_buf = xstrdup(entry->pw_dir); + } +#endif + +#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION + +#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR + my_euid = geteuid(); +#endif + my_uid = getuid(); + my_gid = getgid(); +#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ + handlers_sets |= SET_ATEXIT; + atexit(cmdedit_reset_term); /* be sure to do this only once */ + } +} + +#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION + +static int is_execute(const struct stat *st) +{ + if ((!my_euid && (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) || + (my_uid == st->st_uid && (st->st_mode & S_IXUSR)) || + (my_gid == st->st_gid && (st->st_mode & S_IXGRP)) || + (st->st_mode & S_IXOTH)) return TRUE; + return FALSE; +} + +#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION + +void bb_xasprintf(char **string_ptr, const char *format, ...) +{ + va_list p; + int r; + + va_start(p, format); + r = vasprintf(string_ptr, format, p); + va_end(p); + + if (r < 0) { + perror_msg_and_die("bb_xasprintf"); + } +} + +static char **username_tab_completion(char *ud, int *num_matches) +{ + struct passwd *entry; + int userlen; + char *temp; + + + ud++; /* ~user/... to user/... */ + userlen = strlen(ud); + + if (num_matches == 0) { /* "~/..." or "~user/..." */ + char *sav_ud = ud - 1; + char *home = 0; + + if (*ud == '/') { /* "~/..." */ + home = home_pwd_buf; + } else { + /* "~user/..." */ + temp = strchr(ud, '/'); + *temp = 0; /* ~user\0 */ + entry = getpwnam(ud); + *temp = '/'; /* restore ~user/... */ + ud = temp; + if (entry) + home = entry->pw_dir; + } + if (home) { + if ((userlen + strlen(home) + 1) < BUFSIZ) { + char temp2[BUFSIZ]; /* argument size */ + + /* /home/user/... */ + sprintf(temp2, "%s%s", home, ud); + strcpy(sav_ud, temp2); + } + } + return 0; /* void, result save to argument :-) */ + } else { + /* "~[^/]*" */ + char **matches = (char **) NULL; + int nm = 0; + + setpwent(); + + while ((entry = getpwent()) != NULL) { + /* Null usernames should result in all users as possible completions. */ + if ( /*!userlen || */ !strncmp(ud, entry->pw_name, userlen)) { + + bb_xasprintf(&temp, "~%s/", entry->pw_name); + matches = xrealloc(matches, (nm + 1) * sizeof(char *)); + + matches[nm++] = temp; + } + } + + endpwent(); + (*num_matches) = nm; + return (matches); + } +} +#endif /* BB_FEATURE_COMMAND_USERNAME_COMPLETION */ + +enum { + FIND_EXE_ONLY = 0, + FIND_DIR_ONLY = 1, + FIND_FILE_ONLY = 2, +}; + +static int path_parse(char ***p, int flags) +{ + int npth; + char *tmp; + char *pth; + + /* if not setenv PATH variable, to search cur dir "." */ + if (flags != FIND_EXE_ONLY || (pth = getenv("PATH")) == 0 || + /* PATH= or PATH=: */ + *pth == 0 || (*pth == ':' && *(pth + 1) == 0)) { + return 1; + } + + tmp = pth; + npth = 0; + + for (;;) { + npth++; /* count words is + 1 count ':' */ + tmp = strchr(tmp, ':'); + if (tmp) { + if (*++tmp == 0) + break; /* : */ + } else + break; + } + + *p = xmalloc(npth * sizeof(char *)); + + tmp = pth; + (*p)[0] = xstrdup(tmp); + npth = 1; /* count words is + 1 count ':' */ + + for (;;) { + tmp = strchr(tmp, ':'); + if (tmp) { + (*p)[0][(tmp - pth)] = 0; /* ':' -> '\0' */ + if (*++tmp == 0) + break; /* : */ + } else + break; + (*p)[npth++] = &(*p)[0][(tmp - pth)]; /* p[next]=p[0][&'\0'+1] */ + } + + return npth; +} + +static char *add_quote_for_spec_chars(char *found) +{ + int l = 0; + char *s = xmalloc((strlen(found) + 1) * 2); + + while (*found) { + if (strchr(" `\"#$%^&*()=+{}[]:;\'|\\<>", *found)) + s[l++] = '\\'; + s[l++] = *found++; + } + s[l] = 0; + return s; +} + +static char **exe_n_cwd_tab_completion(char *command, int *num_matches, + int type) +{ + + char **matches = 0; + DIR *dir; + struct dirent *next; + char dirbuf[BUFSIZ]; + int nm = *num_matches; + struct stat st; + char *path1[1]; + char **paths = path1; + int npaths; + int i; + char *found; + char *pfind = strrchr(command, '/'); + + path1[0] = "."; + + if (pfind == NULL) { + /* no dir, if flags==EXE_ONLY - get paths, else "." */ + npaths = path_parse(&paths, type); + pfind = command; + } else { + /* with dir */ + /* save for change */ + strcpy(dirbuf, command); + /* set dir only */ + dirbuf[(pfind - command) + 1] = 0; +#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION + if (dirbuf[0] == '~') /* ~/... or ~user/... */ + username_tab_completion(dirbuf, 0); +#endif + /* "strip" dirname in command */ + pfind++; + + paths[0] = dirbuf; + npaths = 1; /* only 1 dir */ + } + + for (i = 0; i < npaths; i++) { + + dir = opendir(paths[i]); + if (!dir) /* Don't print an error */ + continue; + + while ((next = readdir(dir)) != NULL) { + char *str_found = next->d_name; + + /* matched ? */ + if (strncmp(str_found, pfind, strlen(pfind))) + continue; + /* not see .name without .match */ + if (*str_found == '.' && *pfind == 0) { + if (*paths[i] == '/' && paths[i][1] == 0 + && str_found[1] == 0) str_found = ""; /* only "/" */ + else + continue; + } + found = concat_path_file(paths[i], str_found); + /* hmm, remover in progress? */ + if (stat(found, &st) < 0) + goto cont; + /* find with dirs ? */ + if (paths[i] != dirbuf) + strcpy(found, next->d_name); /* only name */ + if (S_ISDIR(st.st_mode)) { + /* name is directory */ + str_found = found; + found = concat_path_file(found, ""); + free(str_found); + str_found = add_quote_for_spec_chars(found); + } else { + /* not put found file if search only dirs for cd */ + if (type == FIND_DIR_ONLY) + goto cont; + str_found = add_quote_for_spec_chars(found); + if (type == FIND_FILE_ONLY || + (type == FIND_EXE_ONLY && is_execute(&st))) + strcat(str_found, " "); + } + /* Add it to the list */ + matches = xrealloc(matches, (nm + 1) * sizeof(char *)); + + matches[nm++] = str_found; +cont: + free(found); + } + closedir(dir); + } + if (paths != path1) { + free(paths[0]); /* allocated memory only in first member */ + free(paths); + } + *num_matches = nm; + return (matches); +} + +static int match_compare(const void *a, const void *b) +{ + return strcmp(*(char **) a, *(char **) b); +} + + + +#define QUOT (UCHAR_MAX+1) + +#define collapse_pos(is, in) { \ + memcpy(int_buf+(is), int_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); \ + memcpy(pos_buf+(is), pos_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); } + +static int find_match(char *matchBuf, int *len_with_quotes) +{ + int i, j; + int command_mode; + int c, c2; + int int_buf[BUFSIZ + 1]; + int pos_buf[BUFSIZ + 1]; + + /* set to integer dimension characters and own positions */ + for (i = 0;; i++) { + int_buf[i] = (int) ((unsigned char) matchBuf[i]); + if (int_buf[i] == 0) { + pos_buf[i] = -1; /* indicator end line */ + break; + } else + pos_buf[i] = i; + } + + /* mask \+symbol and convert '\t' to ' ' */ + for (i = j = 0; matchBuf[i]; i++, j++) + if (matchBuf[i] == '\\') { + collapse_pos(j, j + 1); + int_buf[j] |= QUOT; + i++; +#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT + if (matchBuf[i] == '\t') /* algorithm equivalent */ + int_buf[j] = ' ' | QUOT; +#endif + } +#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT + else if (matchBuf[i] == '\t') + int_buf[j] = ' '; +#endif + + /* mask "symbols" or 'symbols' */ + c2 = 0; + for (i = 0; int_buf[i]; i++) { + c = int_buf[i]; + if (c == '\'' || c == '"') { + if (c2 == 0) + c2 = c; + else { + if (c == c2) + c2 = 0; + else + int_buf[i] |= QUOT; + } + } else if (c2 != 0 && c != '$') + int_buf[i] |= QUOT; + } + + /* skip commands with arguments if line have commands delimiters */ + /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */ + for (i = 0; int_buf[i]; i++) { + c = int_buf[i]; + c2 = int_buf[i + 1]; + j = i ? int_buf[i - 1] : -1; + command_mode = 0; + if (c == ';' || c == '&' || c == '|') { + command_mode = 1 + (c == c2); + if (c == '&') { + if (j == '>' || j == '<') + command_mode = 0; + } else if (c == '|' && j == '>') + command_mode = 0; + } + if (command_mode) { + collapse_pos(0, i + command_mode); + i = -1; /* hack incremet */ + } + } + /* collapse `command...` */ + for (i = 0; int_buf[i]; i++) + if (int_buf[i] == '`') { + for (j = i + 1; int_buf[j]; j++) + if (int_buf[j] == '`') { + collapse_pos(i, j + 1); + j = 0; + break; + } + if (j) { + /* not found close ` - command mode, collapse all previous */ + collapse_pos(0, i + 1); + break; + } else + i--; /* hack incremet */ + } + + /* collapse (command...(command...)...) or {command...{command...}...} */ + c = 0; /* "recursive" level */ + c2 = 0; + for (i = 0; int_buf[i]; i++) + if (int_buf[i] == '(' || int_buf[i] == '{') { + if (int_buf[i] == '(') + c++; + else + c2++; + collapse_pos(0, i + 1); + i = -1; /* hack incremet */ + } + for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++) + if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) { + if (int_buf[i] == ')') + c--; + else + c2--; + collapse_pos(0, i + 1); + i = -1; /* hack incremet */ + } + + /* skip first not quote space */ + for (i = 0; int_buf[i]; i++) + if (int_buf[i] != ' ') + break; + if (i) + collapse_pos(0, i); + + /* set find mode for completion */ + command_mode = FIND_EXE_ONLY; + for (i = 0; int_buf[i]; i++) + if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') { + if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY + && matchBuf[pos_buf[0]]=='c' + && matchBuf[pos_buf[1]]=='d' ) + command_mode = FIND_DIR_ONLY; + else { + command_mode = FIND_FILE_ONLY; + break; + } + } + /* "strlen" */ + for (i = 0; int_buf[i]; i++); + /* find last word */ + for (--i; i >= 0; i--) { + c = int_buf[i]; + if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') { + collapse_pos(0, i + 1); + break; + } + } + /* skip first not quoted '\'' or '"' */ + for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++); + /* collapse quote or unquote // or /~ */ + while ((int_buf[i] & ~QUOT) == '/' && + ((int_buf[i + 1] & ~QUOT) == '/' + || (int_buf[i + 1] & ~QUOT) == '~')) { + i++; + } + + /* set only match and destroy quotes */ + j = 0; + for (c = 0; pos_buf[i] >= 0; i++) { + matchBuf[c++] = matchBuf[pos_buf[i]]; + j = pos_buf[i] + 1; + } + matchBuf[c] = 0; + /* old lenght matchBuf with quotes symbols */ + *len_with_quotes = j ? j - pos_buf[0] : 0; + + return command_mode; +} + +/* + display by column original ideas from ls applet, + very optimize by my :) +*/ +static void showfiles(char **matches, int nfiles) +{ + int ncols, row; + int column_width = 0; + int nrows = nfiles; + + /* find the longest file name- use that as the column width */ + for (row = 0; row < nrows; row++) { + int l = strlen(matches[row]); + + if (column_width < l) + column_width = l; + } + column_width += 2; /* min space for columns */ + ncols = cmdedit_termw / column_width; + + if (ncols > 1) { + nrows /= ncols; + if(nfiles % ncols) + nrows++; /* round up fractionals */ + column_width = -column_width; /* for printf("%-Ns", ...); */ + } else { + ncols = 1; + } + for (row = 0; row < nrows; row++) { + int n = row; + int nc; + + for(nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) + printf("%*s", column_width, matches[n]); + printf("%s\n", matches[n]); + } +} + + +static void input_tab(int *lastWasTab) +{ + /* Do TAB completion */ + static int num_matches; + static char **matches; + + if (lastWasTab == 0) { /* free all memory */ + if (matches) { + while (num_matches > 0) + free(matches[--num_matches]); + free(matches); + matches = (char **) NULL; + } + return; + } + if (! *lastWasTab) { + + char *tmp; + int len_found; + char matchBuf[BUFSIZ]; + int find_type; + int recalc_pos; + + *lastWasTab = TRUE; /* flop trigger */ + + /* Make a local copy of the string -- up + * to the position of the cursor */ + tmp = strncpy(matchBuf, command_ps, cursor); + tmp[cursor] = 0; + + find_type = find_match(matchBuf, &recalc_pos); + + /* Free up any memory already allocated */ + input_tab(0); + +#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION + /* If the word starts with `~' and there is no slash in the word, + * then try completing this word as a username. */ + + if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0) + matches = username_tab_completion(matchBuf, &num_matches); +#endif + /* Try to match any executable in our path and everything + * in the current working directory that matches. */ + if (!matches) + matches = + exe_n_cwd_tab_completion(matchBuf, + &num_matches, find_type); + /* Remove duplicate found */ + if(matches) { + int i, j; + /* bubble */ + for(i=0; i<(num_matches-1); i++) + for(j=i+1; j 1) { + char *tmp1; + + beep(); + if (!matches) + return; /* not found */ + /* sort */ + qsort(matches, num_matches, sizeof(char *), match_compare); + + /* find minimal match */ + tmp = xstrdup(matches[0]); + for (tmp1 = tmp; *tmp1; tmp1++) + for (len_found = 1; len_found < num_matches; len_found++) + if (matches[len_found][(tmp1 - tmp)] != *tmp1) { + *tmp1 = 0; + break; + } + if (*tmp == 0) { /* have unique */ + free(tmp); + return; + } + } else { /* one match */ + tmp = matches[0]; + /* for next completion current found */ + *lastWasTab = FALSE; + } + + len_found = strlen(tmp); + /* have space to placed match? */ + if ((len_found - strlen(matchBuf) + len) < BUFSIZ) { + + /* before word for match */ + command_ps[cursor - recalc_pos] = 0; + /* save tail line */ + strcpy(matchBuf, command_ps + cursor); + /* add match */ + strcat(command_ps, tmp); + /* add tail */ + strcat(command_ps, matchBuf); + /* back to begin word for match */ + input_backward(recalc_pos); + /* new pos */ + recalc_pos = cursor + len_found; + /* new len */ + len = strlen(command_ps); + /* write out the matched command */ + redraw(cmdedit_y, len - recalc_pos); + } + if (tmp != matches[0]) + free(tmp); + } else { + /* Ok -- the last char was a TAB. Since they + * just hit TAB again, print a list of all the + * available choices... */ + if (matches && num_matches > 0) { + int sav_cursor = cursor; /* change goto_new_line() */ + + /* Go to the next line */ + goto_new_line(); + showfiles(matches, num_matches); + redraw(0, len - sav_cursor); + } + } +} +#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */ + +#if MAX_HISTORY >= 1 +static void get_previous_history(void) +{ + if(command_ps[0] != 0 || history[cur_history] == 0) { + free(history[cur_history]); + history[cur_history] = xstrdup(command_ps); + } + cur_history--; +} + +static int get_next_history(void) +{ + int ch = cur_history; + + if (ch < n_history) { + get_previous_history(); /* save the current history line */ + return (cur_history = ch+1); + } else { + beep(); + return 0; + } +} + +#ifdef BB_FEATURE_COMMAND_SAVEHISTORY +extern void load_history ( const char *fromfile ) +{ + FILE *fp; + int hi; + + /* cleanup old */ + + for(hi = n_history; hi > 0; ) { + hi--; + free ( history [hi] ); + } + + if (( fp = fopen ( fromfile, "r" ))) { + + for ( hi = 0; hi < MAX_HISTORY; ) { + char * hl = get_chomped_line_from_file(fp); + int l; + + if(!hl) + break; + l = strlen(hl); + if(l >= BUFSIZ) + hl[BUFSIZ-1] = 0; + if(l == 0 || hl[0] == ' ') { + free(hl); + continue; + } + history [hi++] = hl; + } + fclose ( fp ); + } + cur_history = n_history = hi; +} + +extern void save_history ( const char *tofile ) +{ + FILE *fp = fopen ( tofile, "w" ); + + if ( fp ) { + int i; + + for ( i = 0; i < n_history; i++ ) { + fprintf(fp, "%s\n", history [i]); + } + fclose ( fp ); + } +} +#endif + +#endif + +enum { + ESC = 27, + DEL = 127, +}; + + +/* + * This function is used to grab a character buffer + * from the input file descriptor and allows you to + * a string with full command editing (sortof like + * a mini readline). + * + * The following standard commands are not implemented: + * ESC-b -- Move back one word + * ESC-f -- Move forward one word + * ESC-d -- Delete back one word + * ESC-h -- Delete forward one word + * CTL-t -- Transpose two characters + * + * Furthermore, the "vi" command editing keys are not implemented. + * + */ + + +int cmdedit_read_input(char *prompt, char command[BUFSIZ]) +{ + + int break_out = 0; + int lastWasTab = FALSE; + unsigned char c = 0; + + /* prepare before init handlers */ + cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */ + len = 0; + command_ps = command; + + getTermSettings(0, (void *) &initial_settings); + memcpy(&new_settings, &initial_settings, sizeof(struct termios)); + new_settings.c_lflag &= ~ICANON; /* unbuffered input */ + /* Turn off echoing and CTRL-C, so we can trap it */ + new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG); + /* Hmm, in linux c_cc[] not parsed if set ~ICANON */ + new_settings.c_cc[VMIN] = 1; + new_settings.c_cc[VTIME] = 0; + /* Turn off CTRL-C, so we can trap it */ +# ifndef _POSIX_VDISABLE +# define _POSIX_VDISABLE '\0' +# endif + new_settings.c_cc[VINTR] = _POSIX_VDISABLE; + command[0] = 0; + + setTermSettings(0, (void *) &new_settings); + handlers_sets |= SET_RESET_TERM; + + /* Now initialize things */ + cmdedit_init(); + /* Print out the command prompt */ + parse_prompt(prompt); + + while (1) { + + fflush(stdout); /* buffered out to fast */ + + if (safe_read(0, &c, 1) < 1) + /* if we can't read input then exit */ + goto prepare_to_die; + + switch (c) { + case '\n': + case '\r': + /* Enter */ + goto_new_line(); + break_out = 1; + break; + case 1: + /* Control-a -- Beginning of line */ + input_backward(cursor); + break; + case 2: + /* Control-b -- Move back one character */ + input_backward(1); + break; + case 3: + /* Control-c -- stop gathering input */ + goto_new_line(); + command[0] = 0; + len = 0; + lastWasTab = FALSE; + put_prompt(); + break; + case 4: + /* Control-d -- Delete one character, or exit + * if the len=0 and no chars to delete */ + if (len == 0) { +prepare_to_die: +#if !defined(BB_ASH) + printf("exit"); + goto_new_line(); + /* cmdedit_reset_term() called in atexit */ + exit(EXIT_SUCCESS); +#else + break_out = -1; /* for control stoped jobs */ + break; +#endif + } else { + input_delete(); + } + break; + case 5: + /* Control-e -- End of line */ + input_end(); + break; + case 6: + /* Control-f -- Move forward one character */ + input_forward(); + break; + case '\b': + case DEL: + /* Control-h and DEL */ + input_backspace(); + break; + case '\t': +#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION + input_tab(&lastWasTab); +#endif + break; + case 11: + /* Control-k -- clear to end of line */ + *(command + cursor) = 0; + len = cursor; + printf("\033[J"); + break; + case 12: + /* Control-l -- clear screen */ + printf("\033[H"); + redraw(0, len-cursor); + break; +#if MAX_HISTORY >= 1 + case 14: + /* Control-n -- Get next command in history */ + if (get_next_history()) + goto rewrite_line; + break; + case 16: + /* Control-p -- Get previous command from history */ + if (cur_history > 0) { + get_previous_history(); + goto rewrite_line; + } else { + beep(); + } + break; +#endif + case 21: + /* Control-U -- Clear line before cursor */ + if (cursor) { + strcpy(command, command + cursor); + redraw(cmdedit_y, len -= cursor); + } + break; + case 23: + /* Control-W -- Remove the last word */ + while (cursor > 0 && isspace(command[cursor-1])) + input_backspace(); + while (cursor > 0 &&!isspace(command[cursor-1])) + input_backspace(); + break; + case ESC:{ + /* escape sequence follows */ + if (safe_read(0, &c, 1) < 1) + goto prepare_to_die; + /* different vt100 emulations */ + if (c == '[' || c == 'O') { + if (safe_read(0, &c, 1) < 1) + goto prepare_to_die; + } + switch (c) { +#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION + case '\t': /* Alt-Tab */ + + input_tab(&lastWasTab); + break; +#endif +#if MAX_HISTORY >= 1 + case 'A': + /* Up Arrow -- Get previous command from history */ + if (cur_history > 0) { + get_previous_history(); + goto rewrite_line; + } else { + beep(); + } + break; + case 'B': + /* Down Arrow -- Get next command in history */ + if (!get_next_history()) + break; + /* Rewrite the line with the selected history item */ +rewrite_line: + /* change command */ + len = strlen(strcpy(command, history[cur_history])); + /* redraw and go to end line */ + redraw(cmdedit_y, 0); + break; +#endif + case 'C': + /* Right Arrow -- Move forward one character */ + input_forward(); + break; + case 'D': + /* Left Arrow -- Move back one character */ + input_backward(1); + break; + case '3': + /* Delete */ + input_delete(); + break; + case '1': + case 'H': + /* Home (Ctrl-A) */ + input_backward(cursor); + break; + case '4': + case 'F': + /* End (Ctrl-E) */ + input_end(); + break; + default: + if (!(c >= '1' && c <= '9')) + c = 0; + beep(); + } + if (c >= '1' && c <= '9') + do + if (safe_read(0, &c, 1) < 1) + goto prepare_to_die; + while (c != '~'); + break; + } + + default: /* If it's regular input, do the normal thing */ +#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT + /* Control-V -- Add non-printable symbol */ + if (c == 22) { + if (safe_read(0, &c, 1) < 1) + goto prepare_to_die; + if (c == 0) { + beep(); + break; + } + } else +#endif + if (!Isprint(c)) /* Skip non-printable characters */ + break; + + if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ + break; + + len++; + + if (cursor == (len - 1)) { /* Append if at the end of the line */ + *(command + cursor) = c; + *(command + cursor + 1) = 0; + cmdedit_set_out_char(0); + } else { /* Insert otherwise */ + int sc = cursor; + + memmove(command + sc + 1, command + sc, len - sc); + *(command + sc) = c; + sc++; + /* rewrite from cursor */ + input_end(); + /* to prev x pos + 1 */ + input_backward(cursor - sc); + } + + break; + } + if (break_out) /* Enter is the command terminator, no more input. */ + break; + + if (c != '\t') + lastWasTab = FALSE; + } + + setTermSettings(0, (void *) &initial_settings); + handlers_sets &= ~SET_RESET_TERM; + +#if MAX_HISTORY >= 1 + /* Handle command history log */ + /* cleanup may be saved current command line */ + free(history[MAX_HISTORY]); + history[MAX_HISTORY] = 0; + if (len) { /* no put empty line */ + int i = n_history; + /* After max history, remove the oldest command */ + if (i >= MAX_HISTORY) { + free(history[0]); + for(i = 0; i < (MAX_HISTORY-1); i++) + history[i] = history[i+1]; + } + history[i++] = xstrdup(command); + cur_history = i; + n_history = i; +#if defined(BB_FEATURE_SH_FANCY_PROMPT) + num_ok_lines++; +#endif + } +#else /* MAX_HISTORY < 1 */ +#if defined(BB_FEATURE_SH_FANCY_PROMPT) + if (len) { /* no put empty line */ + num_ok_lines++; + } +#endif +#endif /* MAX_HISTORY >= 1 */ + if (break_out > 0) { + command[len++] = '\n'; /* set '\n' */ + command[len] = 0; + } +#if defined(BB_FEATURE_CLEAN_UP) && defined(BB_FEATURE_COMMAND_TAB_COMPLETION) + input_tab(0); /* strong free */ +#endif +#if defined(BB_FEATURE_SH_FANCY_PROMPT) + free(cmdedit_prompt); +#endif + cmdedit_reset_term(); + return len; +} + + + +#endif /* BB_FEATURE_COMMAND_EDITING */ + + +#ifdef TEST + +const char *bb_applet_name = "debug stuff usage"; + +#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT +#include +#endif + +int main(int argc, char **argv) +{ + char buff[BUFSIZ]; + char *prompt = +#if defined(BB_FEATURE_SH_FANCY_PROMPT) + "\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:\ +\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \ +\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]"; +#else + "% "; +#endif + +#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT + setlocale(LC_ALL, ""); +#endif + while(1) { + int l; + l = cmdedit_read_input(prompt, buff); + if(l > 0 && buff[l-1] == '\n') { + buff[l-1] = 0; + printf("*** cmdedit_read_input() returned line =%s=\n", buff); + } else { + break; + } + } + printf("*** cmdedit_read_input() detect ^D\n"); + return 0; +} + +#endif /* TEST */ diff --git a/cmdedit.h b/cmdedit.h new file mode 100644 index 000000000..991dafcd1 --- /dev/null +++ b/cmdedit.h @@ -0,0 +1,11 @@ +#ifndef CMDEDIT_H +#define CMDEDIT_H + +int cmdedit_read_input(char* promptStr, char* command); + +#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY +void load_history ( const char *fromfile ); +void save_history ( const char *tofile ); +#endif + +#endif /* CMDEDIT_H */ diff --git a/cmp.c b/cmp.c new file mode 100644 index 000000000..57d83d844 --- /dev/null +++ b/cmp.c @@ -0,0 +1,78 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini cmp implementation for busybox + * + * Copyright (C) 1999,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 + * + */ + +#include +#include +#include +#include +#include +#include "busybox.h" + +int cmp_main(int argc, char **argv) +{ + FILE *fp1 = NULL, *fp2 = stdin; + char *filename1, *filename2 = "-"; + int c, c1, c2, char_pos = 1, line_pos = 1, silent = FALSE; + + while ((c = getopt(argc, argv, "s")) != EOF) { + switch (c) { + case 's': + silent = TRUE; + break; + default: + show_usage(); + } + } + + filename1 = argv[optind]; + switch (argc - optind) { + case 2: + fp2 = xfopen(filename2 = argv[optind + 1], "r"); + case 1: + fp1 = xfopen(filename1, "r"); + break; + default: + show_usage(); + } + + do { + c1 = fgetc(fp1); + c2 = fgetc(fp2); + if (c1 != c2) { + if (silent) + return EXIT_FAILURE; + if (c1 == EOF) + printf("EOF on %s\n", filename1); + else if (c2 == EOF) + printf("EOF on %s\n", filename2); + else + printf("%s %s differ: char %d, line %d\n", filename1, filename2, + char_pos, line_pos); + return EXIT_FAILURE; + } + char_pos++; + if (c1 == '\n') + line_pos++; + } while (c1 != EOF); + + return EXIT_SUCCESS; +} diff --git a/cp.c b/cp.c new file mode 100644 index 000000000..696b06ea5 --- /dev/null +++ b/cp.c @@ -0,0 +1,117 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini cp implementation for busybox + * + * + * Copyright (C) 2000 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "busybox.h" + +extern int cp_main(int argc, char **argv) +{ + int status = 0; + int opt; + int flags = 0; + int i; + + while ((opt = getopt(argc, argv, "adfipRr")) != -1) + switch (opt) { + case 'a': + flags |= FILEUTILS_PRESERVE_STATUS | FILEUTILS_RECUR; + /* fallthrough */ + case 'd': + flags |= FILEUTILS_PRESERVE_SYMLINKS; + break; + case 'f': + flags |= FILEUTILS_FORCE; + break; + case 'i': + flags |= FILEUTILS_INTERACTIVE; + break; + case 'p': + flags |= FILEUTILS_PRESERVE_STATUS; + break; + case 'R': + flags |= FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS; + break; + case 'r': + flags |= FILEUTILS_RECUR; + break; + default: + show_usage(); + } + + if (optind + 2 > argc) + show_usage(); + + /* If there are only two arguments and... */ + if (optind + 2 == argc) { + struct stat source_stat; + struct stat dest_stat; + int source_exists = 1; + int dest_exists = 1; + + if (((flags & FILEUTILS_PRESERVE_SYMLINKS) && + lstat(argv[optind], &source_stat) < 0) || + (!(flags & FILEUTILS_PRESERVE_SYMLINKS) && + stat(argv[optind], &source_stat))) { + if (errno != ENOENT) + perror_msg_and_die("unable to stat `%s'", argv[optind]); + source_exists = 0; + } + + if (stat(argv[optind + 1], &dest_stat) < 0) { + if (errno != ENOENT) + perror_msg_and_die("unable to stat `%s'", argv[optind + 1]); + dest_exists = 0; + } + + /* ...if neither is a directory or... */ + if (((!source_exists || !S_ISDIR(source_stat.st_mode)) && + (!dest_exists || !S_ISDIR(dest_stat.st_mode))) || + /* ...recursing, the first is a directory, and the + * second doesn't exist, then... */ + ((flags & FILEUTILS_RECUR) && S_ISDIR(source_stat.st_mode) && + !dest_exists)) { + /* ...do a simple copy. */ + if (copy_file(argv[optind], argv[optind + 1], flags) < 0) + status = 1; + return status; + } + } + + for (i = optind; i < argc - 1; i++) { + char *dest = concat_path_file(argv[argc - 1], + get_last_path_component(argv[i])); + if (copy_file(argv[i], dest, flags) < 0) + status = 1; + free(dest); + } + + return status; +} diff --git a/cpio.c b/cpio.c new file mode 100644 index 000000000..7f68715eb --- /dev/null +++ b/cpio.c @@ -0,0 +1,95 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini cpio implementation for busybox + * + * Copyright (C) 2001 by 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 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 + * + * Limitations: + * Doesn't check CRC's + * Only supports new ASCII and CRC formats + * + */ +#include +#include +#include +#include +#include +#include "busybox.h" + +extern int cpio_main(int argc, char **argv) +{ + FILE *src_stream = stdin; + char **extract_names = NULL; + int extract_function = 0; + int num_of_entries = 0; + int opt = 0; + mode_t oldmask = 0; + + while ((opt = getopt(argc, argv, "idmuvtF:")) != -1) { + switch (opt) { + case 'i': // extract + extract_function |= extract_all_to_fs; + break; + case 'd': // create _leading_ directories + extract_function |= extract_create_leading_dirs; + oldmask = umask(077); /* Make make_directory act like GNU cpio */ + break; + case 'm': // preserve modification time + extract_function |= extract_preserve_date; + break; + case 'v': // verbosly list files + extract_function |= extract_verbose_list; + break; + case 'u': // unconditional + extract_function |= extract_unconditional; + break; + case 't': // list files + extract_function |= extract_list; + break; + case 'F': + src_stream = xfopen(optarg, "r"); + break; + default: + show_usage(); + } + } + + if ((extract_function & extract_all_to_fs) && (extract_function & extract_list)) { + extract_function ^= extract_all_to_fs; /* If specify t, don't extract*/ + } + + if ((extract_function & extract_all_to_fs) && (extract_function & extract_verbose_list)) { + /* The meaning of v changes on extract */ + extract_function ^= extract_verbose_list; + extract_function |= extract_list; + } + + while (optind < argc) { + extract_names = xrealloc(extract_names, sizeof(char *) * (num_of_entries + 2)); + extract_names[num_of_entries] = xstrdup(argv[optind]); + num_of_entries++; + extract_names[num_of_entries] = NULL; + optind++; + } + + unarchive(src_stream, stdout, &get_header_cpio, extract_function, "./", extract_names); + if (oldmask) { + umask(oldmask); /* Restore umask if we changed it */ + } + return EXIT_SUCCESS; +} + diff --git a/cut.c b/cut.c new file mode 100644 index 000000000..b60c41e7f --- /dev/null +++ b/cut.c @@ -0,0 +1,356 @@ +/* + * cut.c - minimalist version of cut + * + * Copyright (C) 1999,2000 by Lineo, inc. and Mark Whitley + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include /* getopt */ +#include +#include +#include "busybox.h" + + +/* globals from other files */ +extern int optind; +extern char *optarg; + + +/* option vars */ +static char part = 0; /* (b)yte, (c)har, (f)ields */ +static unsigned int supress_non_delimited_lines = 0; +static char delim = '\t'; /* delimiter, default is tab */ + +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 */ + + +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; +} + + +/* + * 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) +{ + 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) + 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) + 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) + 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) + 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); + +} + + +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'; + } + 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) + 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++; + } + + /* 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++; + } + + 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 = get_line_from_file(file)) != NULL) { + chomp(line); + + /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */ + if (part == 'c' || part == 'b') + cut_line_by_chars(line); + + /* cut based on fields */ + else if (part == 'f') { + if (delim == '\n') + cut_file_by_lines(line, linenum); + else + cut_line_by_fields(line); + } + + linenum++; + free(line); + } +} + + +extern int cut_main(int argc, char **argv) +{ + int opt; + + while ((opt = getopt(argc, argv, "b:c:d:f:ns")) > 0) { + switch (opt) { + case 'b': + case 'c': + case 'f': + /* make sure they didn't ask for two types of lists */ + if (part != 0) { + error_msg_and_die("only one type of list may be specified"); + } + part = (char)opt; + parse_lists(optarg); + break; + case 'd': + if (strlen(optarg) > 1) { + error_msg_and_die("the delimiter must be a single character"); + } + delim = optarg[0]; + break; + case 'n': + /* no-op */ + break; + case 's': + supress_non_delimited_lines++; + break; + } + } + + if (part == 0) { + error_msg_and_die("you must specify a list of bytes, characters, or fields"); + } + + /* non-field (char or byte) cutting has some special handling */ + if (part != 'f') { + if (supress_non_delimited_lines) { + error_msg_and_die("suppressing non-delimited lines makes sense" + " only when operating on fields"); + } + if (delim != '\t' && part != 'f') { + error_msg_and_die("a delimiter may be specified only when operating on fields"); + } + } + + /* 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 = wfopen(argv[i], "r"); + if(file) { + cut_file(file); + fclose(file); + } + } + } + + return EXIT_SUCCESS; +} diff --git a/date.c b/date.c new file mode 100644 index 000000000..41ceee29d --- /dev/null +++ b/date.c @@ -0,0 +1,247 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini date implementation for busybox + * + * by Matthew Grant + * + * 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 "busybox.h" + + +/* 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 + 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) { + error_msg_and_die(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); + +} + + +/* The new stuff for LRP */ + +static struct tm *date_conv_ftime(struct tm *tm_time, const char *t_string) +{ + 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) { + + t.tm_mon -= 1; /* Adjust dates from 1-12 to 0-11 */ + + } 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) { + + 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:%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 { + error_msg_and_die(invalid_date, t_string); + } + *tm_time = t; + return (tm_time); +} + + +int date_main(int argc, char **argv) +{ + char *date_str = NULL; + char *date_fmt = NULL; + char *t_buff; + int c; + int set_time = 0; + int rfc822 = 0; + int utc = 0; + int use_arg = 0; + time_t tm; + struct tm tm_time; + + /* Interpret command line args */ + while ((c = getopt(argc, argv, "Rs:ud:")) != EOF) { + switch (c) { + case 'R': + rfc822 = 1; + break; + case 's': + set_time = 1; + if ((date_str != NULL) || ((date_str = optarg) == NULL)) { + show_usage(); + } + break; + case 'u': + utc = 1; + if (putenv("TZ=UTC0") != 0) + error_msg_and_die(memory_exhausted); + break; + case 'd': + use_arg = 1; + if ((date_str != NULL) || ((date_str = optarg) == NULL)) + show_usage(); + break; + default: + show_usage(); + } + } + + 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]; + } +#if 0 + else { + error_msg("date_str='%s' date_fmt='%s'\n", date_str, date_fmt); + show_usage(); + } +#endif + + /* Now we have parsed all the information except the date format + which depends on whether the clock is being set or read */ + + time(&tm); + memcpy(&tm_time, localtime(&tm), sizeof(tm_time)); + /* Zero out fields - take her back to midnight! */ + if (date_str != NULL) { + 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); + } else { + date_conv_time(&tm_time, date_str); + } + + /* Correct any day of week and day of year etc. fields */ + tm = mktime(&tm_time); + if (tm < 0) + error_msg_and_die(invalid_date, date_str); + if ( utc ) { + if (putenv("TZ=UTC0") != 0) + error_msg_and_die(memory_exhausted); + } + + /* if setting time, set it */ + if (set_time) { + if (stime(&tm) < 0) { + perror_msg("cannot set date"); + } + } + } + + /* Display output */ + + /* Deal with format string */ + if (date_fmt == NULL) { + 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"); + + } else if (*date_fmt == '\0') { + /* Imitate what GNU 'date' does with NO format string! */ + printf("\n"); + return EXIT_SUCCESS; + } + + /* Handle special conversions */ + + if (strncmp(date_fmt, "%f", 2) == 0) { + date_fmt = "%Y.%m.%d-%H:%M:%S"; + } + + /* Print OUTPUT (after ALL that!) */ + t_buff = xmalloc(201); + strftime(t_buff, 200, date_fmt, &tm_time); + puts(t_buff); + + return EXIT_SUCCESS; +} diff --git a/dc.c b/dc.c new file mode 100644 index 000000000..8d7a92a28 --- /dev/null +++ b/dc.c @@ -0,0 +1,182 @@ +/* vi: set sw=4 ts=4: */ +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */ + +static double stack[100]; +static unsigned int pointer; + +static void push(double a) +{ + if (pointer >= (sizeof(stack) / sizeof(*stack))) + error_msg_and_die("stack overflow"); + stack[pointer++] = a; +} + +static double pop() +{ + if (pointer == 0) + error_msg_and_die("stack underflow"); + return stack[--pointer]; +} + +static void add() +{ + push(pop() + pop()); +} + +static void sub() +{ + double subtrahend = pop(); + + push(pop() - subtrahend); +} + +static void mul() +{ + push(pop() * pop()); +} + +static void divide() +{ + double divisor = pop(); + + push(pop() / divisor); +} + +static void and() +{ + push((unsigned int) pop() & (unsigned int) pop()); +} + +static void or() +{ + push((unsigned int) pop() | (unsigned int) pop()); +} + +static void eor() +{ + push((unsigned int) pop() ^ (unsigned int) pop()); +} + +static void not() +{ + push(~(unsigned int) pop()); +} + +static void print() +{ + printf("%g\n", pop()); +} + +struct op { + const char *name; + void (*function) (); +}; + +static const struct op operators[] = { + {"+", add}, + {"add", add}, + {"-", sub}, + {"sub", sub}, + {"*", mul}, + {"mul", mul}, + {"/", divide}, + {"div", divide}, + {"and", and}, + {"or", or}, + {"not", not}, + {"eor", eor}, + {0, 0} +}; + +static void stack_machine(const char *argument) +{ + char *endPointer = 0; + double d; + const struct op *o = operators; + + if (argument == 0) { + print(); + return; + } + + d = strtod(argument, &endPointer); + + if (endPointer != argument) { + push(d); + return; + } + + while (o->name != 0) { + if (strcmp(o->name, argument) == 0) { + (*(o->function)) (); + return; + } + o++; + } + error_msg_and_die("%s: syntax error.", argument); +} + +/* return pointer to next token in buffer and set *buffer to one char + * past the end of the above mentioned token + */ +static char *get_token(char **buffer) +{ + char *start = NULL; + char *current = *buffer; + + while (isspace(*current)) { current++; } + if (*current != 0) { + start = current; + while (!isspace(*current) && current != 0) { current++; } + *buffer = current; + } + return start; +} + +/* In Perl one might say, scalar m|\s*(\S+)\s*|g */ +static int number_of_tokens(char *buffer) +{ + int i = 0; + char *b = buffer; + while (get_token(&b)) { i++; } + return i; +} + +int dc_main(int argc, char **argv) +{ + /* take stuff from stdin if no args are given */ + if (argc <= 1) { + int i, len; + char *line = NULL; + char *cursor = NULL; + char *token = NULL; + while ((line = get_line_from_file(stdin))) { + cursor = line; + len = number_of_tokens(line); + for (i = 0; i < len; i++) { + token = get_token(&cursor); + *cursor++ = 0; + stack_machine(token); + } + free(line); + } + } else { + if (*argv[1]=='-') + show_usage(); + while (argc >= 2) { + stack_machine(argv[1]); + argv++; + argc--; + } + } + stack_machine(0); + return EXIT_SUCCESS; +} diff --git a/dd.c b/dd.c new file mode 100644 index 000000000..ecacf64ae --- /dev/null +++ b/dd.c @@ -0,0 +1,171 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini dd implementation for busybox + * + * + * Copyright (C) 2000 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include "busybox.h" + + +static const struct suffix_mult dd_suffixes[] = { + { "c", 1 }, + { "w", 2 }, + { "b", 512 }, + { "kD", 1000 }, + { "k", 1024 }, + { "MD", 1000000 }, + { "M", 1048576 }, + { "GD", 1000000000 }, + { "G", 1073741824 }, + { NULL, 0 } +}; + +int dd_main(int argc, char **argv) +{ + int i, ifd, ofd, oflag, sync_flag = FALSE, trunc = TRUE, noerror = FALSE; + size_t in_full = 0, in_part = 0, out_full = 0, out_part = 0; + size_t bs = 512, count = -1; + ssize_t n; + off_t seek = 0, skip = 0; + char *infile = NULL, *outfile = NULL, *buf; + + for (i = 1; i < argc; i++) { + if (strncmp("bs=", argv[i], 3) == 0) + bs = parse_number(argv[i]+3, dd_suffixes); + else if (strncmp("count=", argv[i], 6) == 0) + count = parse_number(argv[i]+6, dd_suffixes); + else if (strncmp("seek=", argv[i], 5) == 0) + seek = parse_number(argv[i]+5, dd_suffixes); + else if (strncmp("skip=", argv[i], 5) == 0) + skip = parse_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; + 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 { + error_msg_and_die("invalid conversion `%s'", argv[i]+5); + } + if (buf[0] == '\0') + break; + if (buf[0] == ',') + buf++; + } + } else + show_usage(); + } + + buf = xmalloc(bs); + + if (infile != NULL) { + if ((ifd = open(infile, O_RDONLY)) < 0) + perror_msg_and_die("%s", infile); + } else { + ifd = STDIN_FILENO; + infile = "standard input"; + } + + if (outfile != NULL) { + oflag = O_WRONLY | O_CREAT; + + if (!seek && trunc) + oflag |= O_TRUNC; + + if ((ofd = open(outfile, oflag, 0666)) < 0) + perror_msg_and_die("%s", outfile); + + if (seek && trunc) { + if (ftruncate(ofd, seek * bs) < 0) { + struct stat st; + if (fstat (ofd, &st) < 0 || S_ISREG (st.st_mode) || + S_ISDIR (st.st_mode)) + perror_msg_and_die("%s", outfile); + } + } + } else { + ofd = STDOUT_FILENO; + outfile = "standard output"; + } + + if (skip) { + if (lseek(ifd, skip * bs, SEEK_CUR) < 0) + perror_msg_and_die("%s", infile); + } + + if (seek) { + if (lseek(ofd, seek * bs, SEEK_CUR) < 0) + perror_msg_and_die("%s", 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; + perror_msg("%s", infile); + } else { + perror_msg_and_die("%s", infile); + } + } + if (n == 0) + break; + if (n == bs) + in_full++; + else + in_part++; + if (sync_flag) { + memset(buf + n, '\0', bs - n); + n = bs; + } + n = full_write(ofd, buf, n); + if (n < 0) + perror_msg_and_die("%s", outfile); + if (n == bs) + out_full++; + else + out_part++; + } + + fprintf(stderr, "%ld+%ld records in\n", (long)in_full, (long)in_part); + fprintf(stderr, "%ld+%ld records out\n", (long)out_full, (long)out_part); + + return EXIT_SUCCESS; +} diff --git a/deallocvt.c b/deallocvt.c new file mode 100644 index 000000000..b7dcc9e22 --- /dev/null +++ b/deallocvt.c @@ -0,0 +1,43 @@ +/* vi: set sw=4 ts=4: */ +/* + * disalloc.c - aeb - 940501 - Disallocate virtual terminal(s) + * Renamed deallocvt. + */ +#include +#include +#include +#include +#include +#include "busybox.h" + +/* From */ +static const int VT_DISALLOCATE = 0x5608; /* free memory associated to vt */ + +int deallocvt_main(int argc, char *argv[]) +{ + int fd, num, i; + + //if ((argc > 2) || ((argv == 2) && (**(argv + 1) == '-'))) + if (argc > 2) + show_usage(); + + fd = get_console_fd(); + + if (argc == 1) { + /* deallocate all unused consoles */ + if (ioctl(fd, VT_DISALLOCATE, 0)) + perror_msg_and_die("VT_DISALLOCATE"); + } else { + for (i = 1; i < argc; i++) { + num = atoi(argv[i]); + if (num == 0) + error_msg("0: illegal VT number"); + else if (num == 1) + error_msg("VT 1 cannot be deallocated"); + else if (ioctl(fd, VT_DISALLOCATE, num)) + perror_msg_and_die("VT_DISALLOCATE"); + } + } + + return EXIT_SUCCESS; +} diff --git a/debian/Config.h-deb b/debian/Config.h-deb new file mode 100644 index 000000000..7b4157447 --- /dev/null +++ b/debian/Config.h-deb @@ -0,0 +1,493 @@ +/* vi: set sw=4 ts=4: */ +// This file defines the feature set to be compiled into busybox. +// When you turn things off here, they won't be compiled in at all. +// +//// This file is parsed by sed. You MUST use single line comments. +// i.e., //#define BB_BLAH +// +// +// BusyBox Applications +//#define BB_ADJTIMEX +#define BB_AR +//#define BB_ASH +//#define BB_BASENAME +#define BB_CAT +#define BB_CHGRP +#define BB_CHMOD +#define BB_CHOWN +#define BB_CHROOT +//#define BB_CHVT +#define BB_CLEAR +//#define BB_CMP +#define BB_CP +//#define BB_CPIO +#define BB_CUT +//#define BB_DATE +//#define BB_DC +//#define BB_DD +//#define BB_DEALLOCVT +#define BB_DF +#define BB_DIRNAME +#define BB_DMESG +//#define BB_DOS2UNIX +//#define BB_DPKG +//#define BB_DPKG_DEB +//#define BB_DUTMP +//#define BB_DU +//#define BB_DUMPKMAP +#define BB_ECHO +//#define BB_ENV +#define BB_EXPR +//#define BB_FBSET +//#define BB_FDFLUSH +#define BB_FIND +#define BB_FREE +//#define BB_FREERAMDISK +//#define BB_FSCK_MINIX +//#define BB_GETOPT +#define BB_GREP +#define BB_GUNZIP +#define BB_GZIP +#define BB_HALT +#define BB_HEAD +//#define BB_HOSTID +#define BB_HOSTNAME +//#define BB_HUSH +#define BB_ID +#define BB_IFCONFIG +#define BB_INIT +//#define BB_INSMOD +#define BB_KILL +#define BB_KILLALL +#define BB_KLOGD +//#define BB_LASH +//#define BB_LENGTH +#define BB_LN +//#define BB_LOADACM +//#define BB_LOADFONT +#define BB_LOADKMAP +#define BB_LOGGER +//#define BB_LOGNAME +#define BB_LOSETUP +#define BB_LS +//#define BB_LSMOD +//#define BB_MAKEDEVS +#define BB_MD5SUM +#define BB_MKDIR +//#define BB_MKFIFO +//#define BB_MKFS_MINIX +#define BB_MKNOD +#define BB_MKSWAP +//#define BB_MKTEMP +//#define BB_MODPROBE +#define BB_MORE +#define BB_MOUNT +//#define BB_MSH +//#define BB_MT +#define BB_MV +//#define BB_NC +//#define BB_NSLOOKUP +//#define BB_PIDOF +#define BB_PING +//#define BB_PIVOT_ROOT +#define BB_POWEROFF +//#define BB_PRINTF +#define BB_PS +#define BB_PWD +//#define BB_RDATE +//#define BB_READLINK +#define BB_REBOOT +//#define BB_RENICE +#define BB_RESET +#define BB_RM +#define BB_RMDIR +//#define BB_RMMOD +#define BB_ROUTE +//#define BB_RPM2CPIO +#define BB_SED +//#define BB_SETKEYCODES +#define BB_SLEEP +#define BB_SORT +//#define BB_STTY +#define BB_SWAPONOFF +#define BB_SYNC +#define BB_SYSLOGD +#define BB_TAIL +#define BB_TAR +//#define BB_TEE +#define BB_TEST +//#define BB_TELNET +//#define BB_TFTP +//#define BB_TIME +//#define BB_TOP +#define BB_TOUCH +#define BB_TR +//#define BB_TRACEROUTE +#define BB_TRUE_FALSE +#define BB_TTY +//#define BB_UNIX2DOS +//#define BB_UUENCODE +//#define BB_UUDECODE +#define BB_UMOUNT +#define BB_UNIQ +#define BB_UNAME +//#define BB_UPDATE +#define BB_UPTIME +//#define BB_USLEEP +//#define BB_VI +//#define BB_WATCHDOG +#define BB_WC +#define BB_WGET +#define BB_WHICH +#define BB_WHOAMI +//#define BB_XARGS +//#define BB_YES +// End of Applications List +// +// +// +// --------------------------------------------------------- +// This is where feature definitions go. Generally speaking, +// turning this stuff off makes things a bit smaller (and less +// pretty/useful). +// +// +// If you enabled one or more of the shells, you may select which one +// should be run when sh is invoked: +//#define BB_FEATURE_SH_IS_ASH +//#define BB_FEATURE_SH_IS_HUSH +//#define BB_FEATURE_SH_IS_LASH +//#define BB_FEATURE_SH_IS_MSH +// +// BusyBox will, by default, malloc space for its buffers. This costs code +// size for the call to xmalloc. You can use the following feature to have +// them put on the stack. For some very small machines with limited stack +// space, this can be deadly. For most folks, this works just fine... +//#define BB_FEATURE_BUFFERS_GO_ON_STACK +// The third alternative for buffer allocation is to use BSS. This works +// beautifully for computers with a real MMU (and OS support), but wastes +// runtime RAM for uCLinux. This behavior was the only one available for +// BusyBox versions 0.48 and earlier. +//#define BB_FEATURE_BUFFERS_GO_IN_BSS +// +// Turn this on to use Erik's very cool devps, and devmtab kernel drivers, +// thereby eliminating the need for the /proc filesystem and thereby saving +// lots and lots memory for more important things. NOTE: If you enable this +// feature, you _must_ have patched the kernel to include the devps patch that +// is included in the busybox/kernel-patches directory. You will also need to +// create some device special files in /dev on your embedded system: +// mknod /dev/mtab c 10 22 +// mknod /dev/ps c 10 21 +// I emailed Linus and this patch will not be going into the stock kernel. +//#define BB_FEATURE_USE_DEVPS_PATCH +// +// show verbose usage messages +//#define BB_FEATURE_VERBOSE_USAGE +// +// Use termios to manipulate the screen ('more' is prettier with this on) +#define BB_FEATURE_USE_TERMIOS +// +// calculate terminal & column widths (for more, ls, and telnet) +#define BB_FEATURE_AUTOWIDTH +// +// show username/groupnames for ls +#define BB_FEATURE_LS_USERNAME +// +// show file timestamps in ls +#define BB_FEATURE_LS_TIMESTAMPS +// +// enable ls -p and -F +#define BB_FEATURE_LS_FILETYPES +// +// sort the file names +#define BB_FEATURE_LS_SORTFILES +// +// enable ls -R +#define BB_FEATURE_LS_RECURSIVE +// +// enable ls -L +#define BB_FEATURE_LS_FOLLOWLINKS +// +// Use color to identify different file types +#define BB_FEATURE_LS_COLOR +// +// Disable for a smaller (but less functional) ping +#define BB_FEATURE_FANCY_PING +// +// Make init use a simplified /etc/inittab file (recommended). +#define BB_FEATURE_USE_INITTAB +// +//Enable init being called as /linuxrc +#define BB_FEATURE_LINUXRC +// +//Have init enable core dumping for child processes (for debugging only) +//#define BB_FEATURE_INIT_COREDUMPS +// +//Make sure nothing is printed to the console on boot +//#define BB_FEATURE_EXTRA_QUIET +// +// enable syslogd -R remotehost +//#define BB_FEATURE_REMOTE_LOG +// +// enable syslogd -C +//#define BB_FEATURE_IPC_SYSLOG +// +//Disable for a simple tail implementation (2.34k vs 3k for the full one). +//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. +#define BB_FEATURE_FANCY_TAIL +// +// Enable support for loop devices in mount +#define BB_FEATURE_MOUNT_LOOP +// +// Enable support for a real /etc/mtab file instead of /proc/mounts +//#define BB_FEATURE_MTAB_SUPPORT +// +// Enable support for mounting remote NFS volumes. +// You may need to mount with "-o nolock" if you are +// not running a local portmapper daemon... +// +// If you are using uClibc, be sure that you've already compiled +// uClibc with INCLUDE_RPC=true (contained in the Config file) +#define BB_FEATURE_NFSMOUNT +// +// Enable support forced filesystem unmounting +// (i.e., in case of an unreachable NFS system). +#define BB_FEATURE_MOUNT_FORCE +// +// Enable support for creation of tar files. +#define BB_FEATURE_TAR_CREATE +// +// Enable support for "--exclude" and "-X" for excluding files +//#define BB_FEATURE_TAR_EXCLUDE +// +// Enable support for tar -z option (currently only works for inflating) +#define BB_FEATURE_TAR_GZIP +// +// Enable reverse sort +//#define BB_FEATURE_SORT_REVERSE +// +// Enable uniqe sort +//#define BB_FEATURE_SORT_UNIQUE +// +// Enable command line editing in the shell. +// Only relevant if a shell is enabled. On by default. +//#define BB_FEATURE_COMMAND_EDITING +// +// Enable tab completion in the shell. This is now working quite nicely. +// This feature adds a bit over 4k. Only relevant if a shell is enabled. +//#define BB_FEATURE_COMMAND_TAB_COMPLETION +// +// Attempts to match usernames in a ~-prefixed path +//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION +// +//Allow the shell to invoke all the compiled in BusyBox applets as if they +//were shell builtins. Nice for staticly linking an emergency rescue shell, +//among other things. Off by default. +// Only relevant if a shell is enabled. +//#define BB_FEATURE_SH_STANDALONE_SHELL +// +//When this is enabled, busybox shell applets can be called using full path +//names. This causes applets (i.e., most busybox commands) to override +//real commands on the filesystem. For example, if you run run /bin/cat, it +//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_ +//busybox. Some systems want this, others do not. Choose wisely. :-) This +//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled. +// Only relevant if a shell is enabled. Off by default. +//#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN +// +// Uncomment this option for a fancy shell prompt that includes the +// current username and hostname. On systems that don't have usernames +// or hostnames, this can look hideous. +// Only relevant if a shell is enabled. +//#define BB_FEATURE_SH_FANCY_PROMPT +// +// Uncomment this option to disable job control. Job control lets you +// run jobs in the background (which completely useless for is all you +// are doing is running scripts). Disabing this is bad for interactive +// use, since when you hit ^C in an application, it will also kill the +// shell. This adds about 2.5k on an x86 system. +//#define BB_FEATURE_ASH_JOB_CONTROL +// +//Turn on extra fbset options +//#define BB_FEATURE_FBSET_FANCY +// +//Turn on fbset readmode support +//#define BB_FEATURE_FBSET_READMODE +// +// Support insmod/lsmod/rmmod for post 2.1 kernels +//#define BB_FEATURE_NEW_MODULE_INTERFACE +// +// Support insmod/lsmod/rmmod for pre 2.1 kernels +//#define BB_FEATURE_OLD_MODULE_INTERFACE +// +// Support module version checking +//#define BB_FEATURE_INSMOD_VERSION_CHECKING +// +// Support for uClinux memory usage optimization, which will load the image +// directly into the kernel memory. This divides memory requrements by three. +// If you are not running uClinux (i.e., your CPU has an MMU) leave this +// disabled... +//#define BB_FEATURE_INSMOD_LOADINKMEM +// +// Support for Minix filesystem, version 2 +//#define BB_FEATURE_MINIX2 +// +// Enable ifconfig status reporting output -- this feature adds 7k. +#define BB_FEATURE_IFCONFIG_STATUS +// +// Enable ifconfig slip-specific options "keepalive" and "outfill" +//#define BB_FEATURE_IFCONFIG_SLIP +// +// Enable ifconfig options "mem_start", "io_addr", and "irq". +#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ +// +// Enable ifconfig option "hw". Currently works for only with "ether". +#define BB_FEATURE_IFCONFIG_HW +// +// Allows "broadcast +" to set broadcast automatically based on hostaddr +// and netmask, at a cost of about 100 bytes of code (i386). +//#define BB_FEATURE_IFCONFIG_BROADCAST_PLUS +// +// Enable busybox --install [-s] +// to create links (or symlinks) for all the commands that are +// compiled into the binary. (needs /proc filesystem) +#define BB_FEATURE_INSTALLER +// +// Enable a nifty progress meter in wget (adds just under 2k) +#define BB_FEATURE_WGET_STATUSBAR +// +// Enable HTTP authentication in wget +#define BB_FEATURE_WGET_AUTHENTICATION +// +// Clean up all memory before exiting -- usually not needed +// as the OS can clean up... Don't enable this unless you +// have a really good reason for cleaning things up manually. +//#define BB_FEATURE_CLEAN_UP +// +// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G) +#define BB_FEATURE_HUMAN_READABLE +// +// Support for the find -type option. +#define BB_FEATURE_FIND_TYPE +// +// Support for the find -perm option. +#define BB_FEATURE_FIND_PERM +// +// Support for the find -mtime option. +#define BB_FEATURE_FIND_MTIME +// +//// Support for the find -newer option. +#define BB_FEATURE_FIND_NEWER +// +// Support for the -A -B and -C context flags in grep +//#define BB_FEATURE_GREP_CONTEXT +// +// Support for the EGREP applet (alias to the grep applet) +//#define BB_FEATURE_GREP_EGREP_ALIAS +// +// Tell tftp what commands that should be supported. +#define BB_FEATURE_TFTP_PUT +#define BB_FEATURE_TFTP_GET +// +// features for vi +//#define BB_FEATURE_VI_COLON // ":" colon commands, no "ex" mode +//#define BB_FEATURE_VI_YANKMARK // Yank/Put commands and Mark cmds +//#define BB_FEATURE_VI_SEARCH // search and replace cmds +//#define BB_FEATURE_VI_USE_SIGNALS // catch signals +//#define BB_FEATURE_VI_DOT_CMD // remember previous cmd and "." cmd +//#define BB_FEATURE_VI_READONLY // vi -R and "view" mode +//#define BB_FEATURE_VI_SETOPTS // set-able options, ai ic showmatch +//#define BB_FEATURE_VI_SET // :set +//#define BB_FEATURE_VI_WIN_RESIZE // handle window resize +// +// Enable a if you system have setuped locale +//#define BB_LOCALE_SUPPORT +// +// Support for TELNET to pass TERM type to remote host. Adds 384 bytes. +#define BB_FEATURE_TELNET_TTYPE +// +// Support for devfs. +//#define BB_FEATURE_DEVFS +// +// End of Features List +// +// +// +// +// +// +//--------------------------------------------------- +// Nothing beyond this point should ever be touched by +// mere mortals so leave this stuff alone. +// +#include +#if defined(__uClinux__) + #undef BB_RPM2CPIO /* Uses gz_open(), which uses fork() */ + #undef BB_DPKG_DEB /* Uses gz_open(), which uses fork() */ + #undef BB_FEATURE_TAR_GZIP /* Uses fork() */ + #undef BB_UPDATE /* Uses daemon() */ +#endif +#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH + #if defined BB_FEATURE_COMMAND_EDITING + #define BB_CMDEDIT + #else + #undef BB_FEATURE_COMMAND_EDITING + #undef BB_FEATURE_COMMAND_TAB_COMPLETION + #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION + #undef BB_FEATURE_SH_FANCY_PROMPT + #endif +#else + #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN + #undef BB_FEATURE_SH_STANDALONE_SHELL + #undef BB_FEATURE_SH_FANCY_PROMPT +#endif +// +#if (defined BB_ASH || defined BB_HUSH || defined BB_MSH) && ! defined BB_TEST + #define BB_TEST +#endif +// +#ifdef BB_KILLALL + #ifndef BB_KILL + #define BB_KILL + #endif +#endif +// +#ifndef BB_INIT + #undef BB_FEATURE_LINUXRC +#endif +// +#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT + #define BB_NFSMOUNT +#endif +// +#if defined BB_FEATURE_AUTOWIDTH + #ifndef BB_FEATURE_USE_TERMIOS + #define BB_FEATURE_USE_TERMIOS + #endif +#endif +// +#if defined BB_INSMOD || defined BB_LSMOD + #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE + #define BB_FEATURE_NEW_MODULE_INTERFACE + #endif +#endif +// +#ifdef BB_UNIX2DOS + #define BB_DOS2UNIX +#endif +// +#ifdef BB_SYSLOGD + #if defined BB_FEATURE_IPC_SYSLOG + #define BB_LOGREAD + #endif +#endif +// +#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH +# define shell_main ash_main +#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH +# define shell_main hush_main +#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH +# define shell_main lash_main +#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH +# define shell_main msh_main +#endif diff --git a/debian/Config.h-static b/debian/Config.h-static new file mode 100644 index 000000000..879642ccc --- /dev/null +++ b/debian/Config.h-static @@ -0,0 +1,493 @@ +/* vi: set sw=4 ts=4: */ +// This file defines the feature set to be compiled into busybox. +// When you turn things off here, they won't be compiled in at all. +// +//// This file is parsed by sed. You MUST use single line comments. +// i.e., //#define BB_BLAH +// +// +// BusyBox Applications +//#define BB_ADJTIMEX +#define BB_AR +#define BB_ASH +#define BB_BASENAME +#define BB_CAT +#define BB_CHGRP +#define BB_CHMOD +#define BB_CHOWN +#define BB_CHROOT +#define BB_CHVT +#define BB_CLEAR +#define BB_CMP +#define BB_CP +#define BB_CPIO +#define BB_CUT +#define BB_DATE +#define BB_DC +#define BB_DD +#define BB_DEALLOCVT +#define BB_DF +#define BB_DIRNAME +#define BB_DMESG +#define BB_DOS2UNIX +#define BB_DPKG +#define BB_DPKG_DEB +#define BB_DUTMP +#define BB_DU +#define BB_DUMPKMAP +#define BB_ECHO +#define BB_ENV +#define BB_EXPR +#define BB_FBSET +#define BB_FDFLUSH +#define BB_FIND +#define BB_FREE +#define BB_FREERAMDISK +#define BB_FSCK_MINIX +#define BB_GETOPT +#define BB_GREP +#define BB_GUNZIP +#define BB_GZIP +#define BB_HALT +#define BB_HEAD +#define BB_HOSTID +#define BB_HOSTNAME +//#define BB_HUSH +#define BB_ID +#define BB_IFCONFIG +#define BB_INIT +//#define BB_INSMOD +#define BB_KILL +#define BB_KILLALL +#define BB_KLOGD +//#define BB_LASH +#define BB_LENGTH +#define BB_LN +#define BB_LOADACM +#define BB_LOADFONT +#define BB_LOADKMAP +#define BB_LOGGER +#define BB_LOGNAME +#define BB_LOSETUP +#define BB_LS +#define BB_LSMOD +#define BB_MAKEDEVS +#define BB_MD5SUM +#define BB_MKDIR +#define BB_MKFIFO +#define BB_MKFS_MINIX +#define BB_MKNOD +#define BB_MKSWAP +#define BB_MKTEMP +#define BB_MODPROBE +#define BB_MORE +#define BB_MOUNT +//#define BB_MSH +#define BB_MT +#define BB_MV +#define BB_NC +#define BB_NSLOOKUP +#define BB_PIDOF +#define BB_PING +#define BB_PIVOT_ROOT +#define BB_POWEROFF +#define BB_PRINTF +#define BB_PS +#define BB_PWD +#define BB_RDATE +#define BB_READLINK +#define BB_REBOOT +#define BB_RENICE +#define BB_RESET +#define BB_RM +#define BB_RMDIR +#define BB_RMMOD +#define BB_ROUTE +#define BB_RPM2CPIO +#define BB_SED +#define BB_SETKEYCODES +#define BB_SLEEP +#define BB_SORT +#define BB_STTY +#define BB_SWAPONOFF +#define BB_SYNC +#define BB_SYSLOGD +#define BB_TAIL +#define BB_TAR +#define BB_TEE +#define BB_TEST +#define BB_TELNET +#define BB_TFTP +#define BB_TIME +#define BB_TOP +#define BB_TOUCH +#define BB_TR +#define BB_TRACEROUTE +#define BB_TRUE_FALSE +#define BB_TTY +#define BB_UNIX2DOS +#define BB_UUENCODE +#define BB_UUDECODE +#define BB_UMOUNT +#define BB_UNIQ +#define BB_UNAME +#define BB_UPDATE +#define BB_UPTIME +#define BB_USLEEP +#define BB_VI +#define BB_WATCHDOG +#define BB_WC +#define BB_WGET +#define BB_WHICH +#define BB_WHOAMI +#define BB_XARGS +#define BB_YES +// End of Applications List +// +// +// +// --------------------------------------------------------- +// This is where feature definitions go. Generally speaking, +// turning this stuff off makes things a bit smaller (and less +// pretty/useful). +// +// +// If you enabled one or more of the shells, you may select which one +// should be run when sh is invoked: +#define BB_FEATURE_SH_IS_ASH +//#define BB_FEATURE_SH_IS_HUSH +//#define BB_FEATURE_SH_IS_LASH +//#define BB_FEATURE_SH_IS_MSH +// +// BusyBox will, by default, malloc space for its buffers. This costs code +// size for the call to xmalloc. You can use the following feature to have +// them put on the stack. For some very small machines with limited stack +// space, this can be deadly. For most folks, this works just fine... +//#define BB_FEATURE_BUFFERS_GO_ON_STACK +// The third alternative for buffer allocation is to use BSS. This works +// beautifully for computers with a real MMU (and OS support), but wastes +// runtime RAM for uCLinux. This behavior was the only one available for +// BusyBox versions 0.48 and earlier. +//#define BB_FEATURE_BUFFERS_GO_IN_BSS +// +// Turn this on to use Erik's very cool devps, and devmtab kernel drivers, +// thereby eliminating the need for the /proc filesystem and thereby saving +// lots and lots memory for more important things. NOTE: If you enable this +// feature, you _must_ have patched the kernel to include the devps patch that +// is included in the busybox/kernel-patches directory. You will also need to +// create some device special files in /dev on your embedded system: +// mknod /dev/mtab c 10 22 +// mknod /dev/ps c 10 21 +// I emailed Linus and this patch will not be going into the stock kernel. +//#define BB_FEATURE_USE_DEVPS_PATCH +// +// show verbose usage messages +#define BB_FEATURE_VERBOSE_USAGE +// +// Use termios to manipulate the screen ('more' is prettier with this on) +#define BB_FEATURE_USE_TERMIOS +// +// calculate terminal & column widths (for more, ls, and telnet) +#define BB_FEATURE_AUTOWIDTH +// +// show username/groupnames for ls +#define BB_FEATURE_LS_USERNAME +// +// show file timestamps in ls +#define BB_FEATURE_LS_TIMESTAMPS +// +// enable ls -p and -F +#define BB_FEATURE_LS_FILETYPES +// +// sort the file names +#define BB_FEATURE_LS_SORTFILES +// +// enable ls -R +#define BB_FEATURE_LS_RECURSIVE +// +// enable ls -L +#define BB_FEATURE_LS_FOLLOWLINKS +// +// Use color to identify different file types +#define BB_FEATURE_LS_COLOR +// +// Disable for a smaller (but less functional) ping +#define BB_FEATURE_FANCY_PING +// +// Make init use a simplified /etc/inittab file (recommended). +#define BB_FEATURE_USE_INITTAB +// +//Enable init being called as /linuxrc +#define BB_FEATURE_LINUXRC +// +//Have init enable core dumping for child processes (for debugging only) +//#define BB_FEATURE_INIT_COREDUMPS +// +//Make sure nothing is printed to the console on boot +//#define BB_FEATURE_EXTRA_QUIET +// +// enable syslogd -R remotehost +#define BB_FEATURE_REMOTE_LOG +// +// enable syslogd -C +//#define BB_FEATURE_IPC_SYSLOG +// +//Disable for a simple tail implementation (2.34k vs 3k for the full one). +//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. +#define BB_FEATURE_FANCY_TAIL +// +// Enable support for loop devices in mount +#define BB_FEATURE_MOUNT_LOOP +// +// Enable support for a real /etc/mtab file instead of /proc/mounts +//#define BB_FEATURE_MTAB_SUPPORT +// +// Enable support for mounting remote NFS volumes. +// You may need to mount with "-o nolock" if you are +// not running a local portmapper daemon... +// +// If you are using uClibc, be sure that you've already compiled +// uClibc with INCLUDE_RPC=true (contained in the Config file) +#define BB_FEATURE_NFSMOUNT +// +// Enable support forced filesystem unmounting +// (i.e., in case of an unreachable NFS system). +#define BB_FEATURE_MOUNT_FORCE +// +// Enable support for creation of tar files. +#define BB_FEATURE_TAR_CREATE +// +// Enable support for "--exclude" and "-X" for excluding files +#define BB_FEATURE_TAR_EXCLUDE +// +// Enable support for tar -z option (currently only works for inflating) +#define BB_FEATURE_TAR_GZIP +// +// Enable reverse sort +#define BB_FEATURE_SORT_REVERSE +// +// Enable uniqe sort +#define BB_FEATURE_SORT_UNIQUE +// +// Enable command line editing in the shell. +// Only relevant if a shell is enabled. On by default. +#define BB_FEATURE_COMMAND_EDITING +// +// Enable tab completion in the shell. This is now working quite nicely. +// This feature adds a bit over 4k. Only relevant if a shell is enabled. +#define BB_FEATURE_COMMAND_TAB_COMPLETION +// +// Attempts to match usernames in a ~-prefixed path +#define BB_FEATURE_COMMAND_USERNAME_COMPLETION +// +//Allow the shell to invoke all the compiled in BusyBox applets as if they +//were shell builtins. Nice for staticly linking an emergency rescue shell, +//among other things. Off by default. +// Only relevant if a shell is enabled. +#define BB_FEATURE_SH_STANDALONE_SHELL +// +//When this is enabled, busybox shell applets can be called using full path +//names. This causes applets (i.e., most busybox commands) to override +//real commands on the filesystem. For example, if you run run /bin/cat, it +//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_ +//busybox. Some systems want this, others do not. Choose wisely. :-) This +//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled. +// Only relevant if a shell is enabled. Off by default. +#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN +// +// Uncomment this option for a fancy shell prompt that includes the +// current username and hostname. On systems that don't have usernames +// or hostnames, this can look hideous. +// Only relevant if a shell is enabled. +#define BB_FEATURE_SH_FANCY_PROMPT +// +// Uncomment this option to disable job control. Job control lets you +// run jobs in the background (which completely useless for is all you +// are doing is running scripts). Disabing this is bad for interactive +// use, since when you hit ^C in an application, it will also kill the +// shell. This adds about 2.5k on an x86 system. +#define BB_FEATURE_ASH_JOB_CONTROL +// +//Turn on extra fbset options +//#define BB_FEATURE_FBSET_FANCY +// +//Turn on fbset readmode support +#define BB_FEATURE_FBSET_READMODE +// +// Support insmod/lsmod/rmmod for post 2.1 kernels +#define BB_FEATURE_NEW_MODULE_INTERFACE +// +// Support insmod/lsmod/rmmod for pre 2.1 kernels +//#define BB_FEATURE_OLD_MODULE_INTERFACE +// +// Support module version checking +//#define BB_FEATURE_INSMOD_VERSION_CHECKING +// +// Support for uClinux memory usage optimization, which will load the image +// directly into the kernel memory. This divides memory requrements by three. +// If you are not running uClinux (i.e., your CPU has an MMU) leave this +// disabled... +//#define BB_FEATURE_INSMOD_LOADINKMEM +// +// Support for Minix filesystem, version 2 +#define BB_FEATURE_MINIX2 +// +// Enable ifconfig status reporting output -- this feature adds 7k. +#define BB_FEATURE_IFCONFIG_STATUS +// +// Enable ifconfig slip-specific options "keepalive" and "outfill" +#define BB_FEATURE_IFCONFIG_SLIP +// +// Enable ifconfig options "mem_start", "io_addr", and "irq". +#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ +// +// Enable ifconfig option "hw". Currently works for only with "ether". +#define BB_FEATURE_IFCONFIG_HW +// +// Allows "broadcast +" to set broadcast automatically based on hostaddr +// and netmask, at a cost of about 100 bytes of code (i386). +#define BB_FEATURE_IFCONFIG_BROADCAST_PLUS +// +// Enable busybox --install [-s] +// to create links (or symlinks) for all the commands that are +// compiled into the binary. (needs /proc filesystem) +//#define BB_FEATURE_INSTALLER +// +// Enable a nifty progress meter in wget (adds just under 2k) +#define BB_FEATURE_WGET_STATUSBAR +// +// Enable HTTP authentication in wget +#define BB_FEATURE_WGET_AUTHENTICATION +// +// Clean up all memory before exiting -- usually not needed +// as the OS can clean up... Don't enable this unless you +// have a really good reason for cleaning things up manually. +//#define BB_FEATURE_CLEAN_UP +// +// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G) +#define BB_FEATURE_HUMAN_READABLE +// +// Support for the find -type option. +#define BB_FEATURE_FIND_TYPE +// +// Support for the find -perm option. +#define BB_FEATURE_FIND_PERM +// +// Support for the find -mtime option. +#define BB_FEATURE_FIND_MTIME +// +//// Support for the find -newer option. +#define BB_FEATURE_FIND_NEWER +// +// Support for the -A -B and -C context flags in grep +#define BB_FEATURE_GREP_CONTEXT +// +// Support for the EGREP applet (alias to the grep applet) +#define BB_FEATURE_GREP_EGREP_ALIAS +// +// Tell tftp what commands that should be supported. +#define BB_FEATURE_TFTP_PUT +#define BB_FEATURE_TFTP_GET +// +// features for vi +#define BB_FEATURE_VI_COLON // ":" colon commands, no "ex" mode +#define BB_FEATURE_VI_YANKMARK // Yank/Put commands and Mark cmds +#define BB_FEATURE_VI_SEARCH // search and replace cmds +#define BB_FEATURE_VI_USE_SIGNALS // catch signals +#define BB_FEATURE_VI_DOT_CMD // remember previous cmd and "." cmd +#define BB_FEATURE_VI_READONLY // vi -R and "view" mode +#define BB_FEATURE_VI_SETOPTS // set-able options, ai ic showmatch +#define BB_FEATURE_VI_SET // :set +#define BB_FEATURE_VI_WIN_RESIZE // handle window resize +// +// Enable a if you system have setuped locale +//#define BB_LOCALE_SUPPORT +// +// Support for TELNET to pass TERM type to remote host. Adds 384 bytes. +#define BB_FEATURE_TELNET_TTYPE +// +// Support for devfs. +//#define BB_FEATURE_DEVFS +// +// End of Features List +// +// +// +// +// +// +//--------------------------------------------------- +// Nothing beyond this point should ever be touched by +// mere mortals so leave this stuff alone. +// +#include +#if defined(__uClinux__) + #undef BB_RPM2CPIO /* Uses gz_open(), which uses fork() */ + #undef BB_DPKG_DEB /* Uses gz_open(), which uses fork() */ + #undef BB_FEATURE_TAR_GZIP /* Uses fork() */ + #undef BB_UPDATE /* Uses daemon() */ +#endif +#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH + #if defined BB_FEATURE_COMMAND_EDITING + #define BB_CMDEDIT + #else + #undef BB_FEATURE_COMMAND_EDITING + #undef BB_FEATURE_COMMAND_TAB_COMPLETION + #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION + #undef BB_FEATURE_SH_FANCY_PROMPT + #endif +#else + #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN + #undef BB_FEATURE_SH_STANDALONE_SHELL + #undef BB_FEATURE_SH_FANCY_PROMPT +#endif +// +#if (defined BB_ASH || defined BB_HUSH || defined BB_MSH) && ! defined BB_TEST + #define BB_TEST +#endif +// +#ifdef BB_KILLALL + #ifndef BB_KILL + #define BB_KILL + #endif +#endif +// +#ifndef BB_INIT + #undef BB_FEATURE_LINUXRC +#endif +// +#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT + #define BB_NFSMOUNT +#endif +// +#if defined BB_FEATURE_AUTOWIDTH + #ifndef BB_FEATURE_USE_TERMIOS + #define BB_FEATURE_USE_TERMIOS + #endif +#endif +// +#if defined BB_INSMOD || defined BB_LSMOD + #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE + #define BB_FEATURE_NEW_MODULE_INTERFACE + #endif +#endif +// +#ifdef BB_UNIX2DOS + #define BB_DOS2UNIX +#endif +// +#ifdef BB_SYSLOGD + #if defined BB_FEATURE_IPC_SYSLOG + #define BB_LOGREAD + #endif +#endif +// +#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH +# define shell_main ash_main +#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH +# define shell_main hush_main +#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH +# define shell_main lash_main +#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH +# define shell_main msh_main +#endif diff --git a/debian/Config.h-udeb b/debian/Config.h-udeb new file mode 100644 index 000000000..82ec78427 --- /dev/null +++ b/debian/Config.h-udeb @@ -0,0 +1,493 @@ +/* vi: set sw=4 ts=4: */ +// This file defines the feature set to be compiled into busybox. +// When you turn things off here, they won't be compiled in at all. +// +//// This file is parsed by sed. You MUST use single line comments. +// i.e., //#define BB_BLAH +// +// +// BusyBox Applications +//#define BB_ADJTIMEX +#define BB_AR +//#define BB_ASH +#define BB_BASENAME +#define BB_CAT +//#define BB_CHGRP +#define BB_CHMOD +#define BB_CHOWN +#define BB_CHROOT +#define BB_CHVT +//#define BB_CLEAR +//#define BB_CMP +#define BB_CP +//#define BB_CPIO +#define BB_CUT +//#define BB_DATE +//#define BB_DC +//#define BB_DD +//#define BB_DEALLOCVT +#define BB_DF +#define BB_DIRNAME +#define BB_DMESG +//#define BB_DOS2UNIX +//#define BB_DPKG +//#define BB_DPKG_DEB +//#define BB_DUTMP +//#define BB_DU +//#define BB_DUMPKMAP +#define BB_ECHO +#define BB_ENV +#define BB_EXPR +//#define BB_FBSET +//#define BB_FDFLUSH +#define BB_FIND +#define BB_FREE +#define BB_FREERAMDISK +//#define BB_FSCK_MINIX +//#define BB_GETOPT +#define BB_GREP +#define BB_GUNZIP +//#define BB_GZIP +//#define BB_HALT +#define BB_HEAD +//#define BB_HOSTID +//#define BB_HOSTNAME +//#define BB_HUSH +#define BB_ID +#define BB_IFCONFIG +#define BB_INIT +//#define BB_INSMOD +#define BB_KILL +//#define BB_KILLALL +#define BB_KLOGD +//#define BB_LASH +//#define BB_LENGTH +#define BB_LN +//#define BB_LOADACM +//#define BB_LOADFONT +//#define BB_LOADKMAP +//#define BB_LOGGER +//#define BB_LOGNAME +//#define BB_LOSETUP +#define BB_LS +#define BB_LSMOD +//#define BB_MAKEDEVS +#define BB_MD5SUM +#define BB_MKDIR +//#define BB_MKFIFO +//#define BB_MKFS_MINIX +#define BB_MKNOD +//#define BB_MKSWAP +//#define BB_MKTEMP +//#define BB_MODPROBE +//#define BB_MORE +#define BB_MOUNT +//#define BB_MSH +//#define BB_MT +#define BB_MV +//#define BB_NC +//#define BB_NSLOOKUP +#define BB_PIDOF +#define BB_PING +#define BB_PIVOT_ROOT +//#define BB_POWEROFF +//#define BB_PRINTF +#define BB_PS +#define BB_PWD +//#define BB_RDATE +//#define BB_READLINK +#define BB_REBOOT +//#define BB_RENICE +//#define BB_RESET +#define BB_RM +#define BB_RMDIR +//#define BB_RMMOD +#define BB_ROUTE +//#define BB_RPM2CPIO +#define BB_SED +//#define BB_SETKEYCODES +//#define BB_SLEEP +#define BB_SORT +//#define BB_STTY +//#define BB_SWAPONOFF +#define BB_SYNC +#define BB_SYSLOGD +#define BB_TAIL +#define BB_TAR +//#define BB_TEE +//#define BB_TEST +#define BB_TELNET +//#define BB_TFTP +//#define BB_TIME +//#define BB_TOP +#define BB_TOUCH +#define BB_TR +//#define BB_TRACEROUTE +#define BB_TRUE_FALSE +//#define BB_TTY +//#define BB_UNIX2DOS +//#define BB_UUENCODE +//#define BB_UUDECODE +#define BB_UMOUNT +//#define BB_UNIQ +#define BB_UNAME +//#define BB_UPDATE +//#define BB_UPTIME +//#define BB_USLEEP +//#define BB_VI +//#define BB_WATCHDOG +#define BB_WC +#define BB_WGET +//#define BB_WHICH +//#define BB_WHOAMI +//#define BB_XARGS +//#define BB_YES +// End of Applications List +// +// +// +// --------------------------------------------------------- +// This is where feature definitions go. Generally speaking, +// turning this stuff off makes things a bit smaller (and less +// pretty/useful). +// +// +// If you enabled one or more of the shells, you may select which one +// should be run when sh is invoked: +//#define BB_FEATURE_SH_IS_ASH +//#define BB_FEATURE_SH_IS_HUSH +//#define BB_FEATURE_SH_IS_LASH +#define BB_FEATURE_SH_IS_MSH +// +// BusyBox will, by default, malloc space for its buffers. This costs code +// size for the call to xmalloc. You can use the following feature to have +// them put on the stack. For some very small machines with limited stack +// space, this can be deadly. For most folks, this works just fine... +//#define BB_FEATURE_BUFFERS_GO_ON_STACK +// The third alternative for buffer allocation is to use BSS. This works +// beautifully for computers with a real MMU (and OS support), but wastes +// runtime RAM for uCLinux. This behavior was the only one available for +// BusyBox versions 0.48 and earlier. +//#define BB_FEATURE_BUFFERS_GO_IN_BSS +// +// Turn this on to use Erik's very cool devps, and devmtab kernel drivers, +// thereby eliminating the need for the /proc filesystem and thereby saving +// lots and lots memory for more important things. NOTE: If you enable this +// feature, you _must_ have patched the kernel to include the devps patch that +// is included in the busybox/kernel-patches directory. You will also need to +// create some device special files in /dev on your embedded system: +// mknod /dev/mtab c 10 22 +// mknod /dev/ps c 10 21 +// I emailed Linus and this patch will not be going into the stock kernel. +//#define BB_FEATURE_USE_DEVPS_PATCH +// +// show verbose usage messages +//#define BB_FEATURE_VERBOSE_USAGE +// +// Use termios to manipulate the screen ('more' is prettier with this on) +#define BB_FEATURE_USE_TERMIOS +// +// calculate terminal & column widths (for more, ls, and telnet) +#define BB_FEATURE_AUTOWIDTH +// +// show username/groupnames for ls +#define BB_FEATURE_LS_USERNAME +// +// show file timestamps in ls +#define BB_FEATURE_LS_TIMESTAMPS +// +// enable ls -p and -F +//#define BB_FEATURE_LS_FILETYPES +// +// sort the file names +#define BB_FEATURE_LS_SORTFILES +// +// enable ls -R +//#define BB_FEATURE_LS_RECURSIVE +// +// enable ls -L +#define BB_FEATURE_LS_FOLLOWLINKS +// +// Use color to identify different file types +#define BB_FEATURE_LS_COLOR +// +// Disable for a smaller (but less functional) ping +#define BB_FEATURE_FANCY_PING +// +// Make init use a simplified /etc/inittab file (recommended). +#define BB_FEATURE_USE_INITTAB +// +//Enable init being called as /linuxrc +#define BB_FEATURE_LINUXRC +// +//Have init enable core dumping for child processes (for debugging only) +//#define BB_FEATURE_INIT_COREDUMPS +// +//Make sure nothing is printed to the console on boot +//#define BB_FEATURE_EXTRA_QUIET +// +// enable syslogd -R remotehost +//#define BB_FEATURE_REMOTE_LOG +// +// enable syslogd -C +//#define BB_FEATURE_IPC_SYSLOG +// +//Disable for a simple tail implementation (2.34k vs 3k for the full one). +//Both provide 'tail -f', but this cuts out -c, -q, -s, and -v. +//#define BB_FEATURE_FANCY_TAIL +// +// Enable support for loop devices in mount +#define BB_FEATURE_MOUNT_LOOP +// +// Enable support for a real /etc/mtab file instead of /proc/mounts +//#define BB_FEATURE_MTAB_SUPPORT +// +// Enable support for mounting remote NFS volumes. +// You may need to mount with "-o nolock" if you are +// not running a local portmapper daemon... +// +// If you are using uClibc, be sure that you've already compiled +// uClibc with INCLUDE_RPC=true (contained in the Config file) +#define BB_FEATURE_NFSMOUNT +// +// Enable support forced filesystem unmounting +// (i.e., in case of an unreachable NFS system). +#define BB_FEATURE_MOUNT_FORCE +// +// Enable support for creation of tar files. +//#define BB_FEATURE_TAR_CREATE +// +// Enable support for "--exclude" and "-X" for excluding files +//#define BB_FEATURE_TAR_EXCLUDE +// +// Enable support for tar -z option (currently only works for inflating) +#define BB_FEATURE_TAR_GZIP +// +// Enable reverse sort +//#define BB_FEATURE_SORT_REVERSE +// +// Enable uniqe sort +//#define BB_FEATURE_SORT_UNIQUE +// +// Enable command line editing in the shell. +// Only relevant if a shell is enabled. On by default. +#define BB_FEATURE_COMMAND_EDITING +// +// Enable tab completion in the shell. This is now working quite nicely. +// This feature adds a bit over 4k. Only relevant if a shell is enabled. +#define BB_FEATURE_COMMAND_TAB_COMPLETION +// +// Attempts to match usernames in a ~-prefixed path +//#define BB_FEATURE_COMMAND_USERNAME_COMPLETION +// +//Allow the shell to invoke all the compiled in BusyBox applets as if they +//were shell builtins. Nice for staticly linking an emergency rescue shell, +//among other things. Off by default. +// Only relevant if a shell is enabled. +//#define BB_FEATURE_SH_STANDALONE_SHELL +// +//When this is enabled, busybox shell applets can be called using full path +//names. This causes applets (i.e., most busybox commands) to override +//real commands on the filesystem. For example, if you run run /bin/cat, it +//will use BusyBox cat even if /bin/cat exists on the filesystem and is _not_ +//busybox. Some systems want this, others do not. Choose wisely. :-) This +//only has meaning when BB_FEATURE_SH_STANDALONE_SHELL is enabled. +// Only relevant if a shell is enabled. Off by default. +//#define BB_FEATURE_SH_APPLETS_ALWAYS_WIN +// +// Uncomment this option for a fancy shell prompt that includes the +// current username and hostname. On systems that don't have usernames +// or hostnames, this can look hideous. +// Only relevant if a shell is enabled. +//#define BB_FEATURE_SH_FANCY_PROMPT +// +// Uncomment this option to disable job control. Job control lets you +// run jobs in the background (which completely useless for is all you +// are doing is running scripts). Disabing this is bad for interactive +// use, since when you hit ^C in an application, it will also kill the +// shell. This adds about 2.5k on an x86 system. +#define BB_FEATURE_ASH_JOB_CONTROL +// +//Turn on extra fbset options +//#define BB_FEATURE_FBSET_FANCY +// +//Turn on fbset readmode support +//#define BB_FEATURE_FBSET_READMODE +// +// Support insmod/lsmod/rmmod for post 2.1 kernels +//#define BB_FEATURE_NEW_MODULE_INTERFACE +// +// Support insmod/lsmod/rmmod for pre 2.1 kernels +//#define BB_FEATURE_OLD_MODULE_INTERFACE +// +// Support module version checking +//#define BB_FEATURE_INSMOD_VERSION_CHECKING +// +// Support for uClinux memory usage optimization, which will load the image +// directly into the kernel memory. This divides memory requrements by three. +// If you are not running uClinux (i.e., your CPU has an MMU) leave this +// disabled... +//#define BB_FEATURE_INSMOD_LOADINKMEM +// +// Support for Minix filesystem, version 2 +//#define BB_FEATURE_MINIX2 +// +// Enable ifconfig status reporting output -- this feature adds 7k. +#define BB_FEATURE_IFCONFIG_STATUS +// +// Enable ifconfig slip-specific options "keepalive" and "outfill" +//#define BB_FEATURE_IFCONFIG_SLIP +// +// Enable ifconfig options "mem_start", "io_addr", and "irq". +#define BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ +// +// Enable ifconfig option "hw". Currently works for only with "ether". +#define BB_FEATURE_IFCONFIG_HW +// +// Allows "broadcast +" to set broadcast automatically based on hostaddr +// and netmask, at a cost of about 100 bytes of code (i386). +//#define BB_FEATURE_IFCONFIG_BROADCAST_PLUS +// +// Enable busybox --install [-s] +// to create links (or symlinks) for all the commands that are +// compiled into the binary. (needs /proc filesystem) +//#define BB_FEATURE_INSTALLER +// +// Enable a nifty progress meter in wget (adds just under 2k) +#define BB_FEATURE_WGET_STATUSBAR +// +// Enable HTTP authentication in wget +//#define BB_FEATURE_WGET_AUTHENTICATION +// +// Clean up all memory before exiting -- usually not needed +// as the OS can clean up... Don't enable this unless you +// have a really good reason for cleaning things up manually. +//#define BB_FEATURE_CLEAN_UP +// +// Support for human readable output by ls, du, etc.(example 13k, 23M, 235G) +#define BB_FEATURE_HUMAN_READABLE +// +// Support for the find -type option. +#define BB_FEATURE_FIND_TYPE +// +// Support for the find -perm option. +#define BB_FEATURE_FIND_PERM +// +// Support for the find -mtime option. +#define BB_FEATURE_FIND_MTIME +// +//// Support for the find -newer option. +#define BB_FEATURE_FIND_NEWER +// +// Support for the -A -B and -C context flags in grep +//#define BB_FEATURE_GREP_CONTEXT +// +// Support for the EGREP applet (alias to the grep applet) +//#define BB_FEATURE_GREP_EGREP_ALIAS +// +// Tell tftp what commands that should be supported. +#define BB_FEATURE_TFTP_PUT +#define BB_FEATURE_TFTP_GET +// +// features for vi +#define BB_FEATURE_VI_COLON // ":" colon commands, no "ex" mode +#define BB_FEATURE_VI_YANKMARK // Yank/Put commands and Mark cmds +#define BB_FEATURE_VI_SEARCH // search and replace cmds +#define BB_FEATURE_VI_USE_SIGNALS // catch signals +#define BB_FEATURE_VI_DOT_CMD // remember previous cmd and "." cmd +#define BB_FEATURE_VI_READONLY // vi -R and "view" mode +#define BB_FEATURE_VI_SETOPTS // set-able options, ai ic showmatch +#define BB_FEATURE_VI_SET // :set +#define BB_FEATURE_VI_WIN_RESIZE // handle window resize +// +// Enable a if you system have setuped locale +//#define BB_LOCALE_SUPPORT +// +// Support for TELNET to pass TERM type to remote host. Adds 384 bytes. +#define BB_FEATURE_TELNET_TTYPE +// +// Support for devfs. +//#define BB_FEATURE_DEVFS +// +// End of Features List +// +// +// +// +// +// +//--------------------------------------------------- +// Nothing beyond this point should ever be touched by +// mere mortals so leave this stuff alone. +// +#include +#if defined(__uClinux__) + #undef BB_RPM2CPIO /* Uses gz_open(), which uses fork() */ + #undef BB_DPKG_DEB /* Uses gz_open(), which uses fork() */ + #undef BB_FEATURE_TAR_GZIP /* Uses fork() */ + #undef BB_UPDATE /* Uses daemon() */ +#endif +#if defined BB_ASH || defined BB_HUSH || defined BB_LASH || defined BB_MSH + #if defined BB_FEATURE_COMMAND_EDITING + #define BB_CMDEDIT + #else + #undef BB_FEATURE_COMMAND_EDITING + #undef BB_FEATURE_COMMAND_TAB_COMPLETION + #undef BB_FEATURE_COMMAND_USERNAME_COMPLETION + #undef BB_FEATURE_SH_FANCY_PROMPT + #endif +#else + #undef BB_FEATURE_SH_APPLETS_ALWAYS_WIN + #undef BB_FEATURE_SH_STANDALONE_SHELL + #undef BB_FEATURE_SH_FANCY_PROMPT +#endif +// +#if (defined BB_ASH || defined BB_HUSH || defined BB_MSH) && ! defined BB_TEST + #define BB_TEST +#endif +// +#ifdef BB_KILLALL + #ifndef BB_KILL + #define BB_KILL + #endif +#endif +// +#ifndef BB_INIT + #undef BB_FEATURE_LINUXRC +#endif +// +#if defined BB_MOUNT && defined BB_FEATURE_NFSMOUNT + #define BB_NFSMOUNT +#endif +// +#if defined BB_FEATURE_AUTOWIDTH + #ifndef BB_FEATURE_USE_TERMIOS + #define BB_FEATURE_USE_TERMIOS + #endif +#endif +// +#if defined BB_INSMOD || defined BB_LSMOD + #if ! defined BB_FEATURE_NEW_MODULE_INTERFACE && ! defined BB_FEATURE_OLD_MODULE_INTERFACE + #define BB_FEATURE_NEW_MODULE_INTERFACE + #endif +#endif +// +#ifdef BB_UNIX2DOS + #define BB_DOS2UNIX +#endif +// +#ifdef BB_SYSLOGD + #if defined BB_FEATURE_IPC_SYSLOG + #define BB_LOGREAD + #endif +#endif +// +#if defined BB_ASH && defined BB_FEATURE_SH_IS_ASH +# define shell_main ash_main +#elif defined BB_HUSH && defined BB_FEATURE_SH_IS_HUSH +# define shell_main hush_main +#elif defined BB_LASH && defined BB_FEATURE_SH_IS_LASH +# define shell_main lash_main +#elif defined BB_MSH && defined BB_FEATURE_SH_IS_MSH +# define shell_main msh_main +#endif diff --git a/debian/README.debian b/debian/README.debian new file mode 100644 index 000000000..a43fde4da --- /dev/null +++ b/debian/README.debian @@ -0,0 +1,10 @@ +BusyBox for Debian +---------------------- + +BusyBox is being developed and maintained by Erik Andersen +. + +If you have a problem with BusyBox, send email to the Debian bug tracking +system that lives at + +Erik Andersen , Sun, 18 Jun 2000 21:52:00 -0600 diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 000000000..236766e96 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,318 @@ +busybox (1:0.60.5-2) unstable; urgency=low + + * It turns out that for the .udeb, we don't want to disable + BB_FEATURE_LINUXRC, we just want to kill the /linuxrc link. + Thanks to Matt Kraai for tracking this one down. (closes: #161611) + + -- Erik Andersen Thu, 31 Oct 2002 02:25:01 -0700 + +busybox (1:0.60.5-1) unstable; urgency=low + + * New version released. See Changelog for non-Debian specific details. + * zcat no longer tries to delete source files (closes: #164968) + * Eliminate /linuxrc from the .udeb (closes: #163890) + * Fix description of the --install option (closes: #164178) + + -- Erik Andersen Sat, 26 Oct 2002 06:23:51 -0600 + +busybox (1:0.60.4-1.1) unstable; urgency=low + + * NMU + * Fix cp -a so it handles symlinks properly (closes: #163501) + + -- Tollef Fog Heen Sun, 6 Oct 2002 16:08:45 +0200 + +busybox (1:0.60.4-1) unstable; urgency=low + + * New version released. See Changelog for non-Debian specific details. + * enable uname for the debian-installer (closes: #158706) + * enable losetup for the boot floppies (closes: #138060) + * init behaves itself better consoles go missing (closes: #129626) + * In 'free', buffers change as buffered data increases (closes: #148396) + * Functions for debootstrap added to the .udeb (closes: #124388) + * This bug is not reproducable (closes: #127522) + + -- Erik Andersen Wed, 18 Sep 2002 14:13:05 -0600 + +busybox (1:0.60.3-1) unstable; urgency=low + + * New version released. See Changelog for non-Debian specific details. + * makedevs no longer segfaults (closes: #123921) + * wget no longer crashes (closes: #138943) + * wget now checks the safe_fwrite return code (closes: #143179) + + -- Erik Andersen Sat, 27 Apr 2002 01:33:34 -0600 + +busybox (1:0.60.2-3) testing unstable; urgency=low + + * Fix wc stdin handling (closes: #123387). + * Fix wget to do just one DNS lookup (closes: #124068) + + -- Erik Andersen Sun, 16 Dec 2001 22:51:03 -0700 + +busybox (1:0.60.2-2) unstable; urgency=low + + * Several small bugfixes (closes: #120353, #120369, #122638, + * Reworked wc.c to fix the severe efficiency problems and make it + smaller. This one is mainly for the boot-floppies (closes: #120441) + * Enable hostname (closes: #120511) + + -- Erik Andersen Thu, 6 Dec 2001 00:06:33 -0700 + +busybox (1:0.60.2-1) unstable; urgency=low + + * New version released. See Changelog for non-Debian specific details. + * dpkg.c now uses an int for getopt (closes: #118975) + * s390 console reboot msg is now appropriate (closes: #118859) + * the manpage is no longer empty (closes: #117013) + * no more .o files in the source tarball (closes: #112046) + * the .udeb contents are exactly as Joey wants them (closes: #105352) + * busybox ash is the default shell for the -static package, + so it can cope with /etc/profile just fine (closes: #95745) + + -- Erik Andersen Tue, 20 Nov 2001 03:41:29 -0700 + +busybox (1:0.60.1-8) unstable; urgency=low + + * Adjusted some apps for the debian installer's .udeb package. + Enabled ifconfig, route. + Disabled chgrp, clear, date, dd, du, gzip, halt, head, killall, + loadkmap, logger, mkswap, more, poweroff, reset, sleep, sort, + swapon, swapoff, touch, tty, uniq, uname, uptime, vi, wc, which, + whoami, xargs, and yes. + + -- Erik Andersen Thu, 18 Oct 2001 22:59:06 -0600 + +busybox (1:0.60.1-7) unstable; urgency=low + + * Re-enable wget's status bar for today's dbootstrap change. (closes: #115717) + * Enable initrd support (even if they are a bad idea). (closes: #114727) + + -- Erik Andersen Mon, 15 Oct 2001 20:45:57 -0600 + +busybox (1:0.60.1-6) unstable; urgency=low + + * Re-enable wc, gzip, tty, and expr. (closes: #114906) + + -- Erik Andersen Wed, 10 Oct 2001 02:47:50 -0600 + +busybox (1:0.60.1-5) unstable; urgency=low + + * Time to make this official. This enables several applets, such + as ifconfig and route, and disables several others. + * Revert ash to the version in the busybox stable branch. For the + -3 non-release, I tried the one from busybox unstable (which lived + up to its name). (closes: #112503) + * Enable id, disable ash (closes: #114260, #113698) + * Backport several bugfixes from unstable + + -- Erik Andersen Fri, 5 Oct 2001 23:03:15 -0600 + +busybox (1:0.60.1-4) unstable; urgency=low + + * Doh! With busybox ash, we need test and echo enabled... + + -- Erik Andersen Wed, 26 Sep 2001 00:05:04 -0600 + +busybox (1:0.60.1-3) unstable; urgency=low + + * This upload is to test whether disabling several applets, and + enabling several others will help. Enabled is ifconfig, route, + and ash. Disabled is basename, date, echo, env, expr, gzip, + lsmod, and wc. + + -- Erik Andersen Tue, 25 Sep 2001 17:45:16 -0600 + +busybox (1:0.60.1-2) unstable; urgency=low + + * Disabled several applets to make busybox be a bit thinner, since the + powerpc boot floppies are _very_ tight on space (closes: #112503) + * Teach 'mount' about usbdevfs (closes: #111055) + * Busybox supports full online help, but due to space constraints on + the boot floppies, it will not be enabled. People can read the + busybox documentation if they need full details. (closes: #111350) + + -- Erik Andersen Sun, 23 Sep 2001 23:32:15 -0600 + +busybox (1:0.60.1-1) unstable; urgency=low + + * New stable version released. See changelog for details. + * Enabled 'ar' for the udeb + + -- Erik Andersen Thu, 23 Aug 2001 15:44:14 -0600 + +busybox (1:0.60.0-1) unstable; urgency=low + + * New stable version released. See changelog for details. + + -- Erik Andersen Thu, 2 Aug 2001 12:12:37 -0600 + +busybox (1:0.52-1.1) unstable; urgency=high + + * Non-maintainer upload + * Fixed wget -P handling (closes: #106223). + + -- Matt Kraai Wed, 25 Jul 2001 11:01:38 -0600 + +busybox (1:0.52-1) unstable; urgency=high + + * New version released. See changelog for details. + + -- Erik Andersen Sat, 7 Jul 2001 01:23:45 -0600 + +busybox (1:0.51-10) unstable; urgency=high + + * Fix a compile problem with gcc 3.0 on hppa (closes: #102045) + + -- Erik Andersen Sat, 23 Jun 2001 23:55:57 -0600 + +busybox (1:0.51-9) unstable; urgency=high + + * tar was creating leading directories with 0777 permissions as + as reult of faulty umask handling. This fixes it, repairing + a grave security problem in the woody the boot floppies. + (closes: #101169) + + -- Erik Andersen Wed, 20 Jun 2001 16:17:38 -0600 + +busybox (1:0.51-8) unstable; urgency=high + + * Fix cp from /proc, where size=0 (closes: #100369) + * Add some padding to struct sysinfo for m68k. + * Apparently some bugs failed to be closed when master choked + (closes: #99627, #99637, #98571) + * Disable the busybox shell for the .deb, since it is not needed + for the boot floppies. + + -- Erik Andersen Mon, 11 Jun 2001 13:26:07 -0600 + +busybox (1:0.51-7) unstable; urgency=high + + * Fix tar permission setting for existing directories (closes: #99627) + * Do not remove the .cvsignore files on 'make release' (closes: #99637) + + -- Erik Andersen Mon, 4 Jun 2001 10:55:19 -0600 + +busybox (1:0.51-6) testing unstable; urgency=high + + * Update the version in testing so DHCP in the woody boot-floppies will work. + * Enable expr for the boot-floppies (closes: #98433) + * It builds on arm just fine now (closes: #97510) + + -- Erik Andersen Wed, 23 May 2001 14:50:13 -0600 + +busybox (1:0.51-5) unstable; urgency=low + + * Backport a sed fix from 0.52pre + * Backport chroot fix from 0.52pre + + -- Erik Andersen Wed, 16 May 2001 23:50:33 -0600 + +busybox (1:0.51-4) unstable; urgency=low + + * Backport from 0.52pre an endianness bugfix for md5sum + * Backport some updates to grep and sed + * Fix 'wget -O -' so it sets the quiet flag + + -- Erik Andersen Mon, 14 May 2001 14:17:36 -0600 + +busybox (1:0.51-3) unstable; urgency=low + + * This is the "I am an idiot" release. + * Make cp and mv work again (closes: #97290) + * Fix the version number. + + -- Erik Andersen Sat, 12 May 2001 17:35:58 -0600 + +busybox (0.51-2) unstable; urgency=low + + * Backport several release critical fixes into the 0.51 codebase + so the boot-floppies will work again. + * Fix a link ordering problem. (closes: #93362) + * Fixed gunzip (closes: #94331) + * Fixed cp permission setting (closes: #94580) + + -- Erik Andersen Sat, 12 May 2001 11:22:35 -0600 + +busybox (0.51-1) unstable; urgency=low + + * Fixes several critical bugs (see the busybox changelog + for complete details) + * Force USE_SYSTEM_PWD_GRP=false, so busybox bypasses + the glibc NSS libraries. (closes: #93362) + * Fixed a bug in sed's address range handling (closes: #91758) + * Removed irrelevant cruft from the bottem of debian/changelog + + -- Erik Andersen Tue, 10 Apr 2001 14:07:29 -0600 + +busybox (0.50-2) unstable; urgency=low + + * Enabled freeramdisk and pivot_root in the udeb (closes: #91336) + * Disabled lash (the busybox shell) in the udeb (closes: #91337) + * fixed a bug in syslog, a problem with rebooting when booted as + an initrd, and a few other minor problems. + + -- Erik Andersen Sun, 25 Mar 2001 20:59:44 -0700 + + +busybox (0.50-2) unstable; urgency=low + + * Enabled freeramdisk and pivot_root in the udeb (closes: #91336) + * Disabled lash (the busybox shell) in the udeb (closes: #91337) + * fixed a bug in syslog, a problem with rebooting when booted as + an initrd, and a few other minor problems. + + -- Erik Andersen Sun, 25 Mar 2001 20:59:44 -0700 + +busybox (0.50-1) unstable; urgency=low + + * Tons on improvements all around -- See changelog for details. + * Fix malformed Build-Depends (closes: #86930) + * grep has worked for some time now (closes: #81084) + * init compiles with DEBUG_INIT enabled (closes: #85794) + * md5sum no longer displays filename when reading stdin (closes: #81283) + * lsmod, rmmod, and insmod are no longer enabled (closes: #85642) + * busybox and buxybox-static now conflict/replace each other (closes: #80421) + + -- Erik Andersen Thu, 15 Mar 2001 14:45:00 -0700 + +busybox (0.49-1) unstable; urgency=low + + * Lots more source updates and bug fixes. See changelog for details. + + -- Erik Andersen Sat, 27 Jan 2001 01:45:53 -0700 + +busybox (0.48-1) unstable; urgency=low + + * Lots more source updates and bug fixes. See changelog for details. + * Now includes .udeb support for the debian-installer. The .udeb + probably needs some more work, but this should be a good start. + + -- Erik Andersen Wed, 13 Dec 2000 08:36:07 -0700 + +busybox (0.47-1) unstable; urgency=low + + * New version released. See changelog for details. + + -- Erik Andersen Mon, 25 Sep 2000 23:00:56 -0600 + +busybox (0.46-1) unstable; urgency=low + + * New version released. See changelog for details. + + -- Erik Andersen Tue, 11 Jul 2000 12:15:44 -0600 + +busybox (0.45-1) unstable; urgency=low + + * First attempt at packaging BusyBox as a .deb. This has been in + in the Debian boot-floppies CVS tree forever. Hopefully, having it as a + standalone app will make life easier for me, the debian-installer team, and + everyone else as well... + * I have created a busybox-static that can be used as a rescue shell when you + hose your system. Just invoke "busybox sh" to fir up the shell. This has + every app provided by busybox staically linked in. There have been several + times in the past that I would have loved to have this sitting on my system + (i.e. when libc gets screwed up.) + + -- Erik Andersen Tue, 27 Jun 2000 12:26:41 -0600 + diff --git a/debian/control b/debian/control new file mode 100644 index 000000000..92551e721 --- /dev/null +++ b/debian/control @@ -0,0 +1,67 @@ +Source: busybox +Priority: optional +Maintainer: Erik Andersen +Build-Depends: debhelper (>= 2.1.18), dpkg-dev (>= 1.7.0) +Standards-Version: 3.2.1.0 + +Package: busybox +Architecture: any +Depends: ${shlibs:Depends} +Conflicts: busybox-static +Replaces: busybox-static +Section: utils +Description: Tiny utilities for small and embedded systems. + BusyBox combines tiny versions of many common UNIX utilities into a single + small executable. It provides minimalist replacements for the most common + utilities you would usually find on your desktop system (i.e., ls, cp, mv, + mount, tar, etc.). The utilities in BusyBox generally have fewer options than + their full-featured GNU cousins; however, the options that are included + provide the expected functionality and behave very much like their GNU + counterparts. + . + This package installs the BusyBox binary but does not install symlinks + for any of the supported utilities. You can use /bin/busybox --install + to install BusyBox to the root directory (you do not want to do this + to your your Debian system, except in dire emergencies!). + +Package: busybox-static +Architecture: any +Depends: ${shlibs:Depends} +Conflicts: busybox +Replaces: busybox +Section: shells +Priority: extra +Description: Standalone rescue shell with tons of builtin utilities. + BusyBox combines tiny versions of many common UNIX utilities into a single + small executable. It provides minimalist replacements for the most common + utilities you would usually find on your desktop system (i.e., ls, cp, mv, + mount, tar, etc.). The utilities in BusyBox generally have fewer options than + their full-featured GNU cousins; however, the options that are included + provide the expected functionality and behave very much like their GNU + counterparts. + . + BusyBox-static provides you with a statically linked simple stand alone shell + that provides all the utilities available in BusyBox. This package is + intended to be used as a rescue shell, in the event that you screw up your + system. Invoke "busybox sh" and you have a standalone shell ready to save + your system from certain destruction. Invoke "busybox", and it will list the + available builtin commands. + +Package: busybox-udeb +Architecture: any +Depends: ${shlibs:Depends} +Section: debian-installer +Priority: standard +Description: Tiny utilities for the debian-installer + BusyBox combines tiny versions of many common UNIX utilities into a single + small executable. It provides minimalist replacements for the most common + utilities you would usually find on your desktop system (i.e., ls, cp, mv, + mount, tar, etc.). The utilities in BusyBox generally have fewer options than + their full-featured GNU cousins; however, the options that are included + provide the expected functionality and behave very much like their GNU + counterparts. + . + busybox-udeb is used by the debian-installer, so unless you are working + on the debian-installer, this package is not for you. Installing this + on your Debian system is a very, very bad idea. You have been warned. + diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 000000000..68a96e68b --- /dev/null +++ b/debian/copyright @@ -0,0 +1,7 @@ +This package was debianized by Erik Andersen on +Sun, 18 Jun 2000 23:31:02 -0600 + +It was downloaded from ftp://ftp.lineo.com/pub/busybox +HomePage is at: http://busybox.lineo.com/ + +Copyright: GPL diff --git a/debian/rules b/debian/rules new file mode 100755 index 000000000..dd0ffa4d1 --- /dev/null +++ b/debian/rules @@ -0,0 +1,194 @@ +#!/usr/bin/make -f + +# This is a bit unusual, in that I have to completely recompile everything +# for each package I build (obviously static and dynamic builds require +# things to be recompiled...) + +# This is the debhelper compatability version to use. +#export DH_COMPAT=1 + +bbbd=debian/busybox_builddir +bb=debian/tmp +bbsbd=debian/busybox_static_builddir +bbs=debian/busybox-static +bbubd=debian/busybox_udeb_builddir +bbu=debian/busybox-udeb + +clean: + dh_testdir + dh_testroot + rm -f debian/build-stamp-busybox debian/build-stamp-busybox-static debian/build-stamp-busybox-udeb + -$(MAKE) clean + -rm -rf $(bb) $(bbbd) $(bbs) $(bbsbd) $(bbubd) $(bbu) + dh_clean + +build: debian/build-stamp-busybox +debian/build-stamp-busybox: + dh_testdir + mkdir -p $(bbbd) + cp Makefile $(bbbd) + cp debian/Config.h-deb $(bbbd)/Config.h + -(cd $(bbbd); $(MAKE) "BB_SRC_DIR=../../" applet_source_list) + (cd $(bbbd); $(MAKE) USE_SYSTEM_PWD_GRP=false "BB_SRC_DIR=../../") + touch debian/build-stamp-busybox + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + # Do not run 'make install', since we do not want all the symlinks. + # This just installes the busybox binary... + #(cd $(bbbd); $(MAKE) "BB_SRC_DIR=../../" "PREFIX=../../$(bb)" install) + mkdir -p $(bb)/bin/ + cp $(bbbd)/busybox $(bb)/bin/busybox + mkdir -p $(bb)/usr/share/doc/busybox + cp $(bbbd)/docs/BusyBox.html $(bb)/usr/share/doc/busybox/ + mkdir -p $(bb)/usr/share/man/man1 + cp $(bbbd)/docs/BusyBox.1 $(bb)/usr/share/man/man1/busybox.1 + +# Now for the statically linked stuff +build-static: debian/build-stamp-busybox-static +debian/build-stamp-busybox-static: + dh_testdir + mkdir -p $(bbsbd) + cp Makefile $(bbsbd) + cp debian/Config.h-static $(bbsbd)/Config.h + (cd $(bbsbd); $(MAKE) DOSTATIC=true USE_SYSTEM_PWD_GRP=false "BB_SRC_DIR=../../") + touch debian/build-stamp-busybox-static + +install-static: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + # Do not run 'make install', since we do not want all the symlinks. + # This just installes the busybox binary... + #(cd $(bbsbd); $(MAKE) "BB_SRC_DIR=../../" "PREFIX=../../$(bbs)" install) + mkdir -p $(bbs)/bin/ + cp $(bbsbd)/busybox $(bbs)/bin/busybox + mkdir -p $(bbs)/usr/share/doc/busybox-static + cp $(bbsbd)/docs/BusyBox.html $(bbs)/usr/share/doc/busybox-static/ + mkdir -p $(bbs)/usr/share/man/man1/ + cp $(bbsbd)/docs/BusyBox.1 $(bbs)/usr/share/man/man1/busybox.1 + +half_clean: + dh_testdir + dh_testroot + rm -rf $(bbs) debian/build-stamp-busybox-static + -$(MAKE) clean + +do_static: half_clean build-static install-static + + + +# Now for the .udeb stuff +PACKAGE=busybox-udeb +VERSION=$(shell dpkg-parsechangelog | grep ^Version: | cut -d ' ' -f 2 | sed -e s/[0-9]://g) +ARCH=$(shell dpkg --print-architecture) +FILENAME=$(PACKAGE)_$(VERSION)_$(ARCH).udeb + +build-udeb: debian/build-stamp-busybox-udeb +debian/build-stamp-busybox-udeb: + dh_testdir + mkdir -p $(bbubd) + cp Makefile $(bbubd) + cp debian/Config.h-udeb $(bbubd)/Config.h + (cd $(bbubd); $(MAKE) USE_SYSTEM_PWD_GRP=false "BB_SRC_DIR=../../") + touch debian/build-stamp-busybox-udeb + +install-udeb: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + (cd $(bbubd); $(MAKE) "BB_SRC_DIR=../../" "PREFIX=../../$(bbu)" install) + rm -f $(bbu)/linuxrc + mkdir -p $(bbu)/usr/share/man/man1/ + cp $(bbubd)/docs/BusyBox.1 $(bbu)/usr/share/man/man1/busybox.1 + +three_quarter_clean: + dh_testdir + dh_testroot + rm -rf $(bbu) debian/build-stamp-busybox-udeb + -$(MAKE) clean + +do_udeb: three_quarter_clean build-udeb install-udeb + + + +# Build architecture-independent files here. +binary-indep: +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: busybox busybox-static busybox-udeb + +busybox: install + @echo "--- Building: $@" + dh_testdir + dh_testroot + dh_installdirs + dh_installdocs -p$@ $(bbbd)/docs/BusyBox.txt \ + $(bbbd)/docs/BusyBox.html docs/style-guide.txt \ + AUTHORS README TODO + rm -rf `find $(bb) -name CVS` + rm -f `find $(bb) -name .cvsignore` + dh_installchangelogs -p$@ Changelog + dh_undocumented -p$@ + dh_strip -p$@ + dh_compress -p$@ + dh_fixperms -p$@ + dh_installdeb -p$@ + dh_shlibdeps -p$@ + dh_gencontrol -p$@ + dh_md5sums -p$@ + dh_builddeb -p$@ + + +busybox-static: do_static + @echo "--- Building: $@" + dh_testdir + dh_testroot + dh_installdirs + dh_installdocs -p$@ $(bbsbd)/docs/BusyBox.txt \ + $(bbsbd)/docs/BusyBox.html docs/style-guide.txt \ + AUTHORS README TODO + rm -rf `find $(bbs) -name CVS` + rm -f `find $(bbs) -name .cvsignore` + dh_installchangelogs -p$@ Changelog + dh_undocumented -p$@ + dh_strip -p$@ + dh_compress -p$@ + dh_fixperms -p$@ + dh_installdeb -p$@ + dh_shlibdeps -p$@ + dh_gencontrol -p$@ + dh_md5sums -p$@ + dh_builddeb -p$@ + + +# Note that this builds a .udeb, which is not policy compliant or anything. +# +busybox-udeb: do_udeb + @echo "--- Building: $@" + dh_testdir + dh_testroot + dh_installdirs + dh_strip -p$@ + dh_compress -p$@ + dh_fixperms -p$@ + dh_installdeb -p$@ + dh_shlibdeps -p$@ + #Make _very_ sure there are no docs lurking about. + rm -rf $(bbu)/usr/share/man + #dh_gencontrol -p$@ + # Don't write your stupid guesses to debian/files. + dh_gencontrol -p$@ -- -fdebian/files~ + # Register file manually. + dpkg-distaddfile $(FILENAME) debian-installer standard + dh_md5sums -p$@ + dh_builddeb -p$@ --filename=$(FILENAME) + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install diff --git a/df.c b/df.c new file mode 100644 index 000000000..535ab58fc --- /dev/null +++ b/df.c @@ -0,0 +1,158 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini df implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +extern const char mtab_file[]; /* Defined in utility.c */ +#ifdef BB_FEATURE_HUMAN_READABLE +static unsigned long df_disp_hr = KILOBYTE; +#endif + +static int do_df(char *device, const char *mount_point) +{ + struct statfs s; + long blocks_used; + long blocks_percent_used; + + if (statfs(mount_point, &s) != 0) { + perror_msg("%s", mount_point); + return FALSE; + } + + if (s.f_blocks > 0) { + blocks_used = s.f_blocks - s.f_bfree; + if(blocks_used == 0) + blocks_percent_used = 0; + else { + blocks_percent_used = (long) + (blocks_used * 100.0 / (blocks_used + s.f_bavail) + 0.5); + } + if (strcmp(device, "/dev/root") == 0) { + /* Adjusts device to be the real root device, + * or leaves device alone if it can't find it */ + device = find_real_root_device_name(device); + if(device==NULL) + return FALSE; + } +#ifdef BB_FEATURE_HUMAN_READABLE + printf("%-20s %9s ", device, + make_human_readable_str(s.f_blocks, s.f_bsize, df_disp_hr)); + + printf("%9s ", + make_human_readable_str( (s.f_blocks - s.f_bfree), s.f_bsize, df_disp_hr)); + + printf("%9s %3ld%% %s\n", + make_human_readable_str(s.f_bavail, s.f_bsize, df_disp_hr), + blocks_percent_used, mount_point); +#else + printf("%-20s %9ld %9ld %9ld %3ld%% %s\n", + device, + (long) (s.f_blocks * (s.f_bsize / (double)KILOBYTE)), + (long) ((s.f_blocks - s.f_bfree)*(s.f_bsize/(double)KILOBYTE)), + (long) (s.f_bavail * (s.f_bsize / (double)KILOBYTE)), + blocks_percent_used, mount_point); +#endif + } + + return TRUE; +} + +extern int df_main(int argc, char **argv) +{ + int status = EXIT_SUCCESS; + int opt = 0; + int i = 0; + char disp_units_hdr[80] = "1k-blocks"; /* default display is kilobytes */ + + while ((opt = getopt(argc, argv, "k" +#ifdef BB_FEATURE_HUMAN_READABLE + "hm" +#endif +)) > 0) + { + switch (opt) { +#ifdef BB_FEATURE_HUMAN_READABLE + case 'h': + df_disp_hr = 0; + strcpy(disp_units_hdr, " Size"); + break; + case 'm': + df_disp_hr = MEGABYTE; + strcpy(disp_units_hdr, "1M-blocks"); + break; +#endif + case 'k': + /* default display is kilobytes */ + break; + default: + show_usage(); + } + } + + printf("%-20s %-14s %s %s %s %s\n", "Filesystem", disp_units_hdr, + "Used", "Available", "Use%", "Mounted on"); + + if(optind < argc) { + struct mntent *mount_entry; + for(i = optind; i < argc; i++) + { + if ((mount_entry = find_mount_point(argv[i], mtab_file)) == 0) { + error_msg("%s: can't find mount point.", argv[i]); + status = EXIT_FAILURE; + } else if (!do_df(mount_entry->mnt_fsname, mount_entry->mnt_dir)) + status = EXIT_FAILURE; + } + } else { + FILE *mount_table; + struct mntent *mount_entry; + + mount_table = setmntent(mtab_file, "r"); + if (mount_table == 0) { + perror_msg("%s", mtab_file); + return EXIT_FAILURE; + } + + while ((mount_entry = getmntent(mount_table))) { + if (!do_df(mount_entry->mnt_fsname, mount_entry->mnt_dir)) + status = EXIT_FAILURE; + } + endmntent(mount_table); + } + + return status; +} + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/dirname.c b/dirname.c new file mode 100644 index 000000000..387233789 --- /dev/null +++ b/dirname.c @@ -0,0 +1,40 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini dirname implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +/* getopt not needed */ + +#include +#include +#include +#include "busybox.h" + +extern int dirname_main(int argc, char **argv) +{ + if ((argc < 2) || (**(argv + 1) == '-')) + show_usage(); + argv++; + + puts (dirname (argv[0])); + + return EXIT_SUCCESS; +} diff --git a/dmesg.c b/dmesg.c new file mode 100644 index 000000000..73de6d1ae --- /dev/null +++ b/dmesg.c @@ -0,0 +1,95 @@ +/* vi: set sw=4 ts=4: */ +/* dmesg.c -- Print out the contents of the kernel ring buffer + * Created: Sat Oct 9 16:19:47 1993 + * Revised: Thu Oct 28 21:52:17 1993 by faith@cs.unc.edu + * Copyright 1993 Theodore Ts'o (tytso@athena.mit.edu) + * This program comes with ABSOLUTELY NO WARRANTY. + * Modifications by Rick Sladkey (jrs@world.std.com) + * Larger buffersize 3 June 1998 by Nicolai Langfeldt, based on a patch + * by Peeter Joot. This was also suggested by John Hudson. + * 1999-02-22 Arkadiusz Mi¶kiewicz + * - added Native Language Support + * + * from util-linux -- adapted for busybox by + * Erik Andersen . I ripped out Native Language + * Support, replaced getopt, added some gotos for redundant stuff. + */ + +#include +#include +#include + +#if __GNU_LIBRARY__ < 5 +# ifdef __alpha__ +# define klogctl syslog +# endif +#else +# include +#endif + +#include "busybox.h" + +int dmesg_main(int argc, char **argv) +{ + char *buf; + int c; + int bufsize = 8196; + int i; + int n; + int level = 0; + int lastc; + int cmd = 3; + + while ((c = getopt(argc, argv, "cn:s:")) != EOF) { + switch (c) { + case 'c': + cmd = 4; + break; + case 'n': + cmd = 8; + if (optarg == NULL) + show_usage(); + level = atoi(optarg); + break; + case 's': + if (optarg == NULL) + show_usage(); + bufsize = atoi(optarg); + break; + default: + show_usage(); + } + } + + if (optind < argc) { + show_usage(); + } + + if (cmd == 8) { + if (klogctl(cmd, NULL, level) < 0) + perror_msg_and_die("klogctl"); + return EXIT_SUCCESS; + } + + if (bufsize < 4096) + bufsize = 4096; + buf = (char *) xmalloc(bufsize); + if ((n = klogctl(cmd, buf, bufsize)) < 0) + perror_msg_and_die("klogctl"); + + lastc = '\n'; + for (i = 0; i < n; i++) { + if (lastc == '\n' && buf[i] == '<') { + i++; + while (buf[i] >= '0' && buf[i] <= '9') + i++; + if (buf[i] == '>') + i++; + } + lastc = buf[i]; + putchar(lastc); + } + if (lastc != '\n') + putchar('\n'); + return EXIT_SUCCESS; +} diff --git a/docs/.cvsignore b/docs/.cvsignore new file mode 100644 index 000000000..ec9e94b27 --- /dev/null +++ b/docs/.cvsignore @@ -0,0 +1,8 @@ +BusyBox.txt +BusyBox.1 +BusyBox.html +busybox.txt +busybox.ps +busybox.pdf +busybox +busybox.pod diff --git a/docs/autodocifier.pl b/docs/autodocifier.pl new file mode 100755 index 000000000..e6e2b0cd3 --- /dev/null +++ b/docs/autodocifier.pl @@ -0,0 +1,287 @@ +#!/usr/bin/perl -w + +use strict; +use Getopt::Long; + +# collect lines continued with a '\' into an array +sub continuation { + my $fh = shift; + my @line; + + while (<$fh>) { + my $s = $_; + $s =~ s/\\\s*$//; + #$s =~ s/#.*$//; + push @line, $s; + last unless (/\\\s*$/); + } + return @line; +} + +# regex && eval away unwanted strings from documentation +sub beautify { + my $text = shift; + $text =~ s/USAGE_NOT\w+\(.*?"\s*\)//sxg; + $text =~ s/USAGE_\w+\(\s*?(.*?)"\s*\)/$1"/sxg; + $text =~ s/"\s*"//sg; + my @line = split("\n", $text); + $text = join('', + map { + s/^\s*"//; + s/"\s*$//; + s/%/%%/g; + s/\$/\\\$/g; + eval qq[ sprintf(qq{$_}) ] + } @line + ); + return $text; +} + +# generate POD for an applet +sub pod_for_usage { + my $name = shift; + my $usage = shift; + + # make options bold + my $trivial = $usage->{trivial}; + $trivial =~ s/(?/sxg; + my @f0 = + map { $_ !~ /^\s/ && s/(?/g; $_ } + split("\n", $usage->{full}); + + # add "\n" prior to certain lines to make indented + # lines look right + my @f1; + my $len = @f0; + for (my $i = 0; $i < $len; $i++) { + push @f1, $f0[$i]; + if (($i+1) != $len && $f0[$i] !~ /^\s/ && $f0[$i+1] =~ /^\s/) { + next if ($f0[$i] =~ /^$/); + push(@f1, "") unless ($f0[$i+1] =~ /^\s*$/s); + } + } + my $full = join("\n", @f1); + + # prepare notes if they exist + my $notes = (defined $usage->{notes}) + ? "$usage->{notes}\n\n" + : ""; + + # prepare examples if they exist + my $example = (defined $usage->{example}) + ? + "Example:\n\n" . + join ("\n", + map { "\t$_" } + split("\n", $usage->{example})) . "\n\n" + : ""; + + return + "=item B<$name>". + "\n\n" . + "$name $trivial". + "\n\n" . + $full . + "\n\n" . + $notes . + $example. + "-------------------------------". + "\n\n" + ; +} + +# FIXME | generate SGML for an applet +sub sgml_for_usage { + my $name = shift; + my $usage = shift; + return + "\n". + " $name\n". + "\n" + ; +} + +# the keys are applet names, and +# the values will contain hashrefs of the form: +# +# { +# trivial => "...", +# full => "...", +# notes => "...", +# example => "...", +# } +my %docs; + + +# get command-line options + +my %opt; + +GetOptions( + \%opt, + "help|h", + "sgml|s", + "pod|p", + "verbose|v", +); + +if (defined $opt{help}) { + print + "$0 [OPTION]... [FILE]...\n", + "\t--help\n", + "\t--sgml\n", + "\t--pod\n", + "\t--verbose\n", + ; + exit 1; +} + + +# collect documenation into %docs + +foreach (@ARGV) { + open(USAGE, $_) || die("$0: $_: $!"); + my $fh = *USAGE; + my ($applet, $type, @line); + while (<$fh>) { + if (/^#define (\w+)_(\w+)_usage/) { + $applet = $1; + $type = $2; + @line = continuation($fh); + my $doc = $docs{$applet} ||= { }; + my $text = join("\n", @line); + $doc->{$type} = beautify($text); + } + } +} + + +# generate structured documentation + +my $generator = \&pod_for_usage; +if (defined $opt{sgml}) { + $generator = \&sgml_for_usage; +} + +foreach my $applet (sort keys %docs) { + print $generator->($applet, $docs{$applet}); +} + +exit 0; + +__END__ + +=head1 NAME + +autodocifier.pl - generate docs for busybox based on usage.h + +=head1 SYNOPSIS + +autodocifier.pl [OPTION]... [FILE]... + +Example: + + ( cat docs/busybox_header.pod; \ + docs/autodocifier.pl usage.h; \ + cat docs/busybox_footer.pod ) > docs/busybox.pod + +=head1 DESCRIPTION + +The purpose of this script is to automagically generate documentation +for busybox using its usage.h as the original source for content. +Currently, the same content has to be duplicated in 3 places in +slightly different formats -- F, F, and +F. This is tedious, so Perl has come to the rescue. + +This script was based on a script by Erik Andersen +which was in turn based on a script by Mark Whitley + +=head1 OPTIONS + +=over 4 + +=item B<--help> + +This displays the help message. + +=item B<--pod> + +Generate POD (this is the default) + +=item B<--sgml> + +Generate SGML + +=item B<--verbose> + +Be verbose (not implemented) + +=back + +=head1 FORMAT + +The following is an example of some data this script might parse. + + #define length_trivial_usage \ + "STRING" + #define length_full_usage \ + "Prints out the length of the specified STRING." + #define length_example_usage \ + "$ length Hello\n" \ + "5\n" + +Each entry is a cpp macro that defines a string. The macros are +named systematically in the form: + + $name_$type_usage + +$name is the name of the applet. $type can be "trivial", "full", "notes", +or "example". Every documentation macro must end with "_usage". + +The definition of the types is as follows: + +=over 4 + +=item B + +This should be a brief, one-line description of parameters that +the command expects. This will be displayed when B<-h> is issued to +a command. I + +=item B + +This should contain descriptions of each option. This will also +be displayed along with the trivial help if BB_FEATURE_TRIVIAL_HELP +is disabled. I + +=item B + +This is documentation that is intended to go in the POD or SGML, but +not be printed when a B<-h> is given to a command. To see an example +of notes being used, see init_notes_usage. I + +=item B + +This should be an example of how the command is acutally used. +This will not be printed when a B<-h> is given to a command -- it +is inteded only for the POD or SGML documentation. I + +=back + +=head1 FILES + +F + +=head1 COPYRIGHT + +Copyright (c) 2001 John BEPPU. All rights reserved. This program is +free software; you can redistribute it and/or modify it under the same +terms as Perl itself. + +=head1 AUTHOR + +John BEPPU + +=cut + +# $Id: autodocifier.pl,v 1.22 2001/11/19 23:57:54 andersen Exp $ diff --git a/docs/busybox.sgml b/docs/busybox.sgml new file mode 100644 index 000000000..3dbd85083 --- /dev/null +++ b/docs/busybox.sgml @@ -0,0 +1,3974 @@ + + + + BusyBox - The Swiss Army Knife of Embedded Linux + + + + This documentation 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 + + + + For more details see the file COPYING in the source + distribution of Linux. + + + + + + + Introduction + + + BusyBox combines tiny versions of many common UNIX utilities into a single + small executable. It provides minimalist replacements for most of the + utilities you usually find in fileutils, shellutils, findutils, textutils, + grep, gzip, tar, etc. BusyBox provides a fairly complete POSIX environment + for any small or embedded system. The utilities in BusyBox generally have + fewer options than their full-featured GNU cousins; however, the options + that are included provide the expected functionality and behave very much + like their GNU counterparts. + + + + BusyBox has been written with size-optimization and limited resources in + mind. It is also extremely modular so you can easily include or exclude + commands (or features) at compile time. This makes it easy to customize + your embedded systems. To create a working system, just add a kernel, a + shell (such as ash), and an editor (such as elvis-tiny or ae). + + + + + How to use BusyBox + + Syntax + + + + BusyBox <function> [arguments...] # or + + + + + + <function> [arguments...] # if symlinked + + + + + + Invoking BusyBox + + + When you create a link to BusyBox for the function you wish to use, when + BusyBox is called using that link it will behave as if the command itself + has been invoked. + + + + For example, entering + + + + + ln -s ./BusyBox ls + ./ls + + + + + will cause BusyBox to behave as 'ls' (if the 'ls' command has been compiled + into BusyBox). + + + + You can also invoke BusyBox by issuing the command as an argument on the + command line. For example, entering + + + + + ./BusyBox ls + + + + + will also cause BusyBox to behave as 'ls'. + + + + + + Common options + + + Most BusyBox commands support the --help option to provide + a terse runtime description of their behavior. + + + + + + BusyBox Commands + + Available BusyBox Commands + + Currently defined functions include: + + + + ar, basename, cat, chgrp, chmod, chown, chroot, chvt, clear, + cp, cut, date, dc, dd, deallocvt, df, dirname, dmesg, dpkg-deb, + du, dumpkmap, dutmp, echo, false, fbset, fdflush, find, free, + freeramdisk, fsck.minix, grep, gunzip, gzip, halt, head, + hostid, hostname, id, init, insmod, kill, killall, length, ln, + loadacm, loadfont, loadkmap, logger, logname, ls, lsmod, + makedevs, mkdir, mkfifo, mkfs.minix, mknod, mkswap, mktemp, + more, mount, mt, mv, nc, nslookup, ping, poweroff, printf, ps, + pwd, reboot, renice, reset, rm, rmdir, rmmod, sed, setkeycodes, sh, sleep, + sort, swapoff, swapon, sync, syslogd, tail, tar, tee, telnet, + test, touch, tr, true, tty, umount, uname, uniq, update, + uptime, usleep, uudecode, uuencode, wc, which, whoami, yes, + zcat, [ + + + + + ar + + + Usage: ar [OPTION] archive [FILENAME]... + + + + Extract or list files from an ar archive. + + + + Options: + + + + + o Preserve original dates + p Extract to stdout + t List + x Extract + v Verbosely list files processed + + + + + + basename + + Usage: basename FILE [SUFFIX] + + + + Strip directory path and suffixes from FILE. If specified, also removes + any trailing SUFFIX. + + + + Example: + + + + + $ basename /usr/local/bin/foo + foo + $ basename /usr/local/bin/ + bin + $ basename /foo/bar.txt .txt + bar + + + + + + cat + + + Usage: cat [FILE]... + + + + Concatenate FILE(s) and prints them to the standard + output. + + + + Example: + + + + + $ cat /proc/uptime + 110716.72 17.67 + + + + + + chgrp + + + Usage: chgrp [OPTION]... GROUP FILE... + + + + Change the group membership of each FILE to GROUP. + + + + Options: + + + + + -R Change files and directories recursively + + + + + Example: + + + + + $ ls -l /tmp/foo + -r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo + $ chgrp root /tmp/foo + $ ls -l /tmp/foo + -r--r--r-- 1 andersen root 0 Apr 12 18:25 /tmp/foo + + + + + + chmod + + + Usage: chmod [-R] MODE[,MODE]... FILE... + + + + Change file access permissions for the specified + FILE(s) (or directories). Each MODE is defined by + combining the letters for WHO has access to the file, an OPERATOR for + selecting how the permissions should be changed, and a PERMISSION for + FILE(s) (or directories). + + + + WHO may be chosen from + + + + + u User who owns the file + g Users in the file's Group + o Other users not in the file's group + a All users + + + + + OPERATOR may be chosen from + + + + + + Add a permission + - Remove a permission + = Assign a permission + + + + + PERMISSION may be chosen from + + + + + r Read + w Write + x Execute (or access for directories) + s Set user (or group) ID bit + t Sticky bit (for directories prevents removing files by non-owners) + + + + + Alternately, permissions can be set numerically where the first three + numbers are calculated by adding the octal values, such as + + + + + 4 Read + 2 Write + 1 Execute + + + + + An optional fourth digit can also be used to specify + + + + + 4 Set user ID + 2 Set group ID + 1 Sticky bit + + + + + Options: + + + + + -R Change files and directories recursively. + + + + + Example: + + + + + $ ls -l /tmp/foo + -rw-rw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo + $ chmod u+x /tmp/foo + $ ls -l /tmp/foo + -rwxrw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo* + $ chmod 444 /tmp/foo + $ ls -l /tmp/foo + -r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo + + + + + + chown + + Usage: chown [OPTION]... OWNER[<.|:>[GROUP] FILE... + + + + Change the owner and/or group of each FILE to OWNER and/or GROUP. + + + + Options: + + + + + -R Change files and directories recursively + + + + + Example: + + + + + $ ls -l /tmp/foo + -r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo + $ chown root /tmp/foo + $ ls -l /tmp/foo + -r--r--r-- 1 root andersen 0 Apr 12 18:25 /tmp/foo + $ chown root.root /tmp/foo + ls -l /tmp/foo + -r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo + + + + + + chroot + + Usage: chroot NEWROOT [COMMAND...] + + + + Run COMMAND with root directory set to NEWROOT. + + + + Example: + + + + + $ ls -l /bin/ls + lrwxrwxrwx 1 root root 12 Apr 13 00:46 /bin/ls -> /BusyBox + $ mount /dev/hdc1 /mnt -t minix + $ chroot /mnt + $ ls -l /bin/ls + -rwxr-xr-x 1 root root 40816 Feb 5 07:45 /bin/ls* + + + + + + chvt + + Usage: chvt N + + + + Change the foreground virtual terminal to /dev/ttyN + + + + + clear + + + Usage: clear + + + + Clear the screen. + + + + + cp + + + Usage: cp [OPTION]... SOURCE DEST + + + + + or: cp [OPTION]... SOURCE... DIRECTORY + + + + + Copy SOURCE to DEST, or multiple SOURCE(s) to + DIRECTORY. + + + + Options: + + + + + -a Same as -dpR + -d Preserve links + -p Preserve file attributes if possible + -R Copy directories recursively + + + + + + cut + + + Usage: cut [OPTION]... [FILE]... + + + + Print selected fields from each input FILE to standard output. + + + + Options: + + + + + -b LIST Output only bytes from LIST + -c LIST Output only characters from LIST + -d CHAR Use CHAR instead of tab as the field delimiter + -s Output only the lines containing delimiter + -f N Print only these fields + -n Ignored + + + + + Example: + + + + + $ echo "Hello world" | cut -f 1 -d ' ' + Hello + $ echo "Hello world" | cut -f 2 -d ' ' + world + + + + + + date + + + Usage: date [OPTION]... [+FORMAT] + + + + + or: date [OPTION] [MMDDhhmm[[CC]YY][.ss]] + + + + + Display the current time in the given FORMAT, or set the system date. + + + + Options: + + + + + -R Output RFC-822 compliant date string + -s Set time described by STRING + -u Print or set Coordinated Universal Time + + + + + Example: + + + + + $ date + Wed Apr 12 18:52:41 MDT 2000 + + + + + + dc + + + Usage: dc [EXPRESSION] + + + + This is a Tiny RPN calculator that understands the + following operations: +, -, /, *, and, or, not, eor. If + no arguments are given, dc will process input from + stdin. + + + + The behaviour of BusyBox/dc deviates (just a little ;-) + from GNU/dc, but this will be remedied in the future. + + + + Example: + + + + + $ dc 2 2 + + 4 + $ dc 8 8 \* 2 2 + / + 16 + $ dc 0 1 and + 0 + $ dc 0 1 or + 1 + $ echo 72 9 div 8 mul | dc + 64 + + + + + + dd + + + Usage: dd [OPTION]... + + + + Copy a file, converting and formatting according to + options. + + + + Options: + + + + + if=FILE Read from FILE instead of stdin + of=FILE Write to FILE instead of stdout + bs=N Read and write N bytes at a time + count=N Copy only N input blocks + skip=N Skip N input blocks + seek=N Skip N output blocks + + + + + Numbers may be suffixed by w (x2), k (x1024), b (x512), + or M (x1024^2). + + + + Example: + + + + + $ dd if=/dev/zero of=/dev/ram1 bs=1M count=4 + 4+0 records in + 4+0 records out + + + + + + deallocvt + + + Usage: deallocvt N + + + + Deallocate unused virtual terminal /dev/ttyN. + + + + + df + + + Usage: df [FILE]... + + + + Print the filesystem space used and space available. + + + + Example: + + + + + $ df + Filesystem 1k-blocks Used Available Use% Mounted on + /dev/sda3 8690864 8553540 137324 98% / + /dev/sda1 64216 36364 27852 57% /boot + $ df /dev/sda3 + Filesystem 1k-blocks Used Available Use% Mounted on + /dev/sda3 8690864 8553540 137324 98% / + + + + + + dirname + + + Usage: dirname NAME + + + + Strip non-directory suffix from NAME. + + + + Example: + + + + + $ dirname /tmp/foo + /tmp + $ dirname /tmp/foo/ + /tmp + + + + + + dmesg + + + Usage: dmesg [OPTION]... + + + + Print or control the kernel ring buffer. + + + + Options: + + + + + -c Clear the ring buffer after printing + -n LEVEL Set the console logging level to LEVEL + -s BUFSIZE Query ring buffer using a buffer of BUFSIZE + + + + + + dos2unix + + + Usage: dos2unix < dosfile > unixfile + + + + Converts a text file from dos format to unix format. + + + + + + dpkg-deb + + + Usage: dpkg-deb [OPTION] archive [directory] + + + + Debian package archive (.deb) manipulation tool + + + + Options: + + + + + -c List the contents of the filesystem tree archive portion of the package + -e Extracts the control information files from a package archive into the specified directory. + If no directory is specified then a subdirectory DEBIAN in the current directory is used. + -x Silently extracts the filesystem tree from a package archive into the specified directory. + -X Extracts the filesystem tree from a package archive into the specified directory, listing the files as it goes. + If required the specified directory (but not its parents) will be created. + + + + + Example: + + + + + dpkg-deb -e ./busybox_0.48-1_i386.deb + dpkg-deb -x ./busybox_0.48-1_i386.deb ./unpack_dir + + + + + + du + + + Usage: du [OPTION]... [FILE]... + + + + Summarize the disk space used for each FILE or current + directory. Disk space printed in units of 1k (i.e., + 1024 bytes). + + + + Options: + + + + + -l Count sizes many times if hard linked + -s Display only a total for each argument + + + + + Example: + + + + + $ du + 16 ./CVS + 12 ./kernel-patches/CVS + 80 ./kernel-patches + 12 ./tests/CVS + 36 ./tests + 12 ./scripts/CVS + 16 ./scripts + 12 ./docs/CVS + 104 ./docs + 2417 . + + + + + + dumpkmap + + + Usage: dumpkmap + + + + Prints out a binary keyboard translation table to standard output. + + + + Example: + + + + + $ dumpkmap < keymap + + + + + + dutmp + + + Usage: dutmp [FILE] + + + + Dump utmp file format (pipe delimited) from FILE or + stdin to stdout. + + + + Example: + + + + + $ dutmp /var/run/utmp + 8|7||si|||0|0|0|955637625|760097|0 + 2|0|~|~~|reboot||0|0|0|955637625|782235|0 + 1|20020|~|~~|runlevel||0|0|0|955637625|800089|0 + 8|125||l4|||0|0|0|955637629|998367|0 + 6|245|tty1|1|LOGIN||0|0|0|955637630|998974|0 + 6|246|tty2|2|LOGIN||0|0|0|955637630|999498|0 + 7|336|pts/0|vt00andersen|andersen|:0.0|0|0|0|955637763|0|0 + + + + + + echo + + + Usage: echo [OPTION]... [ARG]... + + + + Print ARGs to stdout. + + + + Options: + + + + + -n Suppress trailing newline + -e Enable interpretation of escaped characters + -E Disable interpretation of escaped characters + + + + + Example: + + + + + $ echo "Erik is cool" + Erik is cool + $ echo -e "Erik\nis\ncool" + Erik + is + cool + $ echo "Erik\nis\ncool" + Erik\nis\ncool + + + + + + expr + + + Usage: expr EXPRESSION + + + + Prints the value of EXPRESSION to standard output. + + + + EXPRESSION may be: + + + + + ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2 + ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0 + ARG1 < ARG2 ARG1 is less than ARG2 + ARG1 <= ARG2 ARG1 is less than or equal to ARG2 + ARG1 = ARG2 ARG1 is equal to ARG2 + ARG1 != ARG2 ARG1 is unequal to ARG2 + ARG1 >= ARG2 ARG1 is greater than or equal to ARG2 + ARG1 > ARG2 ARG1 is greater than ARG2 + ARG1 + ARG2 arithmetic sum of ARG1 and ARG2 + ARG1 - ARG2 arithmetic difference of ARG1 and ARG2 + ARG1 * ARG2 arithmetic product of ARG1 and ARG2 + ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2 + ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2 + STRING : REGEXP anchored pattern match of REGEXP in STRING + match STRING REGEXP same as STRING : REGEXP + substr STRING POS LENGTH substring of STRING, POS counted from 1 + index STRING CHARS index in STRING where any CHARS is found, or 0 + length STRING length of STRING + quote TOKEN interpret TOKEN as a string, even if it is a + keyword like `match' or an operator like `/' + ( EXPRESSION ) value of EXPRESSION + + + + + Beware that many operators need to be escaped or quoted for shells. + Comparisons are arithmetic if both ARGs are numbers, else + lexicographical. Pattern matches return the string matched between + \( and \) or null; if \( and \) are not used, they return the number + of characters matched or 0. + + + + + + + false + + + Usage: false + + + + Return an exit code of FALSE (1). + + + + Example: + + + + + $ false + $ echo $? + 1 + + + + + + fbset + + + Usage: fbset [OPTION]... [MODE] + + + + Show and modify frame buffer device settings. + + + + Options: + + + + + -h Display option summary + -fb DEVICE Operate on DEVICE + -db FILE Use FILE for mode database + -g XRES YRES VXRES VYRES DEPTH Set all geometry parameters + -t PIXCLOCK LEFT RIGHT UPPER LOWER HSLEN VSLEN Set all timing parameters + -xres RES Set visible horizontal resolution + -yres RES Set visible vertical resolution + + + + + Example: + + + + + $ fbset + mode "1024x768-76" + # D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz + geometry 1024 768 1024 768 16 + timings 12714 128 32 16 4 128 4 + accel false + rgba 5/11,6/5,5/0,0/0 + endmode + + + + + + fdflush + + + Usage: fdflush DEVICE + + + + Force floppy disk drive to detect disk change on DEVICE. + + + + + find + + + Usage: find [PATH]... [EXPRESSION] + + + + Search for files in a directory hierarchy. The default + PATH is the current directory; default EXPRESSION is + '-print'. + + + + EXPRESSION may consist of: + + + + + -follow Dereference symbolic links + -name PATTERN File name (leading directories removed) matches PATTERN + -type X Filetype matches X (where X is one of: f,d,l,b,c,...) + -perm PERMS Permissions match any of (+NNN); all of (-NNN); or exactly (NNN) + -mtime TIME Modified time is greater than (+N); less than (-N); or exactly (N) days + + + + + Example: + + + + + $ find / -name /etc/passwd + /etc/passwd + + + + + + free + + + Usage: free + + + + Displays the amount of free and used system memory. + + + + Example: + + + + + $ free + total used free shared buffers + Mem: 257628 248724 8904 59644 93124 + Swap: 128516 8404 120112 + Total: 386144 257128 129016 + + + + + + freeramdisk + + + Usage: freeramdisk DEVICE + + + + Free all memory used by the ramdisk DEVICE. + + + + Example: + + + + + $ freeramdisk /dev/ram2 + + + + + + fsck.minix + + + Usage: fsck.minix [OPTION]... DEVICE + + + + Perform a consistency check on the MINIX filesystem on + DEVICE. + + + + Options: + + + + + -l List all filenames + -r Perform interactive repairs + -a Perform automatic repairs + -v Verbose + -s Output super-block information + -m Activate MINIX-like "mode not cleared" warnings + -f Force file system check. + + + + + + getopt + + + Usage: getopt [OPTIONS]... + + + + Parse command options + + + + + -a, --alternative Allow long options starting with single -\n" + -l, --longoptions=longopts Long options to be recognized\n" + -n, --name=progname The name under which errors are reported\n" + -o, --options=optstring Short options to be recognized\n" + -q, --quiet Disable error reporting by getopt(3)\n" + -Q, --quiet-output No normal output\n" + -s, --shell=shell Set shell quoting conventions\n" + -T, --test Test for getopt(1) version\n" + -u, --unqote Do not quote the output\n" + + + + + + Example: + + + + + $ cat getopt.test + #!/bin/sh + GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \ + -n 'example.busybox' -- "$@"` + if [ $? != 0 ] ; then exit 1 ; fi + eval set -- "$GETOPT" + while true ; do + case $1 in + -a|--a-long) echo "Option a" ; shift ;; + -b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;; + -c|--c-long) + case "$2" in + "") echo "Option c, no argument"; shift 2 ;; + *) echo "Option c, argument \`$2'" ; shift 2 ;; + esac ;; + --) shift ; break ;; + *) echo "Internal error!" ; exit 1 ;; + esac + done + + + + + + grep + + + Usage: grep [OPTIONS]... PATTERN [FILE]... + + + + Search for PATTERN in each FILE or stdin. + + + + Options: + + + + + -h Suppress the prefixing filename on output + -i Ignore case distinctions + -n Print line number with output lines + -q Be quiet. Returns 0 if result was found, 1 otherwise + -v Select non-matching lines + + + + + This version of grep matches full regular expressions. + + + + Example: + + + + + $ grep root /etc/passwd + root:x:0:0:root:/root:/bin/bash + $ grep ^[rR]oo. /etc/passwd + root:x:0:0:root:/root:/bin/bash + + + + + + gunzip + + + Usage: gunzip [OPTION]... FILE + + + + Uncompress FILE (or stdin if FILE is '-'). + + + + Options: + + + + + -c Write output to standard output + -t Test compressed file integrity + + + + + Example: + + + + + $ ls -la /tmp/BusyBox* + -rw-rw-r-- 1 andersen andersen 557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz + $ gunzip /tmp/BusyBox-0.43.tar.gz + $ ls -la /tmp/BusyBox* + -rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar + + + + + + gzip + + + Usage: gzip [OPTION]... FILE + + + + Compress FILE (or stdin if FILE is '-') with maximum + compression to FILE.gz (or stdout if FILE is '-'). + + + + Options: + + + + + -c Write output to standard output + -d decompress + + + + + Example: + + + + + $ ls -la /tmp/BusyBox* + -rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar + $ gzip /tmp/BusyBox-0.43.tar + $ ls -la /tmp/BusyBox* + -rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/BusyBox-0.43.tar.gz + + + + + + halt + + + Usage: halt + + + + Halt the system. + + + + + head + + + Usage: head [OPTION] FILE... + + + + Print first 10 lines of each FILE to standard output. + With more than one FILE, precede each with a header + giving the file name. With no FILE, or when FILE is -, + read standard input. + + + + Options: + + + + + -n NUM Print first NUM lines instead of first 10 + + + + + Example: + + + + + $ head -n 2 /etc/passwd + root:x:0:0:root:/root:/bin/bash + daemon:x:1:1:daemon:/usr/sbin:/bin/sh + + + + + + hostid + + + Usage: hostid + + + + Prints out a unique 32-bit identifier for the current + machine. The 32-bit identifier is intended to be unique + among all UNIX systems in existence. + + + + + hostname + + + Usage: hostname [OPTION]... [HOSTNAME|-F FILE] + + + + Get or set the hostname or DNS domain name. If a + hostname is given (or a file with the -F parameter), the + host name will be set. + + + + Options: + + + + + -s Short + -i Addresses for the hostname + -d DNS domain name + -F, --file FILE Use the contents of FILE to specify the hostname + + + + + Example: + + + + + $ hostname + slag + + + + + + id + + + Usage: id [OPTION]... [USERNAME] + + + + Print information for USERNAME or the current user. + + + + Options: + + + + + -g Print only the group ID + -u Print only the user ID + -n print a name instead of a number (with for -ug) + -r Print the real user ID instead of the effective ID (with -ug) + + + + + Example: + + + + + $ id + uid=1000(andersen) gid=1000(andersen) + + + + + + init + + + Usage: init + + + + Init is the parent of all processes. + + + + This version of init is designed to be run only by the + kernel. + + + + BusyBox init doesn't support multiple runlevels. The + runlevels field of the /etc/inittab file is completely + ignored by BusyBox init. If you want runlevels, use + sysvinit. + + + + BusyBox init works just fine without an inittab. If no + inittab is found, it has the following default behavior: + + + + + ::sysinit:/etc/init.d/rcS + ::askfirst:/bin/sh + + + + + If it detects that /dev/console is _not_ a serial + console, it will also run: + + + + + tty2::askfirst:/bin/sh + + + + + If you choose to use an /etc/inittab file, the inittab + entry format is as follows: + + + + + <id>:<runlevels>:<action>:<process> + + + + + id + + + WARNING: This field has a non-traditional meaning for BusyBox init! + The id field is used by BusyBox init to specify the controlling tty + for the specified process to run on. The contents of this field + are appended to "/dev/" and used as-is. There is no need for this + field to be unique, although if it isn't you may have strange + results. If this field is left blank, the controlling tty is set + to the console. Also note that if BusyBox detects that a serial + console is in use, then only entries whose controlling tty is + either the serial console or /dev/null will be run. BusyBox init + does nothing with utmp. We don't need no stinkin' utmp. + + + + + + runlevels + + + The runlevels field is completely ignored. + + + + + action + + + + Valid actions include: sysinit, respawn, askfirst, wait, + once, and ctrlaltdel. + + + + + The available actions can be classified into two groups: actions + that are run only once, and actions that are re-run when the specified + process exits. + + + + Run only-once actions: + + + + 'sysinit' is the first item run on boot. init waits until all + sysinit actions are completed before continuing. Following the + completion of all sysinit actions, all 'wait' actions are run. + 'wait' actions, like 'sysinit' actions, cause init to wait until + the specified task completes. 'once' actions are asyncronous, + therefore, init does not wait for them to complete. 'ctrlaltdel' + actions are run immediately before init causes the system to reboot + (unmounting filesystems with a 'ctrlaltdel' action is a very good + idea). + + + + Run repeatedly actions: + + + + 'respawn' actions are run after the 'once' actions. When a process + started with a 'respawn' action exits, init automatically restarts + it. Unlike sysvinit, BusyBox init does not stop processes from + respawning out of control. The 'askfirst' actions acts just like + respawn, except that before running the specified process it + displays the line "Please press Enter to activate this console." + and then waits for the user to press enter before starting the + specified process. + + + + Unrecognized actions (like initdefault) will cause init to emit an + error message, and then go along with its business. All actions are + run in the reverse order from how they appear in /etc/inittab. + + + + + + process + + + Specifies the process to be executed and its + command line. + + + + + Example /etc/inittab file + + + + # This is run first except when booting in single-user mode. + # + ::sysinit:/etc/init.d/rcS + + # /bin/sh invocations on selected ttys + # + # Start an "askfirst" shell on the console (whatever that may be) + ::askfirst:-/bin/sh + # Start an "askfirst" shell on /dev/tty2-4 + tty2::askfirst:-/bin/sh + tty2::askfirst:-/bin/sh + tty2::askfirst:-/bin/sh + + # /sbin/getty invocations for selected ttys + # + tty4::respawn:/sbin/getty 38400 tty5 + tty5::respawn:/sbin/getty 38400 tty6 + + # Example of how to put a getty on a serial line (for a terminal) + # + #::respawn:/sbin/getty -L ttyS0 9600 vt100 + #::respawn:/sbin/getty -L ttyS1 9600 vt100 + # + # Example how to put a getty on a modem line. + #::respawn:/sbin/getty 57600 ttyS2 + + # Stuff to do before rebooting + ::ctrlaltdel:/bin/umount -a -r + ::ctrlaltdel:/sbin/swapoff + + + + + + + insmod + + + Usage: insmod [OPTION]... MODULE [symbol=value]... + + + + Load MODULE into the kernel. + + + + Options: + + + + + -f Force module to load into the wrong kernel version. + -k Make module autoclean-able. + -v Verbose output + -x Do not export externs + -L Prevent simultaneous loads of the same module + + + + + + kill + + + Usage: kill [OPTION] PID... + + + + Send a signal (default is SIGTERM) to the specified + PID(s). + + + + Options: + + + + + -l List all signal names and numbers + -SIG Send signal SIG + + + + + Example: + + + + + $ ps | grep apache + 252 root root S [apache] + 263 www-data www-data S [apache] + 264 www-data www-data S [apache] + 265 www-data www-data S [apache] + 266 www-data www-data S [apache] + 267 www-data www-data S [apache] + $ kill 252 + + + + + + killall + + + Usage: killall [OPTION] NAME... + + + + Send a signal (default is SIGTERM) to the specified + NAME(s). + + + + Options: + + + + + -l List all signal names and numbers + -SIG Send signal SIG + + + + + Example: + + + + + $ killall apache + + + + + + length + + + Usage: length STRING + + + + Print the length of STRING. + + + + Example: + + + + + $ length "Hello" + 5 + + + + + + ln + + + Usage: ln [OPTION]... TARGET FILE|DIRECTORY + + + + Create a link named FILE or DIRECTORY to the specified + TARGET. You may use '--' to indicate that all following + arguments are non-options. + + + + Options: + + + + + -s Make symbolic link instead of hard link + -f Remove existing destination file + + + + + Example: + + + + + $ ln -s BusyBox /tmp/ls + $ ls -l /tmp/ls + lrwxrwxrwx 1 root root 7 Apr 12 18:39 ls -> BusyBox* + + + + + + loadacm + + + Usage: loadacm + + + + Load an acm from stdin. + + + + Example: + + + + + $ loadacm < /etc/i18n/acmname + + + + + + loadfont + + + Usage: loadfont + + + + Load a console font from stdin. + + + + Example: + + + + + $ loadfont < /etc/i18n/fontname + + + + + + loadkmap + + + Usage: loadkmap + + + + Load a binary keyboard translation table from stdin. + + + + Example: + + + + + $ loadkmap < /etc/i18n/lang-keymap + + + + + + logger + + + Usage: logger [OPTION]... [MESSAGE] + + + + Write MESSAGE to the system log. If MESSAGE is omitted, log + stdin. + + + + Options: + + + + + -s Log to stderr as well as the system log + -t Log using the specified tag (defaults to user name) + -p Enter the message with the specified priority + This may be numerical or a ``facility.level'' pair + + + + + Example: + + + + + $ logger "hello" + + + + + + logname + + + Usage: logname + + + + Print the name of the current user. + + + + Example: + + + + + $ logname + root + + + + + + ls + + + Usage: ls [OPTION]... [FILE]... + + + + + + + + Options: + + + + + -a Do not hide entries starting with . + -c With -l: show ctime (the time of last + modification of file status information) + -d List directory entries instead of contents + -e List both full date and full time + -l Use a long listing format + -n List numeric UIDs and GIDs instead of names + -p Append indicator (one of /=@|) to entries + -u With -l: show access time (the time of last + access of the file) + -x List entries by lines instead of by columns + -A Do not list implied . and .. + -C List entries by columns + -F Append indicator (one of */=@|) to entries + -L list entries pointed to by symbolic links + -R List subdirectories recursively + + + + + Example: + + + + + + + + + + lsmod + + + Usage: lsmod + + + + List currently loaded kernel modules. + + + + + makedevs + + + Usage: makedevsf NAME TYPE MAJOR MINOR FIRST LAST [s] + + + + Create a range of block or character special files. + + + + TYPE may be: + + + + + b Make a block (buffered) device + c or u Make a character (un-buffered) device + p Make a named pipe. MAJOR and MINOR are ignored for named pipes + + + + + FIRST specifies the number appended to NAME to create + the first device. LAST specifies the number of the last + item that should be created. If 's' is the last + argument, the base device is created as well. + + + + Example: + + + + + $ makedevs /dev/ttyS c 4 66 2 63 + [creates ttyS2-ttyS63] + $ makedevs /dev/hda b 3 0 0 8 s + [creates hda,hda1-hda8] + + + + + + md5sum + + + Usage: md5sum [OPTION]... FILE... + + + + Print or check MD5 checksums. + + + + Options: + + + + + -b Read files in binary mode + -c Check MD5 sums against given list + -t Read files in text mode (default) + -g Read a string + + + + + The following two options are useful only when verifying + checksums: + + + + + -s Don't output anything, status code shows success + -w Warn about improperly formated MD5 checksum lines + + + + + Example: + + + + + $ md5sum busybox + 6fd11e98b98a58f64ff3398d7b324003 busybox + $ md5sum -c + 6fd11e98b98a58f64ff3398d7b324003 busybox + 6fd11e98b98a58f64ff3398d7b324002 busybox + md5sum: MD5 check failed for 'busybox' + ^D + + + + + + mkdir + + + Usage: mkdir [OPTION]... DIRECTORY... + + + + Create the DIRECTORY(s), if they do not already exist. + + + + Options: + + + + + -m Set permission mode (as in chmod), not rwxrwxrwx - umask + -p No error if directory exists, make parent directories as needed + + + + + Example: + + + + + $ mkdir /tmp/foo + $ mkdir /tmp/foo + /tmp/foo: File exists + $ mkdir /tmp/foo/bar/baz + /tmp/foo/bar/baz: No such file or directory + $ mkdir -p /tmp/foo/bar/baz + + + + + + mkfifo + + + Usage: mkfifo [OPTION] NAME + + + + Create a named pipe (identical to 'mknod NAME p'). + + + + Options: + + + + + -m MODE Create the pipe using the specified mode (default a=rw) + + + + + + mkfs.minix + + + Usage: mkfs.minix [OPTION]... NAME [BLOCKS] + + + + Make a MINIX filesystem. + + + + Options: + + + + + -c Check the device for bad blocks + -n [14|30] Specify the maximum length of filenames + -i Specify the number of inodes for the filesystem + -l FILENAME Read the bad blocks list from FILENAME + -v Make a Minix version 2 filesystem + + + + + + mknod + + + Usage: mknod [OPTION]... NAME TYPE MAJOR MINOR + + + + Create a special file (block, character, or pipe). + + + + Options: + + + + + -m Create the special file using the specified mode (default a=rw) + + + + + TYPE may be: + + + + + b Make a block (buffered) device + c or u Make a character (un-buffered) device + p Make a named pipe. MAJOR and MINOR are ignored for named pipes + + + + + Example: + + + + + $ mknod /dev/fd0 b 2 0 + $ mknod -m 644 /tmp/pipe p + + + + + + mkswap + + + Usage: mkswap [OPTION]... DEVICE [BLOCKS] + + + + Prepare a disk partition to be used as a swap partition. + + + + Options: + + + + + -c Check for read-ability. + -v0 Make version 0 swap [max 128 Megs]. + -v1 Make version 1 swap [big!] (default for kernels > 2.1.117). + BLOCKS Number of block to use (default is entire partition). + + + + + + mktemp + + + Usage: mktemp TEMPLATE + + + + Creates a temporary file with its name based on + TEMPLATE. TEMPLATE is any name with six `Xs' (i.e., + /tmp/temp.XXXXXX). + + + + Example: + + + + + $ mktemp /tmp/temp.XXXXXX + /tmp/temp.mWiLjM + $ ls -la /tmp/temp.mWiLjM + -rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM + + + + + + more + + + Usage: more [FILE]... + + + + Page through text one screenful at a time. + + + + Example: + + + + + $ dmesg | more + + + + + + mount + + + Usage: mount [OPTION]... + + + + + or: mount [OPTION]... DEVICE DIRECTORY + + + + + Mount filesystems. + + + + Options: + + + + + -a Mount all filesystems in /etc/fstab + -o One of the many filesystem options listed below + -r Mount the filesystem read-only + -t TYPE Specify the filesystem type + -w Mount the filesystem read-write + + + + + Options for use with the -o flag: + + + + + async/sync Writes are asynchronous / synchronous + atime/noatime Enable / disable updates to inode access times + dev/nodev Allow / disallow use of special device files + exec/noexec Allow / disallow use of executable files + loop Mount a file via loop device + suid/nosuid Allow / disallow set-user-id-root programs + remount Remount a currently mounted filesystem + ro/rw Mount filesystem read-only / read-write + + + + + There are even more flags that are filesystem specific. + You'll have to see the written documentation for those. + + + + Example: + + + + + $ mount + /dev/hda3 on / type minix (rw) + proc on /proc type proc (rw) + devpts on /dev/pts type devpts (rw) + $ mount /dev/fd0 /mnt -t msdos -o ro + $ mount /tmp/diskimage /opt -t ext2 -o loop + + + + + + mt + + + Usage: mt [OPTION] OPCODE VALUE + + + + Control magnetic tape drive operation. + + + + Options: + + + + + -f DEVICE Control DEVICE + + + + + + mv + + + Usage: mv SOURCE DEST + + + + + or: mv SOURCE... DIRECTORY + + + + + Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY. + + + + Example: + + + + + $ mv /tmp/foo /bin/bar + + + + + + nc + + + Usage: nc HOST PORT + + + + or: nc -p PORT -l + + + + + Open a pipe to HOST:PORT or listen for a connection on PORT. + + + + Example: + + + + + $ nc foobar.somedomain.com 25 + 220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600 + help + 214-Commands supported: + 214- HELO EHLO MAIL RCPT DATA AUTH + 214 NOOP QUIT RSET HELP + quit + 221 foobar closing connection + + + + + + nslookup + + + Usage: nslookup [HOST] + + + + Query the nameserver for the IP address of the given + HOST. + + + + Example: + + + + + $ nslookup localhost + Server: default + Address: default + + Name: debian + Address: 127.0.0.1 + + + + + + ping + + + Usage: ping [OPTION]... HOST + + + + Send ICMP ECHO_REQUEST packets to HOST. + + + + Options: + + + + + -c COUNT Send only COUNT pings + -s SIZE Send SIZE data bytes in packets (default=56) + -q Quiet mode, only displays output at start and when finished + + + + + Example: + + + + + $ ping localhost + PING slag (127.0.0.1): 56 data bytes + 64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms + + --- debian ping statistics --- + 1 packets transmitted, 1 packets received, 0% packet loss + round-trip min/avg/max = 20.1/20.1/20.1 ms + + + + + + poweroff + + + Usage: poweroff + + + + Shut down the system, and request that the kernel turn + off power upon halting. + + + + + printf + + + Usage: printf FORMAT [ARGUMENT]... + + + + Format and print the given data in a manner similar to + the C printf command. + + + + Example: + + + + + $ printf "Val=%d\n" 5 + Val=5 + + + + + + ps + + + Usage: ps + + + + Report process status. This version of ps accepts no + options. + + + + Options: + + + + + + + + + Example: + + + + + $ ps + PID Uid Gid State Command + 1 root root S init + 2 root root S [kflushd] + 3 root root S [kupdate] + 4 root root S [kpiod] + 5 root root S [kswapd] + 742 andersen andersen S [bash] + 743 andersen andersen S -bash + 745 root root S [getty] + 2990 andersen andersen R ps + + + + + + pwd + + + Usage: pwd + + + + Print the full filename of the current working + directory. + + + + Example: + + + + + $ pwd + /root + + + + + + rdate + + + Usage: rdate [OPTION] HOST + + + + Get and possibly set the system date and time from a remote HOST. + + + + Options: + + + + + -s Set the system date and time (default). + -p Print the date and time. + + + + + + reboot + + + Usage: reboot + + + + Reboot the system. + + + + + renice + + + Usage: renice priority pid [pid ...] + + + + Changes priority of running processes. Allowed priorities range + from 20 (the process runs only when nothing else is running) to 0 + (default priority) to -20 (almost nothing else ever gets to run). + + + + + reset + + + Usage: reset + + + + Resets the screen. + + + + + rm + + + Usage: rm [OPTION]... FILE... + + + + Remove (unlink) the FILE(s). You may use '--' to + indicate that all following arguments are non-options. + + + + Options: + + + + + -i Always prompt before removing each destinations + -f Remove existing destinations, never prompt + -r or -R Remove the contents of directories recursively + + + + + Example: + + + + + $ rm -rf /tmp/foo + + + + + + rmdir + + + Usage: rmdir DIRECTORY... + + + + Remove DIRECTORY(s) if they are empty. + + + + Example: + + + + + $ rmdir /tmp/foo + + + + + + rmmod + + + Usage: rmmod [OPTION]... [MODULE]... + + + + Unload MODULE(s) from the kernel. + + + + Options: + + + + + -a Try to remove all unused kernel modules + + + + + Example: + + + + + $ rmmod tulip + + + + + + sed + + + Usage: sed [OPTION]... SCRIPT [FILE]... + + + + Allowed sed scripts come in the following form: + + + + + ADDR [!] COMMAND + + + + + ADDR can be: + + + + + NUMBER Match specified line number + $ Match last line + /REGEXP/ Match specified regexp + + + + + ! inverts the meaning of the match + + + + COMMAND can be: + + + + + s/regexp/replacement/[igp] + which attempt to match regexp against the pattern space + and if successful replaces the matched portion with replacement. + aTEXT + which appends TEXT after the pattern space + + + + + This version of sed matches full regular expressions. + + + + Options: + + + + + -e Add the script to the commands to be executed + -n Suppress automatic printing of pattern space + + + + + Example: + + + + + $ echo "foo" | sed -e 's/f[a-zA-Z]o/bar/g' + bar + + + + + + setkeycodes + + + Usage: setkeycodes SCANCODE KEYCODE ... + + + + Set entries into the kernel's scancode-to-keycode map, + allowing unusual keyboards to generate usable keycodes. + + + + SCANCODE may be either xx or e0xx (hexadecimal), and + KEYCODE is given in decimal. + + + + Example: + + + + + $ setkeycodes e030 127 + + + + + + + sh + + + Usage: sh + + + + lash -- the BusyBox LAme SHell (command interpreter) + + + + This command does not yet have proper documentation. + + + + Use lash just as you would use any other shell. It + properly handles pipes, redirects, job control, can be + used as the shell for scripts (#!/bin/sh), and has a + sufficient set of builtins to do what is needed. It does + not (yet) support Bourne Shell syntax. If you need + things like ``if-then-else'', ``while'', and such, use + ash or bash. If you just need a very simple and + extremely small shell, this will do the job. + + + + + sleep + + + Usage: sleep N + + + + Pause for N seconds. + + + + Example: + + + + + $ sleep 2 + [2 second delay results] + + + + + + sort + + + Usage: sort [OPTION]... [FILE]... + + + + Sort lines of text in FILE(s). + + + + Options: + + + + + -n Compare numerically + -r Reverse after sorting + + + + + Example: + + + + + $ echo -e "e\nf\nb\nd\nc\na" | sort + a + b + c + d + e + f + + + + + + swapoff + + + Usage: swapoff [OPTION] [DEVICE] + + + + Stop swapping virtual memory pages on DEVICE. + + + + Options: + + + + + -a Stop swapping on all swap devices + + + + + + swapon + + + Usage: swapon [OPTION] [DEVICE] + + + + Start swapping virtual memory pages on the given device. + + + + Options: + + + + + -a Start swapping on all swap devices + + + + + + sync + + + Usage: sync + + + + Write all buffered filesystem blocks to disk. + + + + + syslogd + + + Usage: syslogd [OPTION]... + + + + Linux system and kernel (provides klogd) logging + utility. Note that this version of syslogd/klogd ignores + /etc/syslog.conf. + + + + Options: + + + + + -m NUM Interval between MARK lines (default=20min, 0=off) + -n Run as a foreground process + -K Do not start up the klogd process + -O FILE Use an alternate log file (default=/var/log/messages) + -R HOST[:PORT] Log remotely to IP or hostname on PORT (default PORT=514/UDP) + -L Log locally as well as network logging (default is network only) + + + + + Example: + + + + + $ syslogd -R masterlog:514 + $ syslogd -R 192.168.1.1:601 + + + + + + tail + + + Usage: tail [OPTION] [FILE]... + + + + Print last 10 lines of each FILE to standard output. + With more than one FILE, precede each with a header + giving the file name. With no FILE, or when FILE is -, + read stdin. + + + + Options: + + + + + -n NUM Print last NUM lines instead of last 10 + -f Output data as the file grows. This version + of 'tail -f' supports only one file at a time. + + + + + Example: + + + + + $ tail -n 1 /etc/resolv.conf + nameserver 10.0.0.1 + + + + + + tar + + + Usage: tar [MODE] [OPTION] [FILE]... + + + + + + + + MODE may be chosen from + + + + + c Create + x Extract + t List + + + + + Options: + + + + + f FILE Use FILE for tarfile (or stdin if '-') + O Extract to stdout + exclude FILE File to exclude + v List files processed + + + + + Example: + + + + + $ zcat /tmp/tarball.tar.gz | tar -xf - + $ tar -cf /tmp/tarball.tar /usr/local + + + + + + tee + + + Usage: tee [OPTION]... [FILE]... + + + + Copy stdin to FILE(s), and also to stdout. + + + + Options: + + + + + -a Append to the given FILEs, do not overwrite + + + + + Example: + + + + + $ echo "Hello" | tee /tmp/foo + Hello + $ cat /tmp/foo + Hello + + + + + + telnet + + + Usage: telnet HOST [PORT] + + + + Establish interactive communication with another + computer over a network using the TELNET protocol. + + + + + test, [ + + + Usage: test EXPRESSION + + + + or: [ EXPRESSION ] + + + + Check file types and compare values returning an exit + code determined by the value of EXPRESSION. + + + + Example: + + + + + $ test 1 -eq 2 + $ echo $? + 1 + $ test 1 -eq 1 + $ echo $? + 0 + $ [ -d /etc ] + $ echo $? + 0 + $ [ -d /junk ] + $ echo $? + 1 + + + + + + touch + + + Usage: touch [OPTION]... FILE... + + + + Update the last-modified date on (or create) FILE(s). + + + + Options: + + + + + -c Do not create files + + + + + Example: + + + + + $ ls -l /tmp/foo + /bin/ls: /tmp/foo: No such file or directory + $ touch /tmp/foo + $ ls -l /tmp/foo + -rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo + + + + + + tr + + + Usage: tr [OPTION]... STRING1 [STRING2] + + + + Translate, squeeze, and/or delete characters from stdin, + writing to stdout. + + + + Options: + + + + + -c Take complement of STRING1 + -d Delete input characters coded STRING1 + -s Squeeze multiple output characters of STRING2 into one character + + + + + Example: + + + + + $ echo "gdkkn vnqkc" | tr [a-y] [b-z] + hello world + + + + + + true + + + Usage: true + + + + Return an exit code of TRUE (1). + + + + Example: + + + + + $ true + $ echo $? + 0 + + + + + + tty + + + Usage: tty + + + + Print the file name of the terminal connected to stdin. + + + + Options: + + + + + -s Print nothing, only return an exit status + + + + + Example: + + + + + $ tty + /dev/tty2 + + + + + + umount + + + Usage: umount [OPTION]... DEVICE|DIRECTORY + + + + + + + + Options: + + + + + -a Unmount all file systems + -r Try to remount devices as read-only if mount is busy + -f Force filesystem umount (i.e., unreachable NFS server) + -l Do not free loop device (if a loop device has been used) + + + + + Example: + + + + + $ umount /dev/hdc1 + + + + + + uname + + + Usage: uname [OPTION]... + + + + Print certain system information. With no OPTION, same + as -s. + + + + Options: + + + + + -a Print all information + -m Print the machine (hardware) type + -n Print the machine's network node hostname + -r Print the operating system release + -s Print the operating system name + -p Print the host processor type + -v Print the operating system version + + + + + Example: + + + + + $ uname -a + Linux debian 2.2.15pre13 #5 Tue Mar 14 16:03:50 MST 2000 i686 unknown + + + + + + uniq + + + Usage: uniq [INPUT [OUTPUT]] + + + + Discard all but one of successive identical lines from + INPUT (or stdin), writing to OUTPUT (or stdout). + + + + Options: + + + + + -c prefix lines by the number of occurrences + -d only print duplicate lines + -u only print unique lines + + + + + Example: + + + + + $ echo -e "a\na\nb\nc\nc\na" | sort | uniq + a + b + c + + + + + + unix2dos + + + Usage: unix2dos < unixfile > dosfile + + + + Converts a text file from unix format to dos format. + + + + + + unrpm + + + Usage: unrpm < package.rpm | gzip -d | cpio -idmuv + + + + Extracts an rpm archive. + + + + + + update + + + Usage: update [OPTION]... + + + + Periodically flush filesystem buffers. + + + + Options: + + + + + -S Force use of sync(2) instead of flushing + -s SECS Call sync this often (default 30) + -f SECS Flush some buffers this often (default 5) + + + + + + uptime + + + Usage: uptime + + + + Display how long the system has been running since boot. + + + + Example: + + + + + $ uptime + 1:55pm up 2:30, load average: 0.09, 0.04, 0.00 + + + + + + usleep + + + Usage: usleep N + + + + Pause for N microseconds. + + + + Example: + + + + + $ usleep 1000000 + [pauses for 1 second] + + + + + + uudecode + + + Usage: uudecode [OPTION] [FILE] + + + + Uudecode a uuencoded file. + + + + Options: + + + + + -o FILE Direct output to FILE + + + + + Example: + + + + + $ uudecode -o busybox busybox.uu + $ ls -l busybox + -rwxr-xr-x 1 ams ams 245264 Jun 7 21:35 busybox + + + + + + uuencode + + + Usage: uuencode [OPTION] [INFILE] OUTFILE + + + + Uuencode a file. + + + + Options: + + + + + -m Use base64 encoding as of RFC1521 + + + + + Example: + + + + + $ uuencode busybox busybox + begin 755 busybox + M?T5,1@$!`0````````````(``P`!````L+@$"#0```!0N@,``````#0`(``& + ..... + $ uudecode busybox busybox > busybox.uu + $ + + + + + + watchdog + + + Usage: watchdog device + + + + Periodically writes to watchdog device B. + + + + + wc + + + Usage: wc [OPTION]... [FILE]... + + + + Print line, word, and byte counts for each FILE, and a + total line if more than one FILE is specified. With no + FILE, read stdin. + + + + Options: + + + + + -c Print the byte counts + -l Print the newline counts + -L Print the length of the longest line + -w Print the word counts + + + + + Example: + + + + + $ wc /etc/passwd + 31 46 1365 /etc/passwd + + + + + + which + + + Usage: which [COMMAND]... + + + + Locate COMMAND(s). + + + + Example: + + + + + $ which login + /bin/login + + + + + + whoami + + + Usage: whoami + + + + Print the user name associated with the current + effective user id. + + + + Example: + + + + + $ whoami + andersen + + + + + + xargs + + + Usage: xargs [OPTIONS] [COMMAND] [ARGS...] + + + + Executes COMMAND on every item given by standard input. + + + + Options: + + + + + -t Print the command just before it is run + + + + + + Example: + + + + + $ ls | xargs gzip + $ find . -name '*.c' -print | xargs rm + + + + + + yes + + + Usage: yes [STRING]... + + + + Repeatedly output a line with all specified STRING(s), + or `y'. + + + + + zcat + + + Usage: zcat [OPTION]... FILE + + + + Uncompress FILE (or stdin if FILE is '-') to stdout. + + + + Options: + + + + + -t Test compressed file integrity + + + + + Example: + + + + + + + + + + + LIBC NSS + + + GNU Libc uses the Name Service Switch (NSS) to configure the + behavior of the C library for the local environment, and to + configure how it reads system data, such as passwords and group + information. BusyBox has made it Policy that it will never use + NSS, and will never use libc calls that make use of NSS. This + allows you to run an embedded system without the need for + installing an /etc/nsswitch.conf file and without /lib/libnss_* + libraries installed. + + + + If you are using a system that is using a remote LDAP server for + authentication via GNU libc NSS, and you want to use BusyBox, + then you will need to adjust the BusyBox source. Chances are + though, that if you have enough space to install of that stuff + on your system, then you probably want the full GNU utilities. + + + + + SEE ALSO + + + textutils(1), + shellutils(1), + etc... + + + + + MAINTAINER + + + Erik Andersen <andersee@debian.org> <andersen@codepoet.org> + + + + + AUTHORS + + + The following people have made significant contributions to + BusyBox -- whether they know it or not. + + + + Erik Andersen <andersee@debian.org> + + + + Edward Betts <edward@debian.org> + + + + John Beppu <beppu@codepoet.org> + + + + Brian Candler <B.Candler@pobox.com> + + + + Randolph Chung <tausq@debian.org> + + + + Dave Cinege <dcinege@psychosis.com> + + + + Karl M. Hegbloom <karlheg@debian.org> + + + + Daniel Jacobowitz <dan@debian.org> + + + + Matt Kraai <kraai@alumni.carnegiemellon.edu> + + + + John Lombardo <john@deltanet.com> + + + + Glenn McGrath <bug1@netconnect.com.au> + + + + Bruce Perens <bruce@perens.com> + + + + Chip Rosenthal <chip@unicom.com>, <crosenth@covad.com> + + + + Pavel Roskin <proski@gnu.org> + + + + Gyepi Sam <gyepi@praxis-sw.com> + + + + Linus Torvalds <torvalds@transmeta.com> + + + + Mark Whitley <markw@codepoet.org> + + + + Charles P. Wright <cpwright@villagenet.com> + + + + Enrique Zanardi <ezanardi@ull.es> + + + + + diff --git a/docs/busybox_footer.pod b/docs/busybox_footer.pod new file mode 100644 index 000000000..6ba8716f7 --- /dev/null +++ b/docs/busybox_footer.pod @@ -0,0 +1,169 @@ +=back + +=head1 LIBC NSS + +GNU Libc uses the Name Service Switch (NSS) to configure the behavior of the C +library for the local environment, and to configure how it reads system data, +such as passwords and group information. BusyBox has made it Policy that it +will never use NSS, and will never use and libc calls that make use of NSS. +This allows you to run an embedded system without the need for installing an +/etc/nsswitch.conf file and without and /lib/libnss_* libraries installed. + +If you are using a system that is using a remote LDAP server for authentication +via GNU libc NSS, and you want to use BusyBox, then you will need to adjust the +BusyBox source. Chances are though, that if you have enough space to install +of that stuff on your system, then you probably want the full GNU utilities. + +=head1 SEE ALSO + +textutils(1), shellutils(1), etc... + +=head1 MAINTAINER + +Erik Andersen + +=head1 AUTHORS + +The following people have contributed code to BusyBox whether +they know it or not. + + +=for html
+ +Erik Andersen + + Tons of new stuff, major rewrite of most of the + core apps, tons of new apps as noted in header files. + +=for html
+ +John Beppu + + du, head, nslookup, sort, tee, uniq (so Kraai could rewrite them ;-), + documentation + +=for html
+ +Edward Betts + + expr, hostid, logname, tty, wc, whoami, yes + +=for html
+ +Brian Candler + + tiny-ls(ls) + +=for html
+ +Randolph Chung + + fbset, ping, hostname, and mkfifo + +=for html
+ +Dave Cinege + + more(v2), makedevs, dutmp, modularization, auto links file, + various fixes, Linux Router Project maintenance + +=for html
+ +Larry Doolittle + + various fixes, shell rewrite + +=for html
+ +Karl M. Hegbloom + + cp_mv.c, the test suite, various fixes to utility.c, &c. + +=for html
+ +Sterling Huxley + + vi (!!!) + +=for html
+ +Daniel Jacobowitz + + mktemp.c + +=for html
+ +Matt Kraai + + documentation, bugfixes + +=for html
+ +John Lombardo + + dirname, tr + +=for html
+ +Glenn McGrath + + ar.c + +=for html
+ +Vladimir Oleynik + + cmdedit, stty-port, locale, various fixes + and irreconcilable critic of everything not perfect. + +=for html
+ +Bruce Perens + + Original author of BusyBox. His code is still in many apps. + +=for html
+ +Chip Rosenthal , + + wget - Contributed by permission of Covad Communications + +=for html
+ +Pavel Roskin + + Lots of bugs fixes and patches. + +=for html
+ +Gyepi Sam + + Remote logging feature for syslogd + +=for html
+ +Linus Torvalds + + mkswap, fsck.minix, mkfs.minix + +=for html
+ +Mark Whitley + + sed remix, bug fixes, style-guide, etc. + +=for html
+ +Charles P. Wright + + gzip, mini-netcat(nc) + +=for html
+ +Enrique Zanardi + + tarcat (since removed), loadkmap, various fixes, Debian maintenance + +=cut + +# $Id: busybox_footer.pod,v 1.5 2001/11/19 23:57:54 andersen Exp $ diff --git a/docs/busybox_header.pod b/docs/busybox_header.pod new file mode 100644 index 000000000..764d6e35f --- /dev/null +++ b/docs/busybox_header.pod @@ -0,0 +1,74 @@ +# vi: set sw=4 ts=4: + +=head1 NAME + +BusyBox - The Swiss Army Knife of Embedded Linux + +=head1 SYNTAX + + BusyBox [arguments...] # or + + [arguments...] # if symlinked + +=head1 DESCRIPTION + +BusyBox combines tiny versions of many common UNIX utilities into a single +small executable. It provides minimalist replacements for most of the utilities +you usually find in fileutils, shellutils, findutils, textutils, grep, gzip, +tar, etc. BusyBox provides a fairly complete POSIX environment for any small +or embedded system. The utilities in BusyBox generally have fewer options than +their full-featured GNU cousins; however, the options that are included provide +the expected functionality and behave very much like their GNU counterparts. + +BusyBox has been written with size-optimization and limited resources in mind. +It is also extremely modular so you can easily include or exclude commands (or +features) at compile time. This makes it easy to customize your embedded +systems. To create a working system, just add a kernel, a shell (such as ash), +and an editor (such as elvis-tiny or ae). + +=head1 USAGE + +When you create a link to BusyBox for the function you wish to use, when BusyBox +is called using that link it will behave as if the command itself has been invoked. + +For example, entering + + ln -s ./BusyBox ls + ./ls + +will cause BusyBox to behave as 'ls' (if the 'ls' command has been compiled +into BusyBox). + +You can also invoke BusyBox by issuing the command as an argument on the +command line. For example, entering + + ./BusyBox ls + +will also cause BusyBox to behave as 'ls'. + +=head1 COMMON OPTIONS + +Most BusyBox commands support the B<-h> option to provide a +terse runtime description of their behavior. + +=head1 COMMANDS + +Currently defined functions include: + +adjtimex, ar, basename, busybox, cat, chgrp, chmod, chown, chroot, chvt, clear, +cmp, cp, cpio, cut, date, dc, dd, deallocvt, df, dirname, dmesg, dos2unix, dpkg, +dpkg-deb, du, dumpkmap, dutmp, echo, expr, false, fbset, fdflush, find, free, +freeramdisk, fsck.minix, getopt, grep, gunzip, gzip, halt, head, hostid, +hostname, id, ifconfig, init, insmod, kill, killall, klogd, length, ln, +loadacm, loadfont, loadkmap, logger, logname, ls, lsmod, makedevs, md5sum, +mkdir, mkfifo, mkfs.minix, mknod, mkswap, mktemp, more, mount, mt, mv, nc, +nslookup, ping, pivot_root, poweroff, printf, ps, pwd, rdate, readlink, reboot, +renice, reset, rm, rmdir, rmmod, route, rpm2cpio, sed, setkeycodes, +sh, sleep, sort, stty, swapoff, swapon, sync, syslogd, tail, tar, tee, telnet, +test, tftp, touch, tr, true, tty, umount, uname, uniq, unix2dos, update, uptime, +usleep, uudecode, uuencode, watchdog, wc, wget, which, whoami, xargs, yes, zcat, +[ + +=over 4 + + diff --git a/docs/contributing.txt b/docs/contributing.txt new file mode 100644 index 000000000..7103d3e2c --- /dev/null +++ b/docs/contributing.txt @@ -0,0 +1,476 @@ +Contributing To Busybox +======================= + +This document describes what you need to do to contribute to Busybox, where +you can help, guidelines on testing, and how to submit a well-formed patch +that is more likely to be accepted. + +The Busybox home page is at: http://busybox.lineo.com + + + +Pre-Contribution Checklist +-------------------------- + +So you want to contribute to Busybox, eh? Great, wonderful, glad you want to +help. However, before you dive in, headlong and hotfoot, there are some things +you need to do: + + +Checkout the Latest Code from CVS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is a necessary first step. Please do not try to work with the last +released version, as there is a good chance that somebody has already fixed +the bug you found. Somebody might have even added the feature you had in mind. +Don't make your work obsolete before you start! + +For information on how to check out Busybox from CVS, please look at the +following links: + + http://oss.lineo.com/cvs_anon.html + http://oss.lineo.com/cvs_howto.html + + +Read the Mailing List +~~~~~~~~~~~~~~~~~~~~~ + +No one is required to read the entire archives of the mailing list, but you +should at least read up on what people have been talking about lately. If +you've recently discovered a problem, chances are somebody else has too. If +you're the first to discover a problem, post a message and let the rest of us +know. + +Archives can be found here: + + http://oss.lineo.com/lists/busybox/ + +If you have a serious interest in Busybox, i.e., you are using it day-to-day or +as part of an embedded project, it would be a good idea to join the mailing +list. + +A web-based sign-up form can be found here: + + http://oss.lineo.com/mailman/listinfo/busybox + + +Coordinate with the Applet Maintainer +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some (not all) of the applets in Busybox are "owned" by a maintainer who has +put significant effort into it and is probably more familiar with it than +others. To find the maintainer of an applet, look at the top of the .c file +for a name following the word 'Copyright' or 'Written by' or 'Maintainer'. + +Before plunging ahead, it's a good idea to send a message to the mailing list +that says: "Hey, I was thinking about adding the 'transmogrify' feature to the +'foo' applet. Would this be useful? Is anyone else working on it?" You might +want to CC the maintainer (if any) with your question. + + + +Areas Where You Can Help +------------------------ + +Busybox can always use improvement! If you're looking for ways to help, there +there are a variety of areas where you could help. + + +What Busybox Doesn't Need +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before listing the areas where you _can_ help, it's worthwhile to mention the +areas where you shouldn't bother. While Busybox strives to be the "Swiss Army +Knife" of embedded Linux, there are some applets that will not be accepted: + + - Any filesystem manipulation tools: Busybox is filesystem independent and + we do not want to start adding mkfs/fsck tools for every (or any) + filesystem under the sun. (fsck_minix.c and mkfs_minix.c are living on + borrowed time.) There are far too many of these tools out there. Use + the upstream version. Not everything has to be part of Busybox. + + - Any partitioning tools: Partitioning a device is typically done once and + only once, and tools which do this generally do not need to reside on the + target device (esp a flash device). If you need a partitioning tool, grab + one (such as fdisk, sfdisk, or cfdisk from util-linux) and use that, but + don't try to merge it into busybox. These are nasty and complex and we + don't want to maintain them. + + - Any disk, device, or media-specific tools: Use the -utils or -tools package + that was designed for your device; don't try to shoehorn them into Busybox. + + - Any architecture specific tools: Busybox is (or should be) architecture + independent. Do not send us tools that cannot be used across multiple + platforms / arches. + + - Any daemons that are not essential to basic system operation. To date, only + syslogd and klogd meet this requirement. We do not need a web server, an + ftp daemon, a dhcp server, a mail transport agent or a dns resolver. If you + need one of those, you are welcome to ask the folks on the mailing list for + recommendations, but please don't bloat up Busybox with any of these. + + +Bug Reporting +~~~~~~~~~~~~~ + +If you find a bug in Busybox, you can send a bug report to our bug tracking +system (homepage: http://bugs.lineo.com). Instructions on how to send a bug +report to the tracking system can be found at: + + http://bugs.lineo.com/Reporting.html + +The README file that comes with Busybox also describes how to submit a bug. + +A well-written bug report should include a transcript of a shell session that +demonstrates the bad behavior and enables anyone else to duplicate the bug on +their own machine. The following is such an example: + + When I execute Busybox 'date' it produces unexpected results. + + This is using GNU date: + $ date + Wed Mar 21 14:19:41 MST 2001 + + This is using Busybox date: + $ date + codswaddle + + +Bug Triage +~~~~~~~~~~ + +Validating and confirming bugs is nearly as important as reporting them in the +first place. It is valuable to know if a bug can be duplicated on a different +machine, on a different filesystem, on a different architecture, with a +different C library, and so forth. + +To see a listing of all the bugs currently filed against Busybox, look here: + + http://bugs.lineo.com/db/pa/lbusybox.html + +If you have comments to add to a bug (can / can't duplicate, think a bug +should be closed / reopened), please send it to [bugnumber]@bugs.lineo.com. +The message you send will automatically be forwarded to the mailing list for +all to see. + + +Write Documentation +~~~~~~~~~~~~~~~~~~~ + +Chances are, documentation in Busybox is either missing or needs improvement. +Either way, help is welcome. + +Work is being done to automatically generate documentation from sources, +especially from the usage.h file. If you want to correct the documentation, +please make changes to the pre-generation parts, rather than the generated +documentation. [More to come on this later...] + +It is preferred that modifications to documentation be submitted in patch +format (more on this below), but we're a little more lenient when it comes to +docs. You could, for example, just say "after the listing of the mount +options, the following example would be helpful..." + + +Consult Existing Sources +~~~~~~~~~~~~~~~~~~~~~~~~ + +For a quick listing of "needs work" spots in the sources, cd into the Busybox +directory and run the following: + + for i in TODO FIXME XXX; do grep $i *.[ch]; done + +This will show all of the trouble spots or 'questionable' code. Pick a spot, +any spot, these are all invitations for you to contribute. + + +Consult The Bug-Tracking System +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Head to: http://bugs.lineo.com/db/pa/lBusybox.html and look at the bugs on +there. Pick one you think you can fix, and fix it. If it's a wishlist item and +someone's requesting a new feature, take a stab at adding it. Everything +previously said about "reading the mailing list" and "coordinating with the +applet maintainer" still applies. + + +Add a New Applet +~~~~~~~~~~~~~~~~ + +If you want to add a new applet to Busybox, we'd love to see it. However, +before you write any code, please ask beforehand on the mailing list something +like "Do you think applet 'foo' would be useful in Busybox?" or "Would you +guys accept applet 'foo' into Busybox if I were to write it?" If the answer is +"no" by the folks on the mailing list, then you've saved yourself some time. +Conversely, you could get some positive responses from folks who might be +interested in helping you implement it, or can recommend the best approach. +Perhaps most importantly, this is your way of calling "dibs" on something and +avoiding duplication of effort. + +Also, before you write a line of code, please read the 'new-applet-HOWTO.txt' +file in the docs/ directory. + + +Janitorial Work +~~~~~~~~~~~~~~~ + +These are dirty jobs, but somebody's gotta do 'em. + + - Converting applets to use getopt() for option processing. Type 'grep -L + getopt *.c' to get a listing of the applets that currently don't use + getopt. If a .c file processes no options, it should have a line that + reads: /* no options, no getopt */ somewhere in the file. + + - Replace any "naked" calls to malloc, calloc, realloc, str[n]dup, fopen with + the x* equivalents found in utility.c. + + - Security audits: + http://www.securityfocus.com/frames/?content=/forums/secprog/secure-programming.html + + - Synthetic code removal: http://www.perl.com/pub/2000/06/commify.html - This + is very Perl-specific, but the advice given in here applies equally well to + C. + + - C library funciton use audits: Verifying that functions are being used + properly (called with the right args), replacing unsafe library functions + with safer versions, making sure return codes are being checked, etc. + + - Where appropriate, replace preprocessor defined macros and values with + compile-time equivalents. + + - Style guide compliance. See: docs/style-guide.txt + + - Add testcases to tests/testcases. + + - Makefile improvements: + http://www.canb.auug.org.au/~millerp/rmch/recu-make-cons-harm.html + (I think the recursive problems are pretty much taken care of at this point, non?) + + - "Ten Commandments" compliance: (this is a "maybe", certainly not as + important as any of the previous items.) + http://web.onetelnet.ch/~twolf/tw/c/ten_commandments.html + +Other useful links: + + - the comp.lang.c FAQ: http://web.onetelnet.ch/~twolf/tw/c/index.html#Sources + + + +Submitting Patches To Busybox +----------------------------- + +Here are some guidelines on how to submit a patch to Busybox. + + +Making A Patch +~~~~~~~~~~~~~~ + +If you've got anonymous CVS access set up, making a patch is simple. Just make +sure you're in the busybox/ directory and type 'cvs diff -bwu > mychanges.patch'. +You can send the resulting .patch file to the mailing list with a description +of what it does. (But not before you test it! See the next section for some +guidelines.) It is preferred that patches be sent as attachments, but it is +not required. + +Also, feel free to help test other people's patches and reply to them with +comments. You can apply a patch by saving it into your busybox/ directory and +typing 'patch < mychanges.patch'. Then you can recompile, see if it runs, test +if it works as advertised, and post your findings to the mailing list. + +NOTE: Please do not include extraneous or irrelevant changes in your patches. +Please do not try to "bundle" two patches together into one. Make single, +discreet changes on a per-patch basis. Sometimes you need to make a patch that +touches code in many places, but these kind of patches are rare and should be +coordinated with a maintainer. + + +Testing Guidelines +~~~~~~~~~~~~~~~~~~ + +It's considered good form to test your new feature before you submit a patch +to the mailing list, and especially before you commit a change to CVS. Here +are some guidelines on how to test your changes. + + - Always test Busybox applets against GNU counterparts and make sure the + behavior / output is identical between the two. + + - Try several different permutations and combinations of the features you're + adding (i.e., different combinations of command-line switches) and make sure + they all work; make sure one feature does not interfere with another. + + - Make sure you test compiling against the source both with the feature + turned on and turned off in Config.h and make sure Busybox compiles cleanly + both ways. + + - Run the multibuild.pl script in the tests directory and make sure + everything checks out OK. (Do this from within the busybox/ directory by + typing: 'tests/multibuild.pl'.) + + +Making Sure Your Patch Doesn't Get Lost +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you don't want your patch to be lost or forgotten, send it to the bug +tracking system (http://bugs.lineo.com). You do this by emailing your patch in +a message to submit@bugs.lineo.com with a subject line something like this: + + [PATCH] - Adds "transmogrify" feature to "foo" + +In the body, you should have a pseudo-header that looks like the following: + + Package: busybox + Version: v0.50pre (or whatever the current version is) + Severity: wishlist + +The remainder of the body should read along these lines: + + This patch adds the "transmogrify" feature to the "foo" applet. I have + tested this on [arch] system(s) and it works. I have tested it against the + GNU counterparts and the outputs are identical. I have run the scripts in + the 'tests' directory and nothing breaks. + +Detailed instructions on how to submit a bug to the tracking system are at: + + http://bugs.lineo.com/Reporting.html + +If you have a patch that will fix and close a reported bug, please send a +message to [bugnumber]@bugs.lineo.com with your patch attached. It will catch +people's attention if you have a subject line like the following: + + [PATCH INCLUDED] - Fix attached, please apply and close this bug + + + +Improving Your Chances of Patch Acceptance +------------------------------------------ + +Even after you send a brilliant patch to the mailing list, sometimes it can go +unnoticed, un-replied-to, and sometimes (sigh) even lost. This is an +unfortunate fact of life, but there are steps you can take to help your patch +get noticed and convince a maintainer that it should be added: + + +Be Succinct +~~~~~~~~~~~ + +A patch that includes small, isolated, obvious changes is more likely to be +accepted than a patch that touches code in lots of different places or makes +sweeping, dubious changes. + + +Back It Up +~~~~~~~~~~ + +Hard facts on why your patch is better than the existing code will go a long +way toward convincing maintainers that your patch should be included. +Specifically, patches are more likely to be accepted if they are provably more +correct, smaller, faster, simpler, or more maintainable than the existing +code. + +Conversely, any patch that is supported with nothing more than "I think this +would be cool" or "this patch is good because I say it is and I've got a Phd +in Computer Science" will likely be ignored. + + +Follow The Style Guide +~~~~~~~~~~~~~~~~~~~~~~ + +It's considered good form to abide by the established coding style used in a +project; Busybox is no exception. We have gone so far as to delineate the +"elements of Busybox style" in the file docs/style-guide.txt. Please follow +them. + + +Work With Someone Else +~~~~~~~~~~~~~~~~~~~~~~ + +Working on a patch in isolation is less effective than working with someone +else for a variety of reasons. If another Busybox user is interested in what +you're doing, then it's two (or more) voices instead of one that can petition +for inclusion of the patch. You'll also have more people that can test your +changes, or even offer suggestions on better approaches you could take. + +Getting other folks interested follows as a natural course if you've received +responses from queries to applet maintainer or positive responses from folks +on the mailing list. + +We've made strident efforts to put a useful "collaboration" infrastructure in +place in the form of mailing lists, the bug tracking system, and CVS. Please +use these resources. + + +Send Patches to the Bug Tracking System +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This was mentioned above in the "Making Sure Your Patch Doesn't Get Lost" +section, but it is worth mentioning again. A patch sent to the mailing list +might be unnoticed and forgotten. A patch sent to the bug tracking system will +be stored and closely connected to the bug it fixes. + + +Be Polite +~~~~~~~~~ + +The old saying "You'll catch more flies with honey than you will with vinegar" +applies when submitting patches to the mailing list for approval. The way you +present your patch is sometimes just as important as the actual patch itself +(if not more so). Being rude to the maintainers is not an effective way to +convince them that your patch should be included; it will likely have the +opposite effect. + + + +Committing Changes to CVS +------------------------- + +If you submit several patches that demonstrate that you are a skilled and wise +coder, you may be invited to become a committer, thus enabling you to commit +changes directly to CVS. This is nice because you don't have to wait for +someone else to commit your change for you, you can just do it yourself. + +But note that this is a priviledge that comes with some responsibilities. You +should test your changes before you commit them. You should also talk to an +applet maintainer before you make any kind of sweeping changes to somebody +else's code. Big changes should still go to the mailing list first. Remember, +being wise, polite, and discreet is more important than being clever. + + +When To Commit +~~~~~~~~~~~~~~ + +Generally, you should feel free to commit a change if: + + - Your changes are small and don't touch many files + - You are fixing a bug + - Somebody has told you that it's okay + - It's obviously the Right Thing + +The more of the above are true, the better it is to just commit a change +directly to CVS. + + +When Not To Commit +~~~~~~~~~~~~~~~~~~ + +Even if you have commit rights, you should probably still post a patch to the +mailing list if: + + - Your changes are broad and touch many different files + - You are adding a feature + - Your changes are speculative or experimental (i.e., trying a new algorithm) + - You are not the maintainer and your changes make the maintainer cringe + +The more of the above are true, the better it is to post a patch to the +mailing list instead of committing. + + + +Final Words +----------- + +If all of this seems complicated, don't panic, it's really not that tough. If +you're having difficulty following some of the steps outlined in this +document don't worry, the folks on the Busybox mailing list are a fairly +good-natured bunch and will work with you to help get your patches into shape +or help you make contributions. + + diff --git a/docs/new-applet-HOWTO.txt b/docs/new-applet-HOWTO.txt new file mode 100644 index 000000000..f79504f78 --- /dev/null +++ b/docs/new-applet-HOWTO.txt @@ -0,0 +1,138 @@ +How to Add a New Applet to BusyBox +================================== + +This document details the steps you must take to add a new applet to BusyBox. + +Credits: +Matt Kraai - initial writeup +Mark Whitley - the remix + + +Initial Write +------------- + +First, write your applet. Be sure to include copyright information at the +top, such as who you stole the code from and so forth. Also include the +mini-GPL boilerplate. Be sure to name the main function _main instead +of main. And be sure to put it in .c. For a new applet mu, here is +the code that would go in mu.c: + +----begin example code------ + +/* vi: set sw=4 ts=4: */ +/* + * Mini mu implementation for busybox + * + * + * Copyright (C) [YEAR] by [YOUR NAME] + * + * 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 "busybox.h" + +int mu_main(int argc, char **argv) +{ + int fd; + char mu; + + if ((fd = open("/dev/random", O_RDONLY)) < 0) + perror_msg_and_die("/dev/random"); + + if ((n = safe_read(fd, &mu, 1)) < 1) + perror_msg_and_die("/dev/random"); + + return mu; +} + +----end example code------ + + +Coding Style +------------ + +Before you submit your applet for inclusion in BusyBox, (or better yet, before +you _write_ your applet) please read through the style guide in the docs +directory and make your program compliant. + + +Some Words on libbb +------------------- + +As you are writing your applet, please be aware of the body of pre-existing +useful functions in libbb. Use these instead of reinventing the wheel. + +Additionally, if you have any useful, general-purpose functions in your +program that could be useful in another program, consider putting them in +libbb. + + +Usage String(s) +--------------- + +Next, add usage information for you applet to usage.h. This should look like +the following: + + #define mu_trivial_usage \ + "-[abcde] FILES" + #define mu_full_usage \ + "Returns an indeterminate value.\n\n" \ + "Options:\n" \ + "\t-a\t\tfirst function\n" \ + "\t-b\t\tsecond function\n" \ + +If your program supports flags, the flags should be mentioned on the first +line (-[abcde]) and a detailed description of each flag should go in the +mu_full_usage section, one flag per line. (Numerous examples of this +currently exist in usage.h.) + + +Header Files +------------ + +Next, add an entry to applets.h. Be *sure* to keep the list in alphabetical +order, or else it will break the binary-search lookup algorithm in busybox.c +and the Gods of BusyBox smite you. Yea, verily: + + /* all programs above here are alphabetically "less than" 'mu' */ + #ifdef BB_MU + APPLET("mu", mu_main, _BB_DIR_USR_BIN, mu_usage) + #endif + /* all programs below here are alphabetically "greater than" 'mu' */ + + +Finally, add a define for your applet to Config.h: + + #define BB_MU + + +Documentation +------------- + +If you're feeling especially nice, you should also document your applet in the +docs directory (but nobody ever does that). + + +The Grand Announcement +---------------------- + +Then create a diff -urN of the files you added (.c, usage.c, +applets.h, Config.h) and send it to the mailing list: +busybox@oss.lineo.com. Sending patches as attachments is preferred, but +not required. + + diff --git a/docs/style-guide.txt b/docs/style-guide.txt new file mode 100644 index 000000000..c71f1e609 --- /dev/null +++ b/docs/style-guide.txt @@ -0,0 +1,680 @@ +Busybox Style Guide +=================== + +This document describes the coding style conventions used in Busybox. If you +add a new file to Busybox or are editing an existing file, please format your +code according to this style. If you are the maintainer of a file that does +not follow these guidelines, please -- at your own convenience -- modify the +file(s) you maintain to bring them into conformance with this style guide. +Please note that this is a low priority task. + +To help you format the whitespace of your programs, an ".indent.pro" file is +included in the main Busybox source directory that contains option flags to +format code as per this style guide. This way you can run GNU indent on your +files by typing 'indent myfile.c myfile.h' and it will magically apply all the +right formatting rules to your file. Please _do_not_ run this on all the files +in the directory, just your own. + + + +Declaration Order +----------------- + +Here is the order in which code should be laid out in a file: + + - commented program name and one-line description + - commented author name and email address(es) + - commented GPL boilerplate + - commented longer description / notes for the program (if needed) + - #includes of .h files with angle brackets (<>) around them + - #includes of .h files with quotes ("") around them + - #defines (if any, note the section below titled "Avoid the Preprocessor") + - const and global variables + - function declarations (if necessary) + - function implementations + + + +Whitespace and Formatting +------------------------- + +This is everybody's favorite flame topic so let's get it out of the way right +up front. + + +Tabs vs. Spaces in Line Indentation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The preference in Busybox is to indent lines with tabs. Do not indent lines +with spaces and do not indents lines using a mixture of tabs and spaces. (The +indentation style in the Apache and Postfix source does this sort of thing: +\s\s\s\sif (expr) {\n\tstmt; --ick.) The only exception to this rule is +multi-line comments that use an asterisk at the beginning of each line, i.e.: + + /t/* + /t * This is a block comment. + /t * Note that it has multiple lines + /t * and that the beginning of each line has a tab plus a space + /t * except for the opening '/*' line where the slash + /t * is used instead of a space. + /t */ + +Furthermore, The preference is that tabs be set to display at four spaces +wide, but the beauty of using only tabs (and not spaces) at the beginning of +lines is that you can set your editor to display tabs at *whatever* number of +spaces is desired and the code will still look fine. + + +Operator Spacing +~~~~~~~~~~~~~~~~ + +Put spaces between terms and operators. Example: + + Don't do this: + + for(i=0;i 0) + + +Bracket Spacing +~~~~~~~~~~~~~~~ + +If an opening bracket starts a function, it should be on the +next line with no spacing before it. However, if a bracket follows an opening +control block, it should be on the same line with a single space (not a tab) +between it and the opening control block statement. Examples: + + Don't do this: + + while (!done) + { + + do + { + + Don't do this either: + + while (!done){ + + do{ + + And for heaven's sake, don't do this: + + while (!done) + { + + do + { + + Do this instead: + + while (!done) { + + do { + + +Spacing around Parentheses +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Put a space between C keywords and left parens, but not between function names +and the left paren that starts it's parameter list (whether it is being +declared or called). Examples: + + Don't do this: + + while(foo) { + for(i = 0; i < n; i++) { + + Do this instead: + + while (foo) { + for (i = 0; i < n; i++) { + + But do functions like this: + + static int my_func(int foo, char bar) + ... + baz = my_func(1, 2); + +Also, don't put a space between the left paren and the first term, nor between +the last arg and the right paren. + + Don't do this: + + if ( x < 1 ) + strcmp( thisstr, thatstr ) + + Do this instead: + + if (x < 1) + strcmp(thisstr, thatstr) + + +Cuddled Elses +~~~~~~~~~~~~~ + +Also, please "cuddle" your else statements by putting the else keyword on the +same line after the right bracket that closes an 'if' statement. + + Don't do this: + + if (foo) { + stmt; + } + else { + stmt; + } + + Do this instead: + + if (foo) { + stmt; + } else { + stmt; + } + +The exception to this rule is if you want to include a comment before the else +block. Example: + + if (foo) { + stmts... + } + /* otherwise, we're just kidding ourselves, so re-frob the input */ + else { + other_stmts... + } + + + +Variable and Function Names +--------------------------- + +Use the K&R style with names in all lower-case and underscores occasionally +used to separate words (e.g., "variable_name" and "numchars" are both +acceptable). Using underscores makes variable and function names more readable +because it looks like whitespace; using lower-case is easy on the eyes. + + Frowned upon: + + hitList + TotalChars + szFileName + pf_Nfol_TriState + + Preferred: + + hit_list + total_chars + file_name + sensible_name + +Exceptions: + + - Enums, macros, and constant variables are occasionally written in all + upper-case with words optionally seperatedy by underscores (i.e. FIFOTYPE, + ISBLKDEV()). + + - Nobody is going to get mad at you for using 'pvar' as the name of a + variable that is a pointer to 'var'. + + +Converting to K&R +~~~~~~~~~~~~~~~~~ + +The Busybox codebase is very much a mixture of code gathered from a variety of +sources. This explains why the current codebase contains such a hodge-podge of +different naming styles (Java, Pascal, K&R, just-plain-weird, etc.). The K&R +guideline explained above should therefore be used on new files that are added +to the repository. Furthermore, the maintainer of an existing file that uses +alternate naming conventions should, at his own convenience, convert those +names over to K&R style. Converting variable names is a very low priority +task. + +If you want to do a search-and-replace of a single variable name in different +files, you can do the following in the busybox directory: + + $ perl -pi -e 's/\bOldVar\b/new_var/g' *.[ch] + +If you want to convert all the non-K&R vars in your file all at once, follow +these steps: + + - In the busybox directory type 'scripts/mk2knr.pl files-to-convert'. This + does not do the actual conversion, rather, it generates a script called + 'convertme.pl' that shows what will be converted, giving you a chance to + review the changes beforehand. + + - Review the 'convertme.pl' script that gets generated in the busybox + directory and remove / edit any of the substitutions in there. Please + especially check for false positives (strings that should not be + converted). + + - Type './convertme.pl same-files-as-before' to perform the actual + conversion. + + - Compile and see if everything still works. + +Please be aware of changes that have cascading effects into other files. For +example, if you're changing the name of something in, say utility.c, you +should probably run 'scripts/mk2knr.pl utility.c' at first, but when you run +the 'convertme.pl' script you should run it on _all_ files like so: +'./convertme.pl *.[ch]'. + + + +Avoid The Preprocessor +---------------------- + +At best, the preprocessor is a necessary evil, helping us account for platform +and architecture differences. Using the preprocessor unnecessarily is just +plain evil. + + +The Folly of #define +~~~~~~~~~~~~~~~~~~~~ + +Use 'const var' for declaring constants. + + Don't do this: + + #define var 80 + + Do this instead, when the variable is in a header file and will be used in + several source files: + + const int var = 80; + + Or do this when the variable is used only in a single source file: + + static const int var = 80; + +Declaring variables as '[static] const' gives variables an actual type and +makes the compiler do type checking for you; the preprocessor does _no_ type +checking whatsoever, making it much more error prone. Declaring variables with +'[static] const' also makes debugging programs much easier since the value of +the variable can be easily queried and displayed. + + +The Folly of Macros +~~~~~~~~~~~~~~~~~~~ + +Use 'static inline' instead of a macro. + + Don't do this: + + #define mini_func(param1, param2) (param1 << param2) + + Do this instead: + + static inline int mini_func(int param1, param2) + { + return (param1 << param2); + } + +Static inline functions are greatly preferred over macros. They provide type +safety, have no length limitations, no formatting limitations, have an actual +return value, and under gcc they are as cheap as macros. Besides, really long +macros with backslashes at the end of each line are ugly as sin. + + +The Folly of #ifdef +~~~~~~~~~~~~~~~~~~~ + +Code cluttered with ifdefs is difficult to read and maintain. Don't do it. +Instead, put your ifdefs at the top of your .c file (or in a header), and +conditionally define 'static inline' functions, (or *maybe* macros), which are +used in the code. + + Don't do this: + + ret = my_func(bar, baz); + if (!ret) + return -1; + #ifdef BB_FEATURE_FUNKY + maybe_do_funky_stuff(bar, baz); + #endif + + Do this instead: + + (in .h header file) + + #ifdef BB_FEATURE_FUNKY + static inline void maybe_do_funky_stuff (int bar, int baz) + { + /* lotsa code in here */ + } + #else + static inline void maybe_do_funky_stuff (int bar, int baz) {} + #endif + + (in the .c source file) + + ret = my_func(bar, baz); + if (!ret) + return -1; + maybe_do_funky_stuff(bar, baz); + +The great thing about this approach is that the compiler will optimize away +the "no-op" case (the empty function) when the feature is turned off. + +Note also the use of the word 'maybe' in the function name to indicate +conditional execution. + + + +Notes on Strings +---------------- + +Strings in C can get a little thorny. Here's some guidelines for dealing with +strings in Busybox. (There is surely more that could be added to this +section.) + + +String Files +~~~~~~~~~~~~ + +Put all help/usage messages in usage.c. Put other strings in messages.c. +Putting these strings into their own file is a calculated decision designed to +confine spelling errors to a single place and aid internationalization +efforts, if needed. (Side Note: we might want to use a single file - maybe +called 'strings.c' - instead of two, food for thought). + + +Testing String Equivalence +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There's a right way and a wrong way to test for sting equivalence with +strcmp(): + + The wrong way: + + if (!strcmp(string, "foo")) { + ... + + The right way: + + if (strcmp(string, "foo") == 0){ + ... + +The use of the "equals" (==) operator in the latter example makes it much more +obvious that you are testing for equivalence. The former example with the +"not" (!) operator makes it look like you are testing for an error. In a more +perfect world, we would have a streq() function in the string library, but +that ain't the world we're living in. + + +Avoid Dangerous String Functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Unfortunately, the way C handles strings makes them prone to overruns when +certain library functions are (mis)used. The following table offers a summary +of some of the more notorious troublemakers: + +function overflows preferred +---------------------------------------- +strcpy dest string strncpy +strcat dest string strncat +gets string it gets fgets +getwd buf string getcwd +[v]sprintf str buffer [v]snprintf +realpath path buffer use with pathconf +[vf]scanf its arguments just avoid it + + +The above is by no means a complete list. Be careful out there. + + + +Avoid Big Static Buffers +------------------------ + +First, some background to put this discussion in context: Static buffers look +like this in code: + + /* in a .c file outside any functions */ + static char *buffer[BUFSIZ]; /* happily used by any function in this file, + but ick! big! */ + +The problem with these is that any time any busybox app is run, you pay a +memory penalty for this buffer, even if the applet that uses said buffer is +not run. This can be fixed, thusly: + + static char *buffer; + ... + other_func() + { + strcpy(buffer, lotsa_chars); /* happily uses global *buffer */ + ... + foo_main() + { + buffer = xmalloc(sizeof(char)*BUFSIZ); + ... + +However, this approach trades bss segment for text segment. Rather than +mallocing the buffers (and thus growing the text size), buffers can be +declared on the stack in the *_main() function and made available globally by +assigning them to a global pointer thusly: + + static char *pbuffer; + ... + other_func() + { + strcpy(pbuffer, lotsa_chars); /* happily uses global *pbuffer */ + ... + foo_main() + { + char *buffer[BUFSIZ]; /* declared locally, on stack */ + pbuffer = buffer; /* but available globally */ + ... + +This last approach has some advantages (low code size, space not used until +it's needed), but can be a problem in some low resource machines that have +very limited stack space (e.g., uCLinux). + +A macro is declared in busybox.h that implements compile-time selection +between xmalloc() and stack creation, so you can code the line in question as + + RESERVE_BB_BUFFER(buffer, BUFSIZ); + +and the right thing will happen, based on your configuration. + + + +Miscellaneous Coding Guidelines +------------------------------- + +The following are important items that don't fit into any of the above +sections. + + +Model Busybox Applets After GNU Counterparts +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When in doubt about the proper behavior of a Busybox program (output, +formatting, options, etc.), model it after the equivalent GNU program. +Doesn't matter how that program behaves on some other flavor of *NIX; doesn't +matter what the POSIX standard says or doesn't say, just model Busybox +programs after their GNU counterparts and it will make life easier on (nearly) +everyone. + +The only time we deviate from emulating the GNU behavior is when: + + - We are deliberately not supporting a feature (such as a command line + switch) + - Emulating the GNU behavior is prohibitively expensive (lots more code + would be required, lots more memory would be used, etc.) + - The difference is minor or cosmetic + +A note on the 'cosmetic' case: Output differences might be considered +cosmetic, but if the output is significant enough to break other scripts that +use the output, it should really be fixed. + + +Scope +~~~~~ + +If a const variable is used only in a single source file, put it in the source +file and not in a header file. Likewise, if a const variable is used in only +one function, do not make it global to the file. Instead, declare it inside +the function body. Bottom line: Make a conscious effort to limit declarations +to the smallest scope possible. + +Inside applet files, all functions should be declared static so as to keep the +global name space clean. The only exception to this rule is the "applet_main" +function which must be declared extern. + +If you write a function that performs a task that could be useful outside the +immediate file, turn it into a general-purpose function with no ties to any +applet and put it in the utility.c file instead. + + +Brackets Are Your Friends +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Please use brackets on all if and else statements, even if it is only one +line. Example: + + Don't do this: + + if (foo) + stmt1; + stmt2 + stmt3; + + Do this instead: + + if (foo) { + stmt1; + } + stmt2 + stmt3; + +The "bracketless" approach is error prone because someday you might add a line +like this: + + if (foo) + stmt1; + new_line(); + stmt2 + stmt3; + +And the resulting behavior of your program would totally bewilder you. (Don't +laugh, it happens to us all.) Remember folks, this is C, not Python. + + +Function Declarations +~~~~~~~~~~~~~~~~~~~~~ + +Do not use old-style function declarations that declare variable types between +the parameter list and opening bracket. Example: + + Don't do this: + + int foo(parm1, parm2) + char parm1; + float parm2; + { + .... + + Do this instead: + + int foo(char parm1, float parm2) + { + .... + +The only time you would ever need to use the old declaration syntax is to +support ancient, antediluvian compilers. To our good fortune, we have access +to more modern compilers and the old declaration syntax is neither necessary +nor desired. + + +Emphasizing Logical Blocks +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Organization and readability are improved by putting extra newlines around +blocks of code that perform a single task. These are typically blocks that +begin with a C keyword, but not always. + +Furthermore, you should put a single comment (not necessarily one line, just +one comment) before the block, rather than commenting each and every line. +There is an optimal ammount of commenting that a program can have; you can +comment too much as well as too little. + +A picture is really worth a thousand words here, the following example +illustrates how to emphasize logical blocks: + + while (line = get_line_from_file(fp)) { + + /* eat the newline, if any */ + chomp(line); + + /* ignore blank lines */ + if (strlen(file_to_act_on) == 0) { + continue; + } + + /* if the search string is in this line, print it, + * unless we were told to be quiet */ + if (strstr(line, search) && !be_quiet) { + puts(line); + } + + /* clean up */ + free(line); + } + + +Processing Options with getopt +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If your applet needs to process command-line switches, please use getopt() to +do so. Numerous examples can be seen in many of the existing applets, but +basically it boils down to two things: at the top of the .c file, have this +line in the midst of your #includes: + + #include + +And a code block similar to the following near the top of your applet_main() +routine: + + while ((opt = getopt(argc, argv, "abc")) > 0) { + switch (opt) { + case 'a': + do_a_opt = 1; + break; + case 'b': + do_b_opt = 1; + break; + case 'c': + do_c_opt = 1; + break; + default: + show_usage(); /* in utility.c */ + } + } + +If your applet takes no options (such as 'init'), there should be a line +somewhere in the file reads: + + /* no options, no getopt */ + +That way, when people go grepping to see which applets need to be converted to +use getopt, they won't get false positives. + +Additional Note: Do not use the getopt_long library function and do not try to +hand-roll your own long option parsing. Busybox applets should only support +short options. Explanations and examples of the short options should be +documented in usage.h. diff --git a/dos2unix.c b/dos2unix.c new file mode 100644 index 000000000..f4ce2b829 --- /dev/null +++ b/dos2unix.c @@ -0,0 +1,197 @@ +/* + * dos2unix for BusyBox + * + * dos2unix '\n' convertor 0.5.0 + * 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. + */ + +#include +#include +#include +#if (__GNU_LIBRARY__ > 5) +#include +#endif +#include +#include +#include "busybox.h" + + +/* 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) +{ + int c, fd; + struct timeval tv; + char tempFn[BUFSIZ]; + static bb_uint64_t value=0; + FILE *in = stdin, *out = stdout; + + if (fn != NULL) { + if ((in = wfopen(fn, "rw")) == NULL) { + return -1; + } + safe_strncpy(tempFn, fn, sizeof(tempFn)); + c = strlen(tempFn); + tempFn[c] = '.'; + while(1) { + if (c >=BUFSIZ) + 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; + } + } + + 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) { + perror_msg(NULL); + 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)) { + perror_msg(NULL); + return -2; + } + return 0; + } + if (!ConvType) { + ConvType = CT_UNIX2DOS; + } + if (ConvType == 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); + } + + if (fn != NULL) { + if (fclose(in) < 0 || fclose(out) < 0) { + perror_msg(NULL); + 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) { + perror_msg("unable to rename '%s' as '%s'", tempFn, fn); + return -1; + } + } + + return 0; +} + +int dos2unix_main(int argc, char *argv[]) +{ + int ConvType = CT_AUTO; + int o; + + //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; + } + + // process parameters + while ((o = getopt(argc, argv, "du")) != EOF) { + switch (o) { + case 'd': + ConvType = CT_UNIX2DOS; + break; + case 'u': + ConvType = CT_DOS2UNIX; + break; + default: + show_usage(); + } + } + + if (optind < argc) { + while(optind < argc) + if ((o = convert(argv[optind++], ConvType)) < 0) + break; + } + else + o = convert(NULL, ConvType); + + return o; +} + diff --git a/dpkg.c b/dpkg.c new file mode 100644 index 000000000..4ea4dbac9 --- /dev/null +++ b/dpkg.c @@ -0,0 +1,1445 @@ +/* + * Mini dpkg implementation for busybox. + * This is not meant as a replacemnt for dpkg + * + * Copyright (C) 2001 by Glenn McGrath + * + * Started life as a busybox implementation of udpkg + * + * 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. + */ + +/* + * Known difference between busybox dpkg and the official dpkg that i dont + * consider important, its worth keeping a note of differences anyway, just to + * make it easier to maintain. + * - The first value for the Confflile: field isnt placed on a new line. + * - The .control file is extracted and kept in the info dir. + * - When installing a package the Status: field is placed at the end of the + * section, rather than just after the Package: field. + * - Packages with previously unknown status are inserted at the begining of + * the status file + * + * Bugs that need to be fixed + * - (unknown, please let me know when you find any) + * + */ + +#include +#include +#include +#include +#include "busybox.h" + +/* NOTE: If you vary HASH_PRIME sizes be aware, + * 1) Tweaking these will have a big effect on how much memory this program uses. + * 2) For computational efficiency these hash tables should be at least 20% + * larger than the maximum number of elements stored in it. + * 3) All _HASH_PRIME's must be a prime number or chaos is assured, if your looking + * for a prime, try http://www.utm.edu/research/primes/lists/small/10000.txt + * 4) If you go bigger than 15 bits you may get into trouble (untested) as its + * sometimes cast to an unsigned int, if you go to 16 bit you will overlap + * int's and chaos is assured, 16381 is the max prime for 14 bit field + */ + +/* NAME_HASH_PRIME, Stores package names and versions, + * I estimate it should be at least 50% bigger than PACKAGE_HASH_PRIME, + * as there a lot of duplicate version numbers */ +#define NAME_HASH_PRIME 16381 +char *name_hashtable[NAME_HASH_PRIME + 1]; + +/* PACKAGE_HASH_PRIME, Maximum number of unique packages, + * It must not be smaller than STATUS_HASH_PRIME, + * Currently only packages from status_hashtable are stored in here, but in + * future this may be used to store packages not only from a status file, + * but an available_hashtable, and even multiple packages files. + * Package can be stored more than once if they have different versions. + * e.g. The same package may have different versions in the status file + * and available file */ +#define PACKAGE_HASH_PRIME 10007 +typedef struct edge_s { + unsigned int operator:3; + unsigned int type:4; + unsigned int name:14; + unsigned int version:14; +} edge_t; + +typedef struct common_node_s { + unsigned int name:14; + unsigned int version:14; + unsigned int num_of_edges:14; + edge_t **edge; +} common_node_t; +common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1]; + +/* Currently it doesnt store packages that have state-status of not-installed + * So it only really has to be the size of the maximum number of packages + * likely to be installed at any one time, so there is a bit of leaway here */ +#define STATUS_HASH_PRIME 8191 +typedef struct status_node_s { + unsigned int package:14; /* has to fit PACKAGE_HASH_PRIME */ + unsigned int status:14; /* has to fit STATUS_HASH_PRIME */ +} status_node_t; +status_node_t *status_hashtable[STATUS_HASH_PRIME + 1]; + +/* Even numbers are for 'extras', like ored dependecies or null */ +enum edge_type_e { + EDGE_NULL = 0, + EDGE_PRE_DEPENDS = 1, + EDGE_OR_PRE_DEPENDS = 2, + EDGE_DEPENDS = 3, + EDGE_OR_DEPENDS = 4, + EDGE_REPLACES = 5, + EDGE_PROVIDES = 7, + EDGE_CONFLICTS = 9, + EDGE_SUGGESTS = 11, + EDGE_RECOMMENDS = 13, + EDGE_ENHANCES = 15 +}; +enum operator_e { + VER_NULL = 0, + VER_EQUAL = 1, + VER_LESS = 2, + VER_LESS_EQUAL = 3, + VER_MORE = 4, + VER_MORE_EQUAL = 5, + VER_ANY = 6 +}; + +enum dpkg_opt_e { + dpkg_opt_purge = 1, + dpkg_opt_remove = 2, + dpkg_opt_unpack = 4, + dpkg_opt_configure = 8, + dpkg_opt_install = 16, + dpkg_opt_package_name = 32, + dpkg_opt_filename = 64, + dpkg_opt_list_installed = 128, + dpkg_opt_force_ignore_depends = 256 +}; + +typedef struct deb_file_s { + char *control_file; + char *filename; + unsigned int package:14; +} deb_file_t; + + +void make_hash(const char *key, unsigned int *start, unsigned int *decrement, const int hash_prime) +{ + unsigned long int hash_num = key[0]; + int len = strlen(key); + int i; + + /* Maybe i should have uses a "proper" hashing algorithm here instead + * of making one up myself, seems to be working ok though. */ + for(i = 1; i < len; i++) { + /* shifts the ascii based value and adds it to previous value + * shift amount is mod 24 because long int is 32 bit and data + * to be shifted is 8, dont want to shift data to where it has + * no effect*/ + hash_num += ((key[i] + key[i-1]) << ((key[i] * i) % 24)); + } + *start = (unsigned int) hash_num % hash_prime; + *decrement = (unsigned int) 1 + (hash_num % (hash_prime - 1)); +} + +/* this adds the key to the hash table */ +int search_name_hashtable(const char *key) +{ + unsigned int probe_address = 0; + unsigned int probe_decrement = 0; +// char *temp; + + make_hash(key, &probe_address, &probe_decrement, NAME_HASH_PRIME); + while(name_hashtable[probe_address] != NULL) { + if (strcmp(name_hashtable[probe_address], key) == 0) { + return(probe_address); + } else { + probe_address -= probe_decrement; + if ((int)probe_address < 0) { + probe_address += NAME_HASH_PRIME; + } + } + } + name_hashtable[probe_address] = xstrdup(key); + return(probe_address); +} + +/* this DOESNT add the key to the hashtable + * TODO make it consistent with search_name_hashtable + */ +unsigned int search_status_hashtable(const char *key) +{ + unsigned int probe_address = 0; + unsigned int probe_decrement = 0; + + make_hash(key, &probe_address, &probe_decrement, STATUS_HASH_PRIME); + while(status_hashtable[probe_address] != NULL) { + if (strcmp(key, name_hashtable[package_hashtable[status_hashtable[probe_address]->package]->name]) == 0) { + break; + } else { + probe_address -= probe_decrement; + if ((int)probe_address < 0) { + probe_address += STATUS_HASH_PRIME; + } + } + } + return(probe_address); +} + +/* Need to rethink version comparison, maybe the official dpkg has something i can use ? */ +int version_compare_part(const char *version1, const char *version2) +{ + int upstream_len1 = 0; + int upstream_len2 = 0; + char *name1_char; + char *name2_char; + int len1 = 0; + int len2 = 0; + int tmp_int; + int ver_num1; + int ver_num2; + int ret; + + if (version1 == NULL) { + version1 = xstrdup(""); + } + if (version2 != NULL) { + version2 = xstrdup(""); + } + upstream_len1 = strlen(version1); + upstream_len2 = strlen(version2); + + while ((len1 < upstream_len1) || (len2 < upstream_len2)) { + /* Compare non-digit section */ + tmp_int = strcspn(&version1[len1], "0123456789"); + name1_char = xstrndup(&version1[len1], tmp_int); + len1 += tmp_int; + tmp_int = strcspn(&version2[len2], "0123456789"); + name2_char = xstrndup(&version2[len2], tmp_int); + len2 += tmp_int; + tmp_int = strcmp(name1_char, name2_char); + free(name1_char); + free(name2_char); + if (tmp_int != 0) { + ret = tmp_int; + goto cleanup_version_compare_part; + } + + /* Compare digits */ + tmp_int = strspn(&version1[len1], "0123456789"); + name1_char = xstrndup(&version1[len1], tmp_int); + len1 += tmp_int; + tmp_int = strspn(&version2[len2], "0123456789"); + name2_char = xstrndup(&version2[len2], tmp_int); + len2 += tmp_int; + ver_num1 = atoi(name1_char); + ver_num2 = atoi(name2_char); + free(name1_char); + free(name2_char); + if (ver_num1 < ver_num2) { + ret = -1; + goto cleanup_version_compare_part; + } + else if (ver_num1 > ver_num2) { + ret = 1; + goto cleanup_version_compare_part; + } + } + ret = 0; +cleanup_version_compare_part: + return(ret); +} + +/* if ver1 < ver2 return -1, + * if ver1 = ver2 return 0, + * if ver1 > ver2 return 1, + */ +int version_compare(const unsigned int ver1, const unsigned int ver2) +{ + char *ch_ver1 = name_hashtable[ver1]; + char *ch_ver2 = name_hashtable[ver2]; + + char epoch1, epoch2; + char *deb_ver1, *deb_ver2; + char *ver1_ptr, *ver2_ptr; + char *upstream_ver1; + char *upstream_ver2; + int result; + + /* Compare epoch */ + if (ch_ver1[1] == ':') { + epoch1 = ch_ver1[0]; + ver1_ptr = strchr(ch_ver1, ':') + 1; + } else { + epoch1 = '0'; + ver1_ptr = ch_ver1; + } + if (ch_ver2[1] == ':') { + epoch2 = ch_ver2[0]; + ver2_ptr = strchr(ch_ver2, ':') + 1; + } else { + epoch2 = '0'; + ver2_ptr = ch_ver2; + } + if (epoch1 < epoch2) { + return(-1); + } + else if (epoch1 > epoch2) { + return(1); + } + + /* Compare upstream version */ + upstream_ver1 = xstrdup(ver1_ptr); + upstream_ver2 = xstrdup(ver2_ptr); + + /* Chop off debian version, and store for later use */ + deb_ver1 = strrchr(upstream_ver1, '-'); + deb_ver2 = strrchr(upstream_ver2, '-'); + if (deb_ver1) { + deb_ver1[0] = '\0'; + deb_ver1++; + } + if (deb_ver2) { + deb_ver2[0] = '\0'; + deb_ver2++; + } + result = version_compare_part(upstream_ver1, upstream_ver2); + + free(upstream_ver1); + free(upstream_ver2); + + if (result != 0) { + return(result); + } + + /* Compare debian versions */ + return(version_compare_part(deb_ver1, deb_ver2)); +} + +int test_version(const unsigned int version1, const unsigned int version2, const unsigned int operator) +{ + const int version_result = version_compare(version1, version2); + switch(operator) { + case (VER_ANY): + return(TRUE); + case (VER_EQUAL): + if (version_result == 0) { + return(TRUE); + } + break; + case (VER_LESS): + if (version_result < 0) { + return(TRUE); + } + break; + case (VER_LESS_EQUAL): + if (version_result <= 0) { + return(TRUE); + } + break; + case (VER_MORE): + if (version_result > 0) { + return(TRUE); + } + break; + case (VER_MORE_EQUAL): + if (version_result >= 0) { + return(TRUE); + } + break; + } + return(FALSE); +} + + +int search_package_hashtable(const unsigned int name, const unsigned int version, const unsigned int operator) +{ + unsigned int probe_address = 0; + unsigned int probe_decrement = 0; + + make_hash(name_hashtable[name], &probe_address, &probe_decrement, PACKAGE_HASH_PRIME); + while(package_hashtable[probe_address] != NULL) { + if (package_hashtable[probe_address]->name == name) { + if (operator == VER_ANY) { + return(probe_address); + } + if (test_version(package_hashtable[probe_address]->version, version, operator)) { + return(probe_address); + } + } + probe_address -= probe_decrement; + if ((int)probe_address < 0) { + probe_address += PACKAGE_HASH_PRIME; + } + } + return(probe_address); +} + +/* + * Create one new node and one new edge for every dependency. + */ +void add_split_dependencies(common_node_t *parent_node, const char *whole_line, unsigned int edge_type) +{ + char *line = xstrdup(whole_line); + char *line2; + char *line_ptr1 = NULL; + char *line_ptr2 = NULL; + char *field; + char *field2; + char *version; + edge_t *edge; + int offset_ch; + int type; + + field = strtok_r(line, ",", &line_ptr1); + do { + line2 = xstrdup(field); + field2 = strtok_r(line2, "|", &line_ptr2); + if ((edge_type == EDGE_DEPENDS) && (strcmp(field, field2) != 0)) { + type = EDGE_OR_DEPENDS; + } + else if ((edge_type == EDGE_PRE_DEPENDS) && (strcmp(field, field2) != 0)) { + type = EDGE_OR_PRE_DEPENDS; + } else { + type = edge_type; + } + + do { + edge = (edge_t *) xmalloc(sizeof(edge_t)); + edge->type = type; + + /* Skip any extra leading spaces */ + field2 += strspn(field2, " "); + + /* Get dependency version info */ + version = strchr(field2, '('); + if (version == NULL) { + edge->operator = VER_ANY; + /* Get the versions hash number, adding it if the number isnt already in there */ + edge->version = search_name_hashtable("ANY"); + } else { + /* Skip leading ' ' or '(' */ + version += strspn(field2, " "); + version += strspn(version, "("); + /* Calculate length of any operator charactors */ + offset_ch = strspn(version, "<=>"); + /* Determine operator */ + if (offset_ch > 0) { + if (strncmp(version, "=", offset_ch) == 0) { + edge->operator = VER_EQUAL; + } + else if (strncmp(version, "<<", offset_ch) == 0) { + edge->operator = VER_LESS; + } + else if (strncmp(version, "<=", offset_ch) == 0) { + edge->operator = VER_LESS_EQUAL; + } + else if (strncmp(version, ">>", offset_ch) == 0) { + edge->operator = VER_MORE; + } + else if (strncmp(version, ">=", offset_ch) == 0) { + edge->operator = VER_MORE_EQUAL; + } else { + error_msg_and_die("Illegal operator\n"); + } + } + /* skip to start of version numbers */ + version += offset_ch; + version += strspn(version, " "); + + /* Truncate version at trailing ' ' or ')' */ + version[strcspn(version, " )")] = '\0'; + /* Get the versions hash number, adding it if the number isnt already in there */ + edge->version = search_name_hashtable(version); + } + + /* Get the dependency name */ + field2[strcspn(field2, " (")] = '\0'; + edge->name = search_name_hashtable(field2); + + /* link the new edge to the current node */ + parent_node->num_of_edges++; + parent_node->edge = xrealloc(parent_node->edge, sizeof(edge_t) * (parent_node->num_of_edges + 1)); + parent_node->edge[parent_node->num_of_edges - 1] = edge; + } while ((field2 = strtok_r(NULL, "|", &line_ptr2)) != NULL); + free(line2); + } while ((field = strtok_r(NULL, ",", &line_ptr1)) != NULL); + free(line); + + return; +} + +void free_package(common_node_t *node) +{ + int i; + if (node != NULL) { + for (i = 0; i < node->num_of_edges; i++) { + if (node->edge[i] != NULL) { + free(node->edge[i]); + } + } + if (node->edge != NULL) { + free(node->edge); + } + if (node != NULL) { + free(node); + } + } +} + +unsigned int fill_package_struct(char *control_buffer) +{ + common_node_t *new_node = (common_node_t *) xcalloc(1, sizeof(common_node_t)); + + char **field_name = xmalloc(sizeof(char *)); + char **field_value = xmalloc(sizeof(char *)); + int field_start = 0; + int num = -1; + int buffer_length = strlen(control_buffer); + + new_node->version = search_name_hashtable("unknown"); + while (field_start < buffer_length) { + field_start += read_package_field(&control_buffer[field_start], field_name, field_value); + + if (*field_name == NULL) { + goto fill_package_struct_cleanup; // Oh no, the dreaded goto statement !! + } + + if (strcmp(*field_name, "Package") == 0) { + new_node->name = search_name_hashtable(*field_value); + } + else if (strcmp(*field_name, "Version") == 0) { + new_node->version = search_name_hashtable(*field_value); + } + else if (strcmp(*field_name, "Pre-Depends") == 0) { + add_split_dependencies(new_node, *field_value, EDGE_PRE_DEPENDS); + } + else if (strcmp(*field_name, "Depends") == 0) { + add_split_dependencies(new_node, *field_value, EDGE_DEPENDS); + } + else if (strcmp(*field_name, "Replaces") == 0) { + add_split_dependencies(new_node, *field_value, EDGE_REPLACES); + } + else if (strcmp(*field_name, "Provides") == 0) { + add_split_dependencies(new_node, *field_value, EDGE_PROVIDES); + } + else if (strcmp(*field_name, "Conflicts") == 0) { + add_split_dependencies(new_node, *field_value, EDGE_CONFLICTS); + } + else if (strcmp(*field_name, "Suggests") == 0) { + add_split_dependencies(new_node, *field_value, EDGE_SUGGESTS); + } + else if (strcmp(*field_name, "Recommends") == 0) { + add_split_dependencies(new_node, *field_value, EDGE_RECOMMENDS); + } + else if (strcmp(*field_name, "Enhances") == 0) { + add_split_dependencies(new_node, *field_value, EDGE_ENHANCES); + } +fill_package_struct_cleanup: + if (*field_name) { + free(*field_name); + } + if (*field_value) { + free(*field_value); + } + } + free(field_name); + free(field_value); + + if (new_node->version == search_name_hashtable("unknown")) { + free_package(new_node); + return(-1); + } + num = search_package_hashtable(new_node->name, new_node->version, VER_EQUAL); + if (package_hashtable[num] == NULL) { + package_hashtable[num] = new_node; + } else { + free_package(new_node); + } + return(num); +} + +/* if num = 1, it returns the want status, 2 returns flag, 3 returns status */ +unsigned int get_status(const unsigned int status_node, const int num) +{ + char *status_string = name_hashtable[status_hashtable[status_node]->status]; + char *state_sub_string; + unsigned int state_sub_num; + int len; + int i; + + /* set tmp_string to point to the start of the word number */ + for (i = 1; i < num; i++) { + /* skip past a word */ + status_string += strcspn(status_string, " "); + /* skip past the seperating spaces */ + status_string += strspn(status_string, " "); + } + len = strcspn(status_string, " \n\0"); + state_sub_string = xstrndup(status_string, len); + state_sub_num = search_name_hashtable(state_sub_string); + free(state_sub_string); + return(state_sub_num); +} + +void set_status(const unsigned int status_node_num, const char *new_value, const int position) +{ + const unsigned int new_value_len = strlen(new_value); + const unsigned int new_value_num = search_name_hashtable(new_value); + unsigned int want = get_status(status_node_num, 1); + unsigned int flag = get_status(status_node_num, 2); + unsigned int status = get_status(status_node_num, 3); + int want_len = strlen(name_hashtable[want]); + int flag_len = strlen(name_hashtable[flag]); + int status_len = strlen(name_hashtable[status]); + char *new_status; + + switch (position) { + case (1): + want = new_value_num; + want_len = new_value_len; + break; + case (2): + flag = new_value_num; + flag_len = new_value_len; + break; + case (3): + status = new_value_num; + status_len = new_value_len; + break; + default: + error_msg_and_die("DEBUG ONLY: this shouldnt happen"); + } + + new_status = (char *) xmalloc(want_len + flag_len + status_len + 3); + sprintf(new_status, "%s %s %s", name_hashtable[want], name_hashtable[flag], name_hashtable[status]); + status_hashtable[status_node_num]->status = search_name_hashtable(new_status); + free(new_status); + return; +} + +void index_status_file(const char *filename) +{ + FILE *status_file; + char *control_buffer; + char *status_line; + status_node_t *status_node = NULL; + unsigned int status_num; + + status_file = xfopen(filename, "r"); + while ((control_buffer = fgets_str(status_file, "\n\n")) != NULL) { + const unsigned int package_num = fill_package_struct(control_buffer); + if (package_num != -1) { + status_node = xmalloc(sizeof(status_node_t)); + /* fill_package_struct doesnt handle the status field */ + status_line = strstr(control_buffer, "Status:"); + if (status_line != NULL) { + status_line += 7; + status_line += strspn(status_line, " \n\t"); + status_line = xstrndup(status_line, strcspn(status_line, "\n\0")); + status_node->status = search_name_hashtable(status_line); + free(status_line); + } + status_node->package = package_num; + status_num = search_status_hashtable(name_hashtable[package_hashtable[status_node->package]->name]); + status_hashtable[status_num] = status_node; + } + free(control_buffer); + } + fclose(status_file); + return; +} + + +char *get_depends_field(common_node_t *package, const int depends_type) +{ + char *depends = NULL; + char *old_sep = (char *)xcalloc(1, 3); + char *new_sep = (char *)xcalloc(1, 3); + int line_size = 0; + int depends_size; + + int i; + + for (i = 0; i < package->num_of_edges; i++) { + if ((package->edge[i]->type == EDGE_OR_PRE_DEPENDS) || + (package->edge[i]->type == EDGE_OR_DEPENDS)) { + } + + if ((package->edge[i]->type == depends_type) || + (package->edge[i]->type == depends_type + 1)) { + /* Check if its the first time through */ + + depends_size = 8 + strlen(name_hashtable[package->edge[i]->name]) + + strlen(name_hashtable[package->edge[i]->version]); + line_size += depends_size; + depends = (char *) xrealloc(depends, line_size + 1); + + /* Check to see if this dependency is the type we are looking for + * +1 to check for 'extra' types, e.g. ored dependecies */ + strcpy(old_sep, new_sep); + if (package->edge[i]->type == depends_type) { + strcpy(new_sep, ", "); + } + else if (package->edge[i]->type == depends_type + 1) { + strcpy(new_sep, "| "); + } + + if (depends_size == line_size) { + strcpy(depends, ""); + } else { + if ((strcmp(old_sep, "| ") == 0) && (strcmp(new_sep, "| ") == 0)) { + strcat(depends, " | "); + } else { + strcat(depends, ", "); + } + } + + strcat(depends, name_hashtable[package->edge[i]->name]); + if (strcmp(name_hashtable[package->edge[i]->version], "NULL") != 0) { + if (package->edge[i]->operator == VER_EQUAL) { + strcat(depends, " (= "); + } + else if (package->edge[i]->operator == VER_LESS) { + strcat(depends, " (<< "); + } + else if (package->edge[i]->operator == VER_LESS_EQUAL) { + strcat(depends, " (<= "); + } + else if (package->edge[i]->operator == VER_MORE) { + strcat(depends, " (>> "); + } + else if (package->edge[i]->operator == VER_MORE_EQUAL) { + strcat(depends, " (>= "); + } else { + strcat(depends, " ("); + } + strcat(depends, name_hashtable[package->edge[i]->version]); + strcat(depends, ")"); + } + } + } + return(depends); +} + +void write_buffer_no_status(FILE *new_status_file, const char *control_buffer) +{ + char *name; + char *value; + int start = 0; + while (1) { + start += read_package_field(&control_buffer[start], &name, &value); + if (name == NULL) { + break; + } + if (strcmp(name, "Status") != 0) { + fprintf(new_status_file, "%s: %s\n", name, value); + } + } + return; +} + +/* This could do with a cleanup */ +void write_status_file(deb_file_t **deb_file) +{ + FILE *old_status_file = xfopen("/var/lib/dpkg/status", "r"); + FILE *new_status_file = xfopen("/var/lib/dpkg/status.udeb", "w"); + char *package_name; + char *status_from_file; + char *control_buffer = NULL; + char *tmp_string; + int status_num; + int field_start = 0; + int write_flag; + int i = 0; + + /* Update previously known packages */ + while ((control_buffer = fgets_str(old_status_file, "\n\n")) != NULL) { + tmp_string = strstr(control_buffer, "Package:") + 8; + tmp_string += strspn(tmp_string, " \n\t"); + package_name = xstrndup(tmp_string, strcspn(tmp_string, "\n\0")); + write_flag = FALSE; + tmp_string = strstr(control_buffer, "Status:"); + if (tmp_string != NULL) { + /* Seperate the status value from the control buffer */ + tmp_string += 7; + tmp_string += strspn(tmp_string, " \n\t"); + status_from_file = xstrndup(tmp_string, strcspn(tmp_string, "\n")); + } else { + status_from_file = NULL; + } + + /* Find this package in the status hashtable */ + status_num = search_status_hashtable(package_name); + if (status_hashtable[status_num] != NULL) { + const char *status_from_hashtable = name_hashtable[status_hashtable[status_num]->status]; + if (strcmp(status_from_file, status_from_hashtable) != 0) { + /* New status isnt exactly the same as old status */ + const int state_status = get_status(status_num, 3); + if ((strcmp("installed", name_hashtable[state_status]) == 0) || + (strcmp("unpacked", name_hashtable[state_status]) == 0)) { + /* We need to add the control file from the package */ + i = 0; + while(deb_file[i] != NULL) { + if (strcmp(package_name, name_hashtable[package_hashtable[deb_file[i]->package]->name]) == 0) { + /* Write a status file entry with a modified status */ + /* remove trailing \n's */ + write_buffer_no_status(new_status_file, deb_file[i]->control_file); + set_status(status_num, "ok", 2); + fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]); + write_flag = TRUE; + break; + } + i++; + } + /* This is temperary, debugging only */ + if (deb_file[i] == NULL) { + error_msg_and_die("ALERT: Couldnt find a control file, your status file may be broken, status may be incorrect for %s", package_name); + } + } + else if (strcmp("not-installed", name_hashtable[state_status]) == 0) { + /* Only write the Package, Status, Priority and Section lines */ + fprintf(new_status_file, "Package: %s\n", package_name); + fprintf(new_status_file, "Status: %s\n", status_from_hashtable); + + while (1) { + char *field_name; + char *field_value; + field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value); + if (field_name == NULL) { + break; + } + if ((strcmp(field_name, "Priority") == 0) || + (strcmp(field_name, "Section") == 0)) { + fprintf(new_status_file, "%s: %s\n", field_name, field_value); + } + } + write_flag = TRUE; + fputs("\n", new_status_file); + } + else if (strcmp("config-files", name_hashtable[state_status]) == 0) { + /* only change the status line */ + while (1) { + char *field_name; + char *field_value; + field_start += read_package_field(&control_buffer[field_start], &field_name, &field_value); + if (field_name == NULL) { + break; + } + /* Setup start point for next field */ + if (strcmp(field_name, "Status") == 0) { + fprintf(new_status_file, "Status: %s\n", status_from_hashtable); + } else { + fprintf(new_status_file, "%s: %s\n", field_name, field_value); + } + } + write_flag = TRUE; + fputs("\n", new_status_file); + } + } + } + /* If the package from the status file wasnt handle above, do it now*/ + if (write_flag == FALSE) { + fprintf(new_status_file, "%s\n\n", control_buffer); + } + + if (status_from_file != NULL) { + free(status_from_file); + } + free(package_name); + free(control_buffer); + } + + /* Write any new packages */ + for(i = 0; deb_file[i] != NULL; i++) { + status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[i]->package]->name]); + if (strcmp("reinstreq", name_hashtable[get_status(status_num, 2)]) == 0) { + write_buffer_no_status(new_status_file, deb_file[i]->control_file); + set_status(status_num, "ok", 2); + fprintf(new_status_file, "Status: %s\n\n", name_hashtable[status_hashtable[status_num]->status]); + } + } + fclose(old_status_file); + fclose(new_status_file); + + + /* Create a seperate backfile to dpkg */ + if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) { + struct stat stat_buf; + if (stat("/var/lib/dpkg/status", &stat_buf) == 0) { + error_msg_and_die("Couldnt create backup status file"); + } + /* Its ok if renaming the status file fails becasue status + * file doesnt exist, maybe we are starting from scratch */ + error_msg("No status file found, creating new one"); + } + + if (rename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status") == -1) { + error_msg_and_die("DANGER: Couldnt create status file, you need to manually repair your status file"); + } +} + +int check_deps(deb_file_t **deb_file, int deb_start, int dep_max_count) +{ + int *conflicts = NULL; + int conflicts_num = 0; + int state_status; + int state_flag; + int state_want; + unsigned int status_package_num; + int i = deb_start; + int j, k; + + /* Check for conflicts + * TODO: TEST if conflicts with other packages to be installed + * + * Add install packages and the packages they provide + * to the list of files to check conflicts for + */ + + /* Create array of package numbers to check against + * installed package for conflicts*/ + while (deb_file[i] != NULL) { + const unsigned int package_num = deb_file[i]->package; + conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1)); + conflicts[conflicts_num] = package_num; + conflicts_num++; + /* add provides to conflicts list */ + for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) { + if (package_hashtable[package_num]->edge[j]->type == EDGE_PROVIDES) { + const int conflicts_package_num = search_package_hashtable( + package_hashtable[package_num]->edge[j]->name, + package_hashtable[package_num]->edge[j]->version, + package_hashtable[package_num]->edge[j]->operator); + if (package_hashtable[conflicts_package_num] == NULL) { + /* create a new package */ + common_node_t *new_node = (common_node_t *) xmalloc(sizeof(common_node_t)); + new_node->name = package_hashtable[package_num]->edge[j]->name; + new_node->version = package_hashtable[package_num]->edge[j]->version; + new_node->num_of_edges = 0; + new_node->edge = NULL; + package_hashtable[conflicts_package_num] = new_node; + } + conflicts = xrealloc(conflicts, sizeof(int) * (conflicts_num + 1)); + conflicts[conflicts_num] = conflicts_package_num; + conflicts_num++; + } + } + i++; + } + + /* Check conflicts */ + for (i = 0; i < conflicts_num; i++) { + /* Check for conflicts */ + for (j = 0; j < STATUS_HASH_PRIME; j++) { + if (status_hashtable[j] == NULL) { + continue; + } + state_flag = get_status(j, 2); + state_status = get_status(j, 3); + if ((state_status != search_name_hashtable("installed")) + && (state_flag != search_name_hashtable("want-install"))) { + continue; + } + status_package_num = status_hashtable[j]->package; + for (k = 0; k < package_hashtable[status_package_num]->num_of_edges; k++) { + const edge_t *package_edge = package_hashtable[status_package_num]->edge[k]; + if (package_edge->type != EDGE_CONFLICTS) { + continue; + } + if (package_edge->name != package_hashtable[conflicts[i]]->name) { + continue; + } + /* There is a conflict against the package name + * check if version conflict as well */ + if (test_version(package_hashtable[deb_file[i]->package]->version, + package_edge->version, package_edge->operator)) { + error_msg_and_die("Package %s conflict with %s", + name_hashtable[package_hashtable[deb_file[i]->package]->name], + name_hashtable[package_hashtable[status_package_num]->name]); + } + } + } + } + + /* Check dependendcies */ + i = 0; + while (deb_file[i] != NULL) { + const common_node_t *package_node = package_hashtable[deb_file[i]->package]; + int status_num = 0; + + for (j = 0; j < package_hashtable[deb_file[i]->package]->num_of_edges; j++) { + const edge_t *package_edge = package_node->edge[j]; + const unsigned int package_num = search_package_hashtable(package_edge->name, + package_edge->version, package_edge->operator); + + status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]); + state_status = get_status(status_num, 3); + state_want = get_status(status_num, 1); + switch (package_edge->type) { + case(EDGE_PRE_DEPENDS): + case(EDGE_OR_PRE_DEPENDS): + /* It must be already installed */ + /* NOTE: This is untested, nothing apropriate in my status file */ + if ((package_hashtable[package_num] == NULL) || (state_status != search_name_hashtable("installed"))) { + error_msg_and_die("Package %s pre-depends on %s, but it is not installed", + name_hashtable[package_node->name], + name_hashtable[package_edge->name]); + } + break; + case(EDGE_DEPENDS): + case(EDGE_OR_DEPENDS): + /* It must be already installed, or to be installed */ + if ((package_hashtable[package_num] == NULL) || + ((state_status != search_name_hashtable("installed")) && + (state_want != search_name_hashtable("want_install")))) { + error_msg_and_die("Package %s depends on %s, but it is not installed, or flaged to be installed", + name_hashtable[package_node->name], + name_hashtable[package_edge->name]); + } + break; + } + } + i++; + } + free(conflicts); + return(TRUE); +} + +char **create_list(const char *filename) +{ + FILE *list_stream; + char **file_list = xmalloc(sizeof(char *)); + char *line = NULL; + char *last_char; + int length = 0; + int count = 0; + + /* dont use [xw]fopen here, handle error ourself */ + list_stream = fopen(filename, "r"); + if (list_stream == NULL) { + *file_list = NULL; + return(file_list); + } + while (getline(&line, &length, list_stream) != -1) { + file_list = xrealloc(file_list, sizeof(char *) * (length + 1)); + last_char = last_char_is(line, '\n'); + if (last_char) { + *last_char = '\0'; + } + file_list[count] = xstrdup(line); + free(line); + count++; + length = 0; + } + fclose(list_stream); + + if (count == 0) { + return(NULL); + } else { + file_list[count] = NULL; + return(file_list); + } +} + +/* maybe i should try and hook this into remove_file.c somehow */ +int remove_file_array(char **remove_names, char **exclude_names) +{ + struct stat path_stat; + int match_flag; + int remove_flag = FALSE; + int i,j; + + if (remove_names == NULL) { + return(FALSE); + } + for (i = 0; remove_names[i] != NULL; i++) { + match_flag = FALSE; + if (exclude_names != NULL) { + for (j = 0; exclude_names[j] != 0; j++) { + if (strcmp(remove_names[i], exclude_names[j]) == 0) { + match_flag = TRUE; + break; + } + } + } + if (!match_flag) { + if (lstat(remove_names[i], &path_stat) < 0) { + continue; + } + if (S_ISDIR(path_stat.st_mode)) { + if (rmdir(remove_names[i]) != -1) { + remove_flag = TRUE; + } + } else { + if (unlink(remove_names[i]) != -1) { + remove_flag = TRUE; + } + } + } + } + return(remove_flag); +} + +int run_package_script(const char *package_name, const char *script_type) +{ + struct stat path_stat; + char *script_path; + + script_path = xmalloc(strlen(package_name) + strlen(script_type) + 21); + sprintf(script_path, "/var/lib/dpkg/info/%s.%s", package_name, script_type); + + /* If the file doesnt exist is isnt a fatal */ + if (lstat(script_path, &path_stat) < 0) { + free(script_path); + return(EXIT_SUCCESS); + } else { + free(script_path); + return(system(script_path)); + } +} + +void all_control_list(char **remove_files, const char *package_name) +{ + const char *all_extensions[11] = {"preinst", "postinst", "prerm", "postrm", + "list", "md5sums", "shlibs", "conffiles", "config", "templates", NULL }; + int i; + + /* Create a list of all /var/lib/dpkg/info/ files */ + for(i = 0; i < 10; i++) { + remove_files[i] = xmalloc(strlen(package_name) + strlen(all_extensions[i]) + 21); + sprintf(remove_files[i], "/var/lib/dpkg/info/%s.%s", package_name, all_extensions[i]); + } + remove_files[10] = NULL; +} + +void remove_package(const unsigned int package_num) +{ + const char *package_name = name_hashtable[package_hashtable[package_num]->name]; + const unsigned int status_num = search_status_hashtable(package_name); + const int package_name_length = strlen(package_name); + char **remove_files; + char **exclude_files; + char list_name[package_name_length + 25]; + char conffile_name[package_name_length + 30]; + int return_value; + + printf("Removing %s ...\n", package_name); + + /* run prerm script */ + return_value = run_package_script(package_name, "prerm"); + if (return_value == -1) { + error_msg_and_die("script failed, prerm failure"); + } + + /* Create a list of files to remove, and a seperate list of those to keep */ + sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name); + remove_files = create_list(list_name); + + sprintf(conffile_name, "/var/lib/dpkg/info/%s.conffiles", package_name); + exclude_files = create_list(conffile_name); + + /* Some directories cant be removed straight away, so do multiple passes */ + while (remove_file_array(remove_files, exclude_files) == TRUE); + + /* Create a list of all /var/lib/dpkg/info/ files */ + remove_files = xmalloc(11); + all_control_list(remove_files, package_name); + + /* Create a list of files in /var/lib/dpkg/info/.* to keep */ + exclude_files = xmalloc(sizeof(char*) * 3); + exclude_files[0] = xstrdup(conffile_name); + exclude_files[1] = xmalloc(package_name_length + 27); + sprintf(exclude_files[1], "/var/lib/dpkg/info/%s.postrm", package_name); + exclude_files[2] = NULL; + + remove_file_array(remove_files, exclude_files); + + /* rename .conffile to .list */ + rename(conffile_name, list_name); + + /* Change package status */ + set_status(status_num, "deinstall", 1); + set_status(status_num, "config-files", 3); +} + +void purge_package(const unsigned int package_num) +{ + const char *package_name = name_hashtable[package_hashtable[package_num]->name]; + const unsigned int status_num = search_status_hashtable(package_name); + char **remove_files; + char **exclude_files; + char list_name[strlen(package_name) + 25]; + + /* run prerm script */ + if (run_package_script(package_name, "prerm") == -1) { + error_msg_and_die("script failed, prerm failure"); + } + + /* Create a list of files to remove */ + sprintf(list_name, "/var/lib/dpkg/info/%s.list", package_name); + remove_files = create_list(list_name); + + exclude_files = xmalloc(1); + exclude_files[0] = NULL; + + /* Some directories cant be removed straight away, so do multiple passes */ + while (remove_file_array(remove_files, exclude_files) == TRUE); + + /* Create a list of all /var/lib/dpkg/info/ files */ + remove_files = xmalloc(11); + all_control_list(remove_files, package_name); + remove_file_array(remove_files, exclude_files); + + /* run postrm script */ + if (run_package_script(package_name, "postrm") == -1) { + error_msg_and_die("postrm fialure.. set status to what?"); + } + + /* Change package status */ + set_status(status_num, "purge", 1); + set_status(status_num, "not-installed", 3); +} + +void unpack_package(deb_file_t *deb_file) +{ + const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name]; + const unsigned int status_num = search_status_hashtable(package_name); + const unsigned int status_package_num = status_hashtable[status_num]->status; + + FILE *out_stream; + char *info_prefix; + + /* If existing version, remove it first */ + if (strcmp(name_hashtable[get_status(status_num, 3)], "installed") == 0) { + /* Package is already installed, remove old version first */ + printf("Preparing to replace %s %s (using %s) ...\n", package_name, + name_hashtable[package_hashtable[status_package_num]->version], + deb_file->filename); + remove_package(status_package_num); + } else { + printf("Unpacking %s (from %s) ...\n", package_name, deb_file->filename); + } + + /* Extract control.tar.gz to /var/lib/dpkg/info/.filename */ + info_prefix = (char *) xmalloc(sizeof(package_name) + 20 + 4 + 1); + sprintf(info_prefix, "/var/lib/dpkg/info/%s.", package_name); + deb_extract(deb_file->filename, stdout, (extract_quiet | extract_control_tar_gz | extract_all_to_fs), info_prefix, NULL); + + /* Extract data.tar.gz to the root directory */ + deb_extract(deb_file->filename, stdout, (extract_quiet | extract_data_tar_gz | extract_all_to_fs), "/", NULL); + + /* Create the list file */ + strcat(info_prefix, "list"); + out_stream = xfopen(info_prefix, "w"); + deb_extract(deb_file->filename, out_stream, (extract_quiet | extract_data_tar_gz | extract_list), NULL, NULL); + fclose(out_stream); + + /* change status */ + set_status(status_num, "install", 1); + set_status(status_num, "unpacked", 3); + + free(info_prefix); +} + +void configure_package(deb_file_t *deb_file) +{ + const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name]; + const char *package_version = name_hashtable[package_hashtable[deb_file->package]->version]; + const int status_num = search_status_hashtable(package_name); + int return_value; + + printf("Setting up %s (%s)\n", package_name, package_version); + + /* Run the preinst prior to extracting */ + return_value = run_package_script(package_name, "postinst"); + if (return_value == -1) { + /* TODO: handle failure gracefully */ + error_msg_and_die("postrm failure.. set status to what?"); + } + /* Change status to reflect success */ + set_status(status_num, "install", 1); + set_status(status_num, "installed", 3); +} + +extern int dpkg_main(int argc, char **argv) +{ + deb_file_t **deb_file = NULL; + status_node_t *status_node; + int opt = 0; + int package_num; + int dpkg_opt = 0; + int deb_count = 0; + int state_status; + int status_num; + int i; + + while ((opt = getopt(argc, argv, "CF:ilPru")) != -1) { + switch (opt) { + case 'C': // equivalent to --configure in official dpkg + dpkg_opt |= dpkg_opt_configure; + dpkg_opt |= dpkg_opt_package_name; + break; + case 'F': // equivalent to --force in official dpkg + if (strcmp(optarg, "depends") == 0) { + dpkg_opt |= dpkg_opt_force_ignore_depends; + } + case 'i': + dpkg_opt |= dpkg_opt_install; + dpkg_opt |= dpkg_opt_filename; + break; + case 'l': + dpkg_opt |= dpkg_opt_list_installed; + case 'P': + dpkg_opt |= dpkg_opt_purge; + dpkg_opt |= dpkg_opt_package_name; + break; + case 'r': + dpkg_opt |= dpkg_opt_remove; + dpkg_opt |= dpkg_opt_package_name; + break; + case 'u': /* Equivalent to --unpack in official dpkg */ + dpkg_opt |= dpkg_opt_unpack; + dpkg_opt |= dpkg_opt_filename; + break; + default: + show_usage(); + } + } + + if ((argc == optind) || (dpkg_opt == 0)) { + show_usage(); + } + + puts("(Reading database ... xxxxx files and directories installed.)"); + index_status_file("/var/lib/dpkg/status"); + + /* Read arguments and store relevant info in structs */ + deb_file = xmalloc(sizeof(deb_file_t)); + while (optind < argc) { + deb_file[deb_count] = (deb_file_t *) xmalloc(sizeof(deb_file_t)); + if (dpkg_opt & dpkg_opt_filename) { + deb_file[deb_count]->filename = xstrdup(argv[optind]); + deb_file[deb_count]->control_file = deb_extract(argv[optind], stdout, (extract_control_tar_gz | extract_one_to_buffer), NULL, "./control"); + if (deb_file[deb_count]->control_file == NULL) { + error_msg_and_die("Couldnt extract control file"); + } + package_num = fill_package_struct(deb_file[deb_count]->control_file); + + if (package_num == -1) { + error_msg("Invalid control file in %s", argv[optind]); + continue; + } + deb_file[deb_count]->package = (unsigned int) package_num; + /* Add the package to the status hashtable */ + if ((dpkg_opt & dpkg_opt_unpack) || (dpkg_opt & dpkg_opt_install)) { + status_node = (status_node_t *) xmalloc(sizeof(status_node_t)); + status_node->package = deb_file[deb_count]->package; + /* use reinstreq isnt changed to "ok" until the package control info + * is written to the status file*/ + status_node->status = search_name_hashtable("install reinstreq not-installed"); + + status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); + status_hashtable[status_num] = status_node; + } + } + else if (dpkg_opt & dpkg_opt_package_name) { + deb_file[deb_count]->filename = NULL; + deb_file[deb_count]->control_file = NULL; + deb_file[deb_count]->package = search_package_hashtable( + search_name_hashtable(argv[optind]), + search_name_hashtable("ANY"), VER_ANY); + if (package_hashtable[deb_file[deb_count]->package] == NULL) { + error_msg_and_die("Package %s is uninstalled or unknown\n", argv[optind]); + } + state_status = get_status(search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]), 3); + + /* check package status is "installed" */ + if (dpkg_opt & dpkg_opt_remove) { + if ((strcmp(name_hashtable[state_status], "not-installed") == 0) || + (strcmp(name_hashtable[state_status], "config-files") == 0)) { + error_msg_and_die("%s is already removed.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); + } + } + else if (dpkg_opt & dpkg_opt_purge) { + /* if package status is "conf-files" then its ok */ + if (strcmp(name_hashtable[state_status], "not-installed") == 0) { + error_msg_and_die("%s is already purged.", name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); + } + } + } + deb_count++; + optind++; + } + deb_file[deb_count] = NULL; + + /* Check that the deb file arguments are installable */ + /* TODO: check dependencies before removing */ + if ((dpkg_opt & dpkg_opt_force_ignore_depends) != dpkg_opt_force_ignore_depends) { + if (!check_deps(deb_file, 0, deb_count)) { + error_msg_and_die("Dependency check failed"); + } + } + + for (i = 0; i < deb_count; i++) { + /* Remove or purge packages */ + if (dpkg_opt & dpkg_opt_remove) { + remove_package(deb_file[i]->package); + } + else if (dpkg_opt & dpkg_opt_purge) { + purge_package(deb_file[i]->package); + } + else if (dpkg_opt & dpkg_opt_unpack) { + unpack_package(deb_file[i]); + } + else if (dpkg_opt & dpkg_opt_install) { + unpack_package(deb_file[i]); + configure_package(deb_file[i]); + } + else if (dpkg_opt & dpkg_opt_configure) { + configure_package(deb_file[i]); + } + } + + write_status_file(deb_file); + + for (i = 0; i < deb_count; i++) { + free(deb_file[i]->control_file); + free(deb_file[i]->filename); + free(deb_file[i]); + } + free(deb_file); + + for (i = 0; i < NAME_HASH_PRIME; i++) { + if (name_hashtable[i] != NULL) { + free(name_hashtable[i]); + } + } + + for (i = 0; i < PACKAGE_HASH_PRIME; i++) { + free_package(package_hashtable[i]); + } + + for (i = 0; i < STATUS_HASH_PRIME; i++) { + if (status_hashtable[i] != NULL) { + free(status_hashtable[i]); + } + } + + return(EXIT_FAILURE); +} + diff --git a/dpkg_deb.c b/dpkg_deb.c new file mode 100644 index 000000000..a933c6948 --- /dev/null +++ b/dpkg_deb.c @@ -0,0 +1,130 @@ +/* + * 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. + */ + +#include +#include +#include +#include "busybox.h" + +extern int dpkg_deb_main(int argc, char **argv) +{ + char *prefix = NULL; + char *filename = NULL; + char *output_buffer = NULL; + int opt = 0; + int arg_type = 0; + int deb_extract_funct = extract_create_leading_dirs | extract_unconditional; + + const int arg_type_prefix = 1; + const int arg_type_field = 2; + const int arg_type_filename = 4; +// const int arg_type_un_ar_gz = 8; + + while ((opt = getopt(argc, argv, "ceftXxI")) != -1) { + switch (opt) { + case 'c': + deb_extract_funct |= extract_data_tar_gz; + deb_extract_funct |= extract_verbose_list; + break; + case 'e': + arg_type = arg_type_prefix; + deb_extract_funct |= extract_control_tar_gz; + deb_extract_funct |= extract_all_to_fs; + break; + case 'f': + arg_type = arg_type_field; + deb_extract_funct |= extract_control_tar_gz; + deb_extract_funct |= extract_one_to_buffer; + filename = xstrdup("./control"); + break; + case 't': /* --fsys-tarfile, i just made up this short name */ + /* Integrate the functionality needed with some code from ar.c */ + error_msg_and_die("Option disabled"); +// arg_type = arg_type_un_ar_gz; + break; + case 'X': + arg_type = arg_type_prefix; + deb_extract_funct |= extract_data_tar_gz; + deb_extract_funct |= extract_all_to_fs; + deb_extract_funct |= extract_list; + case 'x': + arg_type = arg_type_prefix; + deb_extract_funct |= extract_data_tar_gz; + deb_extract_funct |= extract_all_to_fs; + break; + case 'I': + arg_type = arg_type_filename; + deb_extract_funct |= extract_control_tar_gz; + deb_extract_funct |= extract_one_to_buffer; + break; + default: + show_usage(); + } + } + + if (optind == argc) { + show_usage(); + } + + /* Workout where to extract the files */ + if (arg_type == arg_type_prefix) { + /* argument is a dir name */ + if ((optind + 1) == argc ) { + prefix = xstrdup("./DEBIAN/"); + } else { + prefix = (char *) xmalloc(strlen(argv[optind + 1]) + 2); + strcpy(prefix, argv[optind + 1]); + /* Make sure the directory has a trailing '/' */ + if (last_char_is(prefix, '/') == NULL) { + strcat(prefix, "/"); + } + } + mkdir(prefix, 0777); + } + + if (arg_type == arg_type_filename) { + if ((optind + 1) != argc) { + filename = xstrdup(argv[optind + 1]); + } else { + error_msg_and_die("-I currently requires a filename to be specified"); + } + } + + output_buffer = deb_extract(argv[optind], stdout, deb_extract_funct, prefix, filename); + + if ((arg_type == arg_type_filename) && (output_buffer != NULL)) { + puts(output_buffer); + } + else if (arg_type == arg_type_field) { + char *field = NULL; + char *name; + char *value; + int field_start = 0; + + while (1) { + field_start += read_package_field(&output_buffer[field_start], &name, &value); + if (name == NULL) { + break; + } + if (strcmp(name, argv[optind + 1]) == 0) { + puts(value); + } + free(field); + } + } + + return(EXIT_SUCCESS); +} diff --git a/du.c b/du.c new file mode 100644 index 000000000..d2b85b404 --- /dev/null +++ b/du.c @@ -0,0 +1,194 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini du implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and John Beppu + * 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + + +#ifdef BB_FEATURE_HUMAN_READABLE +static unsigned long disp_hr = KILOBYTE; +#endif + +typedef void (Display) (long, char *); + +static int du_depth = 0; +static int count_hardlinks = 0; +static int one_file_system = 0; +static dev_t dir_dev = 0; + +static Display *print; + +static void print_normal(long size, char *filename) +{ +#ifdef BB_FEATURE_HUMAN_READABLE + printf("%s\t%s\n", make_human_readable_str(size<<10, 1, disp_hr), filename); +#else + printf("%ld\t%s\n", size, filename); +#endif +} + +static void print_summary(long size, char *filename) +{ + if (du_depth == 1) { + print_normal(size, filename); + } +} + +/* tiny recursive du */ +static long du(char *filename) +{ + struct stat statbuf; + long sum; + + if ((lstat(filename, &statbuf)) != 0) { + perror_msg("%s", filename); + return 0; + } + if (du_depth == 0) + dir_dev = statbuf.st_dev; + else if (one_file_system && dir_dev != statbuf.st_dev) + return 0; + + du_depth++; + sum = (statbuf.st_blocks >> 1); + + /* Don't add in stuff pointed to by symbolic links */ + if (S_ISLNK(statbuf.st_mode)) { + sum = 0L; + if (du_depth == 1) { + } + } + if (S_ISDIR(statbuf.st_mode)) { + DIR *dir; + struct dirent *entry; + char *newfile; + + dir = opendir(filename); + if (!dir) { + du_depth--; + return 0; + } + + newfile = last_char_is(filename, '/'); + if (newfile) + *newfile = '\0'; + + while ((entry = readdir(dir))) { + char *name = entry->d_name; + + if ((strcmp(name, "..") == 0) + || (strcmp(name, ".") == 0)) { + continue; + } + newfile = concat_path_file(filename, name); + sum += du(newfile); + free(newfile); + } + closedir(dir); + print(sum, filename); + } + else if (statbuf.st_nlink > 1 && !count_hardlinks) { + /* Add files with hard links only once */ + if (is_in_ino_dev_hashtable(&statbuf, NULL)) { + sum = 0L; + if (du_depth == 1) + print(sum, filename); + } + else { + add_to_ino_dev_hashtable(&statbuf, NULL); + } + } + du_depth--; + return sum; +} + +int du_main(int argc, char **argv) +{ + int status = EXIT_SUCCESS; + int i; + int c; + + /* default behaviour */ + print = print_normal; + + /* parse argv[] */ + while ((c = getopt(argc, argv, "slx" +#ifdef BB_FEATURE_HUMAN_READABLE +"hm" +#endif +"k")) != EOF) { + switch (c) { + case 's': + print = print_summary; + break; + case 'l': + count_hardlinks = 1; + break; + case 'x': + one_file_system = 1; + break; +#ifdef BB_FEATURE_HUMAN_READABLE + case 'h': disp_hr = 0; break; + case 'm': disp_hr = MEGABYTE; break; +#endif + case 'k': break; + default: + show_usage(); + } + } + + /* go through remaining args (if any) */ + if (optind >= argc) { + if (du(".") == 0) + status = EXIT_FAILURE; + } else { + long sum; + + for (i=optind; i < argc; i++) { + sum = du(argv[i]); + if(is_directory(argv[i], FALSE, NULL)==FALSE) { + print_normal(sum, argv[i]); + } + reset_ino_dev_hashtable(); + } + } + + return status; +} + +/* $Id: du.c,v 1.53 2002/09/18 19:21:06 andersen Exp $ */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/dumpkmap.c b/dumpkmap.c new file mode 100644 index 000000000..22652a5e2 --- /dev/null +++ b/dumpkmap.c @@ -0,0 +1,95 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini dumpkmap implementation for busybox + * + * Copyright (C) Arne Bernin + * + * 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 "busybox.h" + +/* From */ +struct kbentry { + unsigned char kb_table; + unsigned char kb_index; + unsigned short kb_value; +}; +static const int KDGKBENT = 0x4B46; /* gets one entry in translation table */ + +/* From */ +static const int NR_KEYS = 128; +static const int MAX_NR_KEYMAPS = 256; + +int dumpkmap_main(int argc, char **argv) +{ + struct kbentry ke; + int i, j, fd; + char flags[MAX_NR_KEYMAPS], magic[] = "bkeymap"; + + if (argc>=2 && *argv[1]=='-') { + show_usage(); + } + + fd = open(CURRENT_VC, O_RDWR); + if (fd < 0) { + perror_msg("Error opening " CURRENT_VC); + return EXIT_FAILURE; + } + + write(1, magic, 7); + + for (i=0; i < MAX_NR_KEYMAPS; i++) flags[i]=0; + flags[0]=1; + flags[1]=1; + flags[2]=1; + flags[4]=1; + flags[5]=1; + flags[6]=1; + flags[8]=1; + flags[9]=1; + flags[10]=1; + flags[12]=1; + + /* dump flags */ + for (i=0; i < MAX_NR_KEYMAPS; i++) write(1,&flags[i],1); + + for (i = 0; i < MAX_NR_KEYMAPS; i++) { + if (flags[i] == 1) { + for (j = 0; j < NR_KEYS; j++) { + ke.kb_index = j; + ke.kb_table = i; + if (ioctl(fd, KDGKBENT, &ke) < 0) { + + error_msg("ioctl returned: %s, %s, %s, %xqq", strerror(errno),(char *)&ke.kb_index,(char *)&ke.kb_table,(int)&ke.kb_value); + } + else { + write(1,(void*)&ke.kb_value,2); + } + + } + } + } + close(fd); + return EXIT_SUCCESS; +} diff --git a/dutmp.c b/dutmp.c new file mode 100644 index 000000000..9b9124a07 --- /dev/null +++ b/dutmp.c @@ -0,0 +1,64 @@ +/* vi: set sw=4 ts=4: */ +/* + * public domain -- Dave 'Kill a Cop' Cinege + * + * dutmp + * Takes utmp formated file on stdin and dumps it's contents + * out in colon delimited fields. Easy to 'cut' for shell based + * versions of 'who', 'last', etc. IP Addr is output in hex, + * little endian on x86. + * + * Modified to support all sorts of libcs by + * Erik Andersen + */ + +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +extern int dutmp_main(int argc, char **argv) +{ + + int file; + struct utmp ut; + + if (argc<2) { + file = fileno(stdin); + } else if (*argv[1] == '-' ) { + show_usage(); + } else { + file = open(argv[1], O_RDONLY); + if (file < 0) { + perror_msg_and_die(io_error, argv[1]); + } + } + +/* Kludge around the fact that the binary format for utmp has changed. */ +#if __GNU_LIBRARY__ < 5 + /* Linux libc5 */ + while (read(file, (void*)&ut, sizeof(struct utmp))) { + printf("%d|%d|%s|%s|%s|%s|%s|%lx\n", + ut.ut_type, ut.ut_pid, ut.ut_line, + ut.ut_id, ut.ut_user, ut.ut_host, + ctime(&(ut.ut_time)), + (long)ut.ut_addr); + } +#else + /* Glibc, uClibc, etc. */ + while (read(file, (void*)&ut, sizeof(struct utmp))) { + printf("%d|%d|%s|%s|%s|%s|%d|%d|%ld|%ld|%ld|%x\n", + ut.ut_type, ut.ut_pid, ut.ut_line, + ut.ut_id, ut.ut_user, ut.ut_host, + ut.ut_exit.e_termination, ut.ut_exit.e_exit, + ut.ut_session, + ut.ut_tv.tv_sec, ut.ut_tv.tv_usec, + ut.ut_addr); + } +#endif + return EXIT_SUCCESS; +} diff --git a/echo.c b/echo.c new file mode 100644 index 000000000..31c031528 --- /dev/null +++ b/echo.c @@ -0,0 +1,152 @@ +/* vi: set sw=4 ts=4: */ +/* + * echo implementation for busybox + * + * 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 + * + * Original copyright notice is retained at the end of this file. + */ + +#include +#include +#include +#include "busybox.h" + +extern int +echo_main(int argc, char** argv) +{ + int nflag = 0; + int eflag = 0; + + /* Skip argv[0]. */ + argc--; + argv++; + + while (argc > 0 && *argv[0] == '-') + { + register char *temp; + register int ix; + + /* + * 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. + */ + temp = argv[0] + 1; + + for (ix = 0; temp[ix]; ix++) + { + if (strrchr("neE", temp[ix]) == 0) + goto just_echo; + } + + if (!*temp) + goto just_echo; + + /* + * All of the options in temp are valid options to echo. + * Handle them. + */ + while (*temp) + { + if (*temp == 'n') + nflag = 1; + else if (*temp == 'e') + eflag = 1; + else if (*temp == 'E') + eflag = 0; + else + goto just_echo; + + temp++; + } + argc--; + argv++; + } + +just_echo: + while (argc > 0) { + const char *arg = argv[0]; + register int c; + + while ((c = *arg++)) { + + /* Check for escape sequence. */ + if (c == '\\' && eflag && *arg) { + if (*arg == 'c') { + /* '\c' means cancel newline. */ + nflag = 1; + arg++; + continue; + } else { + c = process_escape_sequence(&arg); + } + } + + putchar(c); + } + argc--; + argv++; + if (argc > 0) + putchar(' '); + } + if (!nflag) + putchar('\n'); + fflush(stdout); + + return EXIT_SUCCESS; +} + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Kenneth Almquist. + * + * 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. + * + * California, Berkeley and its contributors. + * 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. + * + * @(#)echo.c 8.1 (Berkeley) 5/31/93 + */ diff --git a/env.c b/env.c new file mode 100644 index 000000000..40a6001da --- /dev/null +++ b/env.c @@ -0,0 +1,106 @@ +/* vi: set sw=4 ts=4: */ +/* + * env implementation for busybox + * + * 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 + * + * Original copyright notice is retained at the end of this file. + * + * Modified for BusyBox by Erik Andersen + */ + +#include +#include +#include +#include +#include +#include "busybox.h" + +extern int env_main(int argc, char** argv) +{ + char **ep, *p; + char *cleanenv[1]; + int ignore_environment = 0; + int ch; + + while ((ch = getopt(argc, argv, "+iu:")) != -1) { + switch(ch) { + case 'i': + ignore_environment = 1; + break; + case 'u': + unsetenv(optarg); + break; + default: + show_usage(); + } + } + if (optind != argc && !strcmp(argv[optind], "-")) { + ignore_environment = 1; + argv++; + } + if (ignore_environment) { + environ = cleanenv; + cleanenv[0] = NULL; + } + for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv) + if (putenv(*argv) < 0) + perror_msg_and_die("%s", *argv); + if (*argv) { + execvp(*argv, argv); + perror_msg_and_die("%s", *argv); + } + for (ep = environ; *ep; ep++) + puts(*ep); + return 0; +} + +/* + * Copyright (c) 1988, 1993, 1994 + * The 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. + */ + + diff --git a/expr.c b/expr.c new file mode 100644 index 000000000..d6cc82e3e --- /dev/null +++ b/expr.c @@ -0,0 +1,535 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini expr implementation for busybox + * + * based on GNU expr Mike Parker. + * Copyright (C) 86, 1991-1997, 1999 Free Software Foundation, Inc. + * + * Busybox modifications + * 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 + * + */ + +/* This program evaluates expressions. Each token (operator, operand, + * parenthesis) of the expression must be a seperate argument. The + * parser used is a reasonably general one, though any incarnation of + * it is language-specific. It is especially nice for expressions. + * + * No parse tree is needed; a new node is evaluated immediately. + * One function can handle multiple operators all of equal precedence, + * provided they all associate ((x op x) op x). */ + +/* no getopt needed */ + +#include +#include +#include +#include +#include +#include "busybox.h" + + +/* The kinds of value we can have. */ +enum valtype { + integer, + string +}; +typedef enum valtype TYPE; + +/* A value is.... */ +struct valinfo { + TYPE type; /* Which kind. */ + union { /* The value itself. */ + int 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) { + error_msg_and_die("too few arguments"); + } + + args = argv + 1; + + v = eval (); + if (*args) + error_msg_and_die ("syntax error"); + + if (v->type == integer) + printf ("%d\n", v->u.i); + else + puts (v->u.s); + + exit (null (v)); +} + +/* Return a VALUE for I. */ + +static VALUE *int_value (int i) +{ + VALUE *v; + + v = xmalloc (sizeof(VALUE)); + v->type = integer; + v->u.i = i; + return v; +} + +/* Return a VALUE for S. */ + +static VALUE *str_value (char *s) +{ + VALUE *v; + + v = xmalloc (sizeof(VALUE)); + v->type = string; + v->u.s = strdup (s); + return v; +} + +/* Free VALUE V, including structure components. */ + +static void freev (VALUE *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) +{ + 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 (); + } +} + +/* Coerce V to a string value (can't fail). */ + +static void tostring (VALUE *v) +{ + char *temp; + + if (v->type == integer) { + temp = xmalloc (4 * (sizeof (int) / sizeof (char))); + sprintf (temp, "%d", v->u.i); + v->u.s = temp; + v->type = string; + } +} + +/* Coerce V to an integer value. Return 1 on success, 0 on failure. */ + +static int 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 (); + } +} + +/* Return nonzero if the next token matches STR exactly. + STR must not be NULL. */ + +static int +nextarg (char *str) +{ + if (*args == NULL) + return 0; + return strcmp (*args, str) == 0; +} + +/* The comparison operator handling functions. */ + +#define cmpf(name, rel) \ +static int name (l, r) 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; \ +} + 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 (l, r) VALUE *l; VALUE *r; \ +{ \ + if (!toarith (l) || !toarith (r)) \ + error_msg_and_die ("non-numeric argument"); \ + return l->u.i op r->u.i; \ +} + +#define arithdivf(name, op) \ +static int name (l, r) VALUE *l; VALUE *r; \ +{ \ + if (!toarith (l) || !toarith (r)) \ + error_msg_and_die ( "non-numeric argument"); \ + if (r->u.i == 0) \ + error_msg_and_die ( "division by zero"); \ + return l->u.i op r->u.i; \ +} + + 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) +{ + VALUE *v; + const char *errmsg; + struct re_pattern_buffer re_buffer; + struct re_registers re_regs; + int len; + + 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); + } + + 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) { + error_msg_and_die("%s", errmsg); + } + + len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs); + if (len >= 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]); + } + else + v = int_value (len); + } + else { + /* Match failed -- return the right kind of null. */ + if (re_buffer.re_nsub > 0) + v = str_value (""); + else + v = int_value (0); + } + free (re_buffer.buffer); + return v; +} + +/* Handle bare operands and ( expr ) syntax. */ + +static VALUE *eval7 (void) +{ + VALUE *v; + + if (!*args) + error_msg_and_die ( "syntax error"); + + if (nextarg ("(")) { + args++; + v = eval (); + if (!nextarg (")")) + error_msg_and_die ( "syntax error"); + args++; + return v; + } + + if (nextarg (")")) + error_msg_and_die ( "syntax error"); + + return str_value (*args++); +} + +/* Handle match, substr, index, length, and quote keywords. */ + +static VALUE *eval6 (void) +{ + VALUE *l, *r, *v, *i1, *i2; + + if (nextarg ("quote")) { + args++; + if (!*args) + error_msg_and_die ( "syntax error"); + return str_value (*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; + } + 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) + v->u.i = 0; + freev (l); + freev (r); + return v; + } + 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 (""); + else { + v = xmalloc (sizeof(VALUE)); + v->type = string; + v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1), + l->u.s + i1->u.i - 1, i2->u.i); + v->u.s[i2->u.i] = 0; + } + freev (l); + freev (i1); + freev (i2); + return v; + } + else + return eval7 (); +} + +/* Handle : operator (pattern matching). + Calls docolon to do the real work. */ + +static VALUE *eval5 (void) +{ + VALUE *l, *r, *v; + + l = eval6 (); + while (nextarg (":")) { + args++; + r = eval6 (); + v = docolon (l, r); + freev (l); + freev (r); + l = v; + } + return l; +} + +/* Handle *, /, % operators. */ + +static VALUE *eval4 (void) +{ + VALUE *l, *r; + int (*fxn) (), val; + + 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); + } +} + +/* Handle +, - operators. */ + +static VALUE *eval3 (void) +{ + VALUE *l, *r; + int (*fxn) (), val; + + 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); + } +} + +/* Handle comparisons. */ + +static VALUE *eval2 (void) +{ + VALUE *l, *r; + int (*fxn) (), val; + + 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); + } +} + +/* Handle &. */ + +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); + } + return l; +} + +/* Handle |. */ + +static VALUE *eval (void) +{ + VALUE *l, *r; + + l = eval1 (); + while (nextarg ("|")) { + args++; + r = eval1 (); + if (null (l)) { + freev (l); + l = r; + } + else + freev (r); + } + return l; +} diff --git a/fbset.c b/fbset.c new file mode 100644 index 000000000..8daee6605 --- /dev/null +++ b/fbset.c @@ -0,0 +1,427 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini fbset implementation for busybox + * + * Copyright (C) 1999 by Randolph Chung + * + * 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 + * + * This is a from-scratch implementation of fbset; but the de facto fbset + * implementation was a good reference. fbset (original) is released under + * the GPL, and is (c) 1995-1999 by: + * Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +#define DEFAULTFBDEV "/dev/fb0" +#define DEFAULTFBMODE "/etc/fb.modes" + +static const int OPT_CHANGE = (1 << 0); +static const int OPT_INFO = (1 << 1); +static const int OPT_READMODE = (1 << 2); + +enum { + CMD_FB = 1, + CMD_DB = 2, + CMD_GEOMETRY = 3, + CMD_TIMING = 4, + CMD_ACCEL = 5, + CMD_HSYNC = 6, + CMD_VSYNC = 7, + CMD_LACED = 8, + CMD_DOUBLE = 9, +/* CMD_XCOMPAT = 10, */ + CMD_ALL = 11, + CMD_INFO = 12, + CMD_CHANGE = 13, + +#ifdef BB_FEATURE_FBSET_FANCY + CMD_XRES = 100, + CMD_YRES = 101, + CMD_VXRES = 102, + CMD_VYRES = 103, + CMD_DEPTH = 104, + CMD_MATCH = 105, + CMD_PIXCLOCK = 106, + CMD_LEFT = 107, + CMD_RIGHT = 108, + CMD_UPPER = 109, + CMD_LOWER = 110, + CMD_HSLEN = 111, + CMD_VSLEN = 112, + CMD_CSYNC = 113, + CMD_GSYNC = 114, + CMD_EXTSYNC = 115, + CMD_BCAST = 116, + CMD_RGBA = 117, + CMD_STEP = 118, + CMD_MOVE = 119, +#endif +}; + +static unsigned int g_options = 0; + +/* Stuff stolen from the kernel's fb.h */ +static const int FBIOGET_VSCREENINFO = 0x4600; +static const int FBIOPUT_VSCREENINFO = 0x4601; +#define __u32 u_int32_t +struct fb_bitfield { + __u32 offset; /* beginning of bitfield */ + __u32 length; /* length of bitfield */ + __u32 msb_right; /* != 0 : Most significant bit is */ + /* right */ +}; +struct fb_var_screeninfo { + __u32 xres; /* visible resolution */ + __u32 yres; + __u32 xres_virtual; /* virtual resolution */ + __u32 yres_virtual; + __u32 xoffset; /* offset from virtual to visible */ + __u32 yoffset; /* resolution */ + + __u32 bits_per_pixel; /* guess what */ + __u32 grayscale; /* != 0 Graylevels instead of colors */ + + struct fb_bitfield red; /* bitfield in fb mem if true color, */ + struct fb_bitfield green; /* else only length is significant */ + struct fb_bitfield blue; + struct fb_bitfield transp; /* transparency */ + + __u32 nonstd; /* != 0 Non standard pixel format */ + + __u32 activate; /* see FB_ACTIVATE_* */ + + __u32 height; /* height of picture in mm */ + __u32 width; /* width of picture in mm */ + + __u32 accel_flags; /* acceleration flags (hints) */ + + /* Timing: All values in pixclocks, except pixclock (of course) */ + __u32 pixclock; /* pixel clock in ps (pico seconds) */ + __u32 left_margin; /* time from sync to picture */ + __u32 right_margin; /* time from picture to sync */ + __u32 upper_margin; /* time from sync to picture */ + __u32 lower_margin; + __u32 hsync_len; /* length of horizontal sync */ + __u32 vsync_len; /* length of vertical sync */ + __u32 sync; /* see FB_SYNC_* */ + __u32 vmode; /* see FB_VMODE_* */ + __u32 reserved[6]; /* Reserved for future compatibility */ +}; + + +static struct cmdoptions_t { + char *name; + unsigned char param_count; + unsigned char code; +} g_cmdoptions[] = { + { + "-fb", 1, CMD_FB}, { + "-db", 1, CMD_DB}, { + "-a", 0, CMD_ALL}, { + "-i", 0, CMD_INFO}, { + "-g", 5, CMD_GEOMETRY}, { + "-t", 7, CMD_TIMING}, { + "-accel", 1, CMD_ACCEL}, { + "-hsync", 1, CMD_HSYNC}, { + "-vsync", 1, CMD_VSYNC}, { + "-laced", 1, CMD_LACED}, { + "-double", 1, CMD_DOUBLE}, { + "-n", 0, CMD_CHANGE}, { +#ifdef BB_FEATURE_FBSET_FANCY + "-all", 0, CMD_ALL}, { + "-xres", 1, CMD_XRES}, { + "-yres", 1, CMD_YRES}, { + "-vxres", 1, CMD_VXRES}, { + "-vyres", 1, CMD_VYRES}, { + "-depth", 1, CMD_DEPTH}, { + "-match", 0, CMD_MATCH}, { + "-geometry", 5, CMD_GEOMETRY}, { + "-pixclock", 1, CMD_PIXCLOCK}, { + "-left", 1, CMD_LEFT}, { + "-right", 1, CMD_RIGHT}, { + "-upper", 1, CMD_UPPER}, { + "-lower", 1, CMD_LOWER}, { + "-hslen", 1, CMD_HSLEN}, { + "-vslen", 1, CMD_VSLEN}, { + "-timings", 7, CMD_TIMING}, { + "-csync", 1, CMD_CSYNC}, { + "-gsync", 1, CMD_GSYNC}, { + "-extsync", 1, CMD_EXTSYNC}, { + "-bcast", 1, CMD_BCAST}, { + "-rgba", 1, CMD_RGBA}, { + "-step", 1, CMD_STEP}, { + "-move", 1, CMD_MOVE}, { +#endif + 0, 0, 0} +}; + +#ifdef BB_FEATURE_FBSET_READMODE +/* taken from linux/fb.h */ +static const int FB_VMODE_INTERLACED = 1; /* interlaced */ +static const int FB_VMODE_DOUBLE = 2; /* double scan */ +static const int FB_SYNC_HOR_HIGH_ACT = 1; /* horizontal sync high active */ +static const int FB_SYNC_VERT_HIGH_ACT = 2; /* vertical sync high active */ +static const int FB_SYNC_EXT = 4; /* external sync */ +static const int FB_SYNC_COMP_HIGH_ACT = 8; /* composite sync high active */ +#endif +static int readmode(struct fb_var_screeninfo *base, const char *fn, + const char *mode) +{ +#ifdef BB_FEATURE_FBSET_READMODE + FILE *f; + char buf[256]; + char *p = buf; + + f = xfopen(fn, "r"); + while (!feof(f)) { + fgets(buf, sizeof(buf), f); + if ((p = strstr(buf, "mode ")) || (p = strstr(buf, "mode\t"))) { + p += 5; + if ((p = strstr(buf, mode))) { + p += strlen(mode); + if (!isspace(*p) && (*p != 0) && (*p != '"') + && (*p != '\r') && (*p != '\n')) + continue; /* almost, but not quite */ + while (!feof(f)) { + fgets(buf, sizeof(buf), f); + + if ((p = strstr(buf, "geometry "))) { + p += 9; + + sscanf(p, "%d %d %d %d %d", + &(base->xres), &(base->yres), + &(base->xres_virtual), &(base->yres_virtual), + &(base->bits_per_pixel)); + } else if ((p = strstr(buf, "timings "))) { + p += 8; + + sscanf(p, "%d %d %d %d %d %d %d", + &(base->pixclock), + &(base->left_margin), &(base->right_margin), + &(base->upper_margin), &(base->lower_margin), + &(base->hsync_len), &(base->vsync_len)); + } else if ((p = strstr(buf, "laced "))) { + p += 6; + + if (strstr(buf, "false")) { + base->vmode &= ~FB_VMODE_INTERLACED; + } else { + base->vmode |= FB_VMODE_INTERLACED; + } + } else if ((p = strstr(buf, "double "))) { + p += 7; + + if (strstr(buf, "false")) { + base->vmode &= ~FB_VMODE_DOUBLE; + } else { + base->vmode |= FB_VMODE_DOUBLE; + } + } else if ((p = strstr(buf, "vsync "))) { + p += 6; + + if (strstr(buf, "low")) { + base->sync &= ~FB_SYNC_VERT_HIGH_ACT; + } else { + base->sync |= FB_SYNC_VERT_HIGH_ACT; + } + } else if ((p = strstr(buf, "hsync "))) { + p += 6; + + if (strstr(buf, "low")) { + base->sync &= ~FB_SYNC_HOR_HIGH_ACT; + } else { + base->sync |= FB_SYNC_HOR_HIGH_ACT; + } + } else if ((p = strstr(buf, "csync "))) { + p += 6; + + if (strstr(buf, "low")) { + base->sync &= ~FB_SYNC_COMP_HIGH_ACT; + } else { + base->sync |= FB_SYNC_COMP_HIGH_ACT; + } + } else if ((p = strstr(buf, "extsync "))) { + p += 8; + + if (strstr(buf, "false")) { + base->sync &= ~FB_SYNC_EXT; + } else { + base->sync |= FB_SYNC_EXT; + } + } + + if (strstr(buf, "endmode")) + return 1; + } + } + } + } +#else + error_msg( "mode reading not compiled in"); +#endif + return 0; +} + +static void setmode(struct fb_var_screeninfo *base, + struct fb_var_screeninfo *set) +{ + if ((int) set->xres > 0) + base->xres = set->xres; + if ((int) set->yres > 0) + base->yres = set->yres; + if ((int) set->xres_virtual > 0) + base->xres_virtual = set->xres_virtual; + if ((int) set->yres_virtual > 0) + base->yres_virtual = set->yres_virtual; + if ((int) set->bits_per_pixel > 0) + base->bits_per_pixel = set->bits_per_pixel; +} + +static void showmode(struct fb_var_screeninfo *v) +{ + double drate = 0, hrate = 0, vrate = 0; + + if (v->pixclock) { + drate = 1e12 / v->pixclock; + hrate = + drate / (v->left_margin + v->xres + v->right_margin + + v->hsync_len); + vrate = + hrate / (v->upper_margin + v->yres + v->lower_margin + + v->vsync_len); + } + printf("\nmode \"%ux%u-%u\"\n", v->xres, v->yres, (int) (vrate + 0.5)); +#ifdef BB_FEATURE_FBSET_FANCY + printf("\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n", drate / 1e6, + hrate / 1e3, vrate); +#endif + printf("\tgeometry %u %u %u %u %u\n", v->xres, v->yres, + v->xres_virtual, v->yres_virtual, v->bits_per_pixel); + printf("\ttimings %u %u %u %u %u %u %u\n", v->pixclock, v->left_margin, + v->right_margin, v->upper_margin, v->lower_margin, v->hsync_len, + v->vsync_len); + printf("\taccel %s\n", (v->accel_flags > 0 ? "true" : "false")); + printf("\trgba %u/%u,%u/%u,%u/%u,%u/%u\n", v->red.length, + v->red.offset, v->green.length, v->green.offset, v->blue.length, + v->blue.offset, v->transp.length, v->transp.offset); + printf("endmode\n\n"); +} + +#ifdef STANDALONE +int main(int argc, char **argv) +#else +extern int fbset_main(int argc, char **argv) +#endif +{ + struct fb_var_screeninfo var, varset; + int fh, i; + char *fbdev = DEFAULTFBDEV; + char *modefile = DEFAULTFBMODE; + char *thisarg, *mode = NULL; + + memset(&varset, 0xFF, sizeof(varset)); + + /* parse cmd args.... why do they have to make things so difficult? */ + argv++; + argc--; + for (; argc > 0 && (thisarg = *argv); argc--, argv++) { + for (i = 0; g_cmdoptions[i].name; i++) { + if (!strcmp(thisarg, g_cmdoptions[i].name)) { + if (argc - 1 < g_cmdoptions[i].param_count) + show_usage(); + switch (g_cmdoptions[i].code) { + case CMD_FB: + fbdev = argv[1]; + break; + case CMD_DB: + modefile = argv[1]; + break; + case CMD_GEOMETRY: + varset.xres = strtoul(argv[1], 0, 0); + varset.yres = strtoul(argv[2], 0, 0); + varset.xres_virtual = strtoul(argv[3], 0, 0); + varset.yres_virtual = strtoul(argv[4], 0, 0); + varset.bits_per_pixel = strtoul(argv[5], 0, 0); + break; + case CMD_TIMING: + varset.pixclock = strtoul(argv[1], 0, 0); + varset.left_margin = strtoul(argv[2], 0, 0); + varset.right_margin = strtoul(argv[3], 0, 0); + varset.upper_margin = strtoul(argv[4], 0, 0); + varset.lower_margin = strtoul(argv[5], 0, 0); + varset.hsync_len = strtoul(argv[6], 0, 0); + varset.vsync_len = strtoul(argv[7], 0, 0); + break; + case CMD_CHANGE: + g_options |= OPT_CHANGE; + break; +#ifdef BB_FEATURE_FBSET_FANCY + case CMD_XRES: + varset.xres = strtoul(argv[1], 0, 0); + break; + case CMD_YRES: + varset.yres = strtoul(argv[1], 0, 0); + break; + case CMD_DEPTH: + varset.bits_per_pixel = strtoul(argv[1], 0, 0); + break; +#endif + } + argc -= g_cmdoptions[i].param_count; + argv += g_cmdoptions[i].param_count; + break; + } + } + if (!g_cmdoptions[i].name) { + if (argc == 1) { + mode = *argv; + g_options |= OPT_READMODE; + } else { + show_usage(); + } + } + } + + if ((fh = open(fbdev, O_RDONLY)) < 0) + perror_msg_and_die("fbset(open)"); + if (ioctl(fh, FBIOGET_VSCREENINFO, &var)) + perror_msg_and_die("fbset(ioctl)"); + if (g_options & OPT_READMODE) { + if (!readmode(&var, modefile, mode)) { + error_msg("Unknown video mode `%s'", mode); + return EXIT_FAILURE; + } + } + + setmode(&var, &varset); + if (g_options & OPT_CHANGE) + if (ioctl(fh, FBIOPUT_VSCREENINFO, &var)) + perror_msg_and_die("fbset(ioctl)"); + showmode(&var); + /* Don't close the file, as exiting will take care of that */ + /* close(fh); */ + + return EXIT_SUCCESS; +} diff --git a/fdflush.c b/fdflush.c new file mode 100644 index 000000000..28f5cb68a --- /dev/null +++ b/fdflush.c @@ -0,0 +1,47 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini fdflush implementation for busybox + * + * + * 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 + * + */ + +#include +#include +#include +#include +#include "busybox.h" + +/* From */ +#define FDFLUSH _IO(2,0x4b) + +extern int fdflush_main(int argc, char **argv) +{ + int fd; + + if (argc <= 1 || **(++argv) == '-') + show_usage(); + + if ((fd = open(*argv, 0)) < 0) + perror_msg_and_die("%s", *argv); + + if (ioctl(fd, FDFLUSH, 0)) + perror_msg_and_die("%s", *argv); + + return EXIT_SUCCESS; +} diff --git a/find.c b/find.c new file mode 100644 index 000000000..46dd91410 --- /dev/null +++ b/find.c @@ -0,0 +1,220 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini find implementation for busybox + * + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen + * Reworked by David Douthitt and + * 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + + +static char *pattern; + +#ifdef BB_FEATURE_FIND_TYPE +static int type_mask = 0; +#endif + +#ifdef BB_FEATURE_FIND_PERM +static char perm_char = 0; +static int perm_mask = 0; +#endif + +#ifdef BB_FEATURE_FIND_MTIME +static char mtime_char; +static int mtime_days; +#endif + +#ifdef BB_FEATURE_FIND_NEWER +time_t newer_mtime; +#endif + +static int fileAction(const char *fileName, struct stat *statbuf, void* junk) +{ + if (pattern != NULL) { + const char *tmp = strrchr(fileName, '/'); + + if (tmp == NULL) + tmp = fileName; + else + tmp++; + if (!(fnmatch(pattern, tmp, FNM_PERIOD) == 0)) + goto no_match; + } +#ifdef BB_FEATURE_FIND_TYPE + if (type_mask != 0) { + if (!((statbuf->st_mode & S_IFMT) == type_mask)) + goto no_match; + } +#endif +#ifdef BB_FEATURE_FIND_PERM + if (perm_mask != 0) { + if (!((isdigit(perm_char) && (statbuf->st_mode & 07777) == perm_mask) || + (perm_char == '-' && (statbuf->st_mode & perm_mask) == perm_mask) || + (perm_char == '+' && (statbuf->st_mode & perm_mask) != 0))) + goto no_match; + } +#endif +#ifdef BB_FEATURE_FIND_MTIME + if (mtime_char != 0) { + time_t file_age = time(NULL) - statbuf->st_mtime; + time_t mtime_secs = mtime_days * 24 * 60 * 60; + if (!((isdigit(mtime_char) && file_age >= mtime_secs && + file_age < mtime_secs + 24 * 60 * 60) || + (mtime_char == '+' && file_age >= mtime_secs + 24 * 60 * 60) || + (mtime_char == '-' && file_age < mtime_secs))) + goto no_match; + } +#endif +#ifdef BB_FEATURE_FIND_NEWER + if (newer_mtime != 0) { + time_t file_age = newer_mtime - statbuf->st_mtime; + if (file_age >= 0) + goto no_match; + } +#endif + puts(fileName); +no_match: + return (TRUE); +} + +#ifdef BB_FEATURE_FIND_TYPE +static int find_type(char *type) +{ + int mask = 0; + + switch (type[0]) { + case 'b': + mask = S_IFBLK; + break; + case 'c': + mask = S_IFCHR; + break; + case 'd': + mask = S_IFDIR; + break; + case 'p': + mask = S_IFIFO; + break; + case 'f': + mask = S_IFREG; + break; + case 'l': + mask = S_IFLNK; + break; + case 's': + mask = S_IFSOCK; + break; + } + + if (mask == 0 || type[1] != '\0') + error_msg_and_die("invalid argument `%s' to `-type'", type); + + return mask; +} +#endif + +int find_main(int argc, char **argv) +{ + int dereference = FALSE; + int i, firstopt, status = EXIT_SUCCESS; + + for (firstopt = 1; firstopt < argc; firstopt++) { + if (argv[firstopt][0] == '-') + break; + } + + /* Parse any options */ + for (i = firstopt; i < argc; i++) { + if (strcmp(argv[i], "-follow") == 0) + dereference = TRUE; + else if (strcmp(argv[i], "-print") == 0) { + ; + } + else if (strcmp(argv[i], "-name") == 0) { + if (++i == argc) + error_msg_and_die("option `-name' requires an argument"); + pattern = argv[i]; +#ifdef BB_FEATURE_FIND_TYPE + } else if (strcmp(argv[i], "-type") == 0) { + if (++i == argc) + error_msg_and_die("option `-type' requires an argument"); + type_mask = find_type(argv[i]); +#endif +#ifdef BB_FEATURE_FIND_PERM + } else if (strcmp(argv[i], "-perm") == 0) { + char *end; + if (++i == argc) + error_msg_and_die("option `-perm' requires an argument"); + perm_mask = strtol(argv[i], &end, 8); + if (end[0] != '\0') + error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]); + if (perm_mask > 07777) + error_msg_and_die("invalid argument `%s' to `-perm'", argv[i]); + if ((perm_char = argv[i][0]) == '-') + perm_mask = -perm_mask; +#endif +#ifdef BB_FEATURE_FIND_MTIME + } else if (strcmp(argv[i], "-mtime") == 0) { + char *end; + if (++i == argc) + error_msg_and_die("option `-mtime' requires an argument"); + mtime_days = strtol(argv[i], &end, 10); + if (end[0] != '\0') + error_msg_and_die("invalid argument `%s' to `-mtime'", argv[i]); + if ((mtime_char = argv[i][0]) == '-') + mtime_days = -mtime_days; +#endif +#ifdef BB_FEATURE_FIND_NEWER + } else if (strcmp(argv[i], "-newer") == 0) { + struct stat stat_newer; + if (++i == argc) + error_msg_and_die("option `-newer' requires an argument"); + if (stat (argv[i], &stat_newer) != 0) + error_msg_and_die("file %s not found", argv[i]); + newer_mtime = stat_newer.st_mtime; +#endif + } else + show_usage(); + } + + if (firstopt == 1) { + if (recursive_action(".", TRUE, dereference, FALSE, fileAction, + fileAction, NULL) == FALSE) + status = EXIT_FAILURE; + } else { + for (i = 1; i < firstopt; i++) { + if (recursive_action(argv[i], TRUE, dereference, FALSE, fileAction, + fileAction, NULL) == FALSE) + status = EXIT_FAILURE; + } + } + + return status; +} diff --git a/free.c b/free.c new file mode 100644 index 000000000..4a5469b10 --- /dev/null +++ b/free.c @@ -0,0 +1,85 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini free implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +/* getopt not needed */ + +#include +#include +#include +#include "busybox.h" + +extern int free_main(int argc, char **argv) +{ + struct sysinfo info; + sysinfo(&info); + + /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */ + if (info.mem_unit==0) { + info.mem_unit=1; + } + if ( info.mem_unit == 1 ) { + info.mem_unit=1024; + + /* TODO: Make all this stuff not overflow when mem >= 4 Gib */ + info.totalram/=info.mem_unit; + info.freeram/=info.mem_unit; +#ifndef __uClinux__ + info.totalswap/=info.mem_unit; + info.freeswap/=info.mem_unit; +#endif + info.sharedram/=info.mem_unit; + info.bufferram/=info.mem_unit; + } else { + info.mem_unit/=1024; + /* TODO: Make all this stuff not overflow when mem >= 4 Gib */ + info.totalram*=info.mem_unit; + info.freeram*=info.mem_unit; +#ifndef __uClinux__ + info.totalswap*=info.mem_unit; + info.freeswap*=info.mem_unit; +#endif + info.sharedram*=info.mem_unit; + info.bufferram*=info.mem_unit; + } + + if (argc > 1 && **(argv + 1) == '-') + show_usage(); + + printf("%6s%13s%13s%13s%13s%13s\n", "", "total", "used", "free", + "shared", "buffers"); + + printf("%6s%13ld%13ld%13ld%13ld%13ld\n", "Mem:", info.totalram, + info.totalram-info.freeram, info.freeram, + info.sharedram, info.bufferram); + +#ifndef __uClinux__ + printf("%6s%13ld%13ld%13ld\n", "Swap:", info.totalswap, + info.totalswap-info.freeswap, info.freeswap); + + printf("%6s%13ld%13ld%13ld\n", "Total:", info.totalram+info.totalswap, + (info.totalram-info.freeram)+(info.totalswap-info.freeswap), + info.freeram+info.freeswap); +#endif + return EXIT_SUCCESS; +} + diff --git a/freeramdisk.c b/freeramdisk.c new file mode 100644 index 000000000..cf25fae6a --- /dev/null +++ b/freeramdisk.c @@ -0,0 +1,65 @@ +/* vi: set sw=4 ts=4: */ +/* + * freeramdisk implementation for busybox + * + * Copyright (C) 2000 and written by Emanuele Caratti + * Adjusted a bit 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + + +/* From linux/fs.h */ +#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */ + +extern int +freeramdisk_main(int argc, char **argv) +{ + int f; + + if (argc != 2 || *argv[1] == '-') { + show_usage(); + } + + if ((f = open(argv[1], O_RDWR)) == -1) { + perror_msg_and_die("cannot open %s", argv[1]); + } + if (ioctl(f, BLKFLSBUF) < 0) { + perror_msg_and_die("failed ioctl on %s", argv[1]); + } + /* Don't bother closing. Exit does + * that, so we can save a few bytes */ + /* close(f); */ + return EXIT_SUCCESS; +} + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ + diff --git a/fsck_minix.c b/fsck_minix.c new file mode 100644 index 000000000..952968d85 --- /dev/null +++ b/fsck_minix.c @@ -0,0 +1,1478 @@ +/* vi: set sw=4 ts=4: */ +/* + * fsck.c - a file system consistency checker for Linux. + * + * (C) 1991, 1992 Linus Torvalds. This file may be redistributed + * as per the GNU copyleft. + */ + +/* + * 09.11.91 - made the first rudimetary functions + * + * 10.11.91 - updated, does checking, no repairs yet. + * Sent out to the mailing-list for testing. + * + * 14.11.91 - Testing seems to have gone well. Added some + * correction-code, and changed some functions. + * + * 15.11.91 - More correction code. Hopefully it notices most + * cases now, and tries to do something about them. + * + * 16.11.91 - More corrections (thanks to Mika Jalava). Most + * things seem to work now. Yeah, sure. + * + * + * 19.04.92 - Had to start over again from this old version, as a + * kernel bug ate my enhanced fsck in february. + * + * 28.02.93 - added support for different directory entry sizes.. + * + * Sat Mar 6 18:59:42 1993, faith@cs.unc.edu: Output namelen with + * super-block information + * + * Sat Oct 9 11:17:11 1993, faith@cs.unc.edu: make exit status conform + * to that required by fsutil + * + * Mon Jan 3 11:06:52 1994 - Dr. Wettstein (greg%wind.uucp@plains.nodak.edu) + * Added support for file system valid flag. Also + * added program_version variable and output of + * program name and version number when program + * is executed. + * + * 30.10.94 - added support for v2 filesystem + * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de) + * + * 10.12.94 - added test to prevent checking of mounted fs adapted + * from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck + * program. (Daniel Quinlan, quinlan@yggdrasil.com) + * + * 01.07.96 - Fixed the v2 fs stuff to use the right #defines and such + * for modern libcs (janl@math.uio.no, Nicolai Langfeldt) + * + * 02.07.96 - Added C bit fiddling routines from rmk@ecs.soton.ac.uk + * (Russell King). He made them for ARM. It would seem + * that the ARM is powerful enough to do this in C whereas + * i386 and m64k must use assembly to get it fast >:-) + * This should make minix fsck systemindependent. + * (janl@math.uio.no, Nicolai Langfeldt) + * + * 04.11.96 - Added minor fixes from Andreas Schwab to avoid compiler + * warnings. Added mc68k bitops from + * Joerg Dorchain . + * + * 06.11.96 - Added v2 code submitted by Joerg Dorchain, but written by + * Andreas Schwab. + * + * 1999-02-22 Arkadiusz Mi¶kiewicz + * - added Native Language Support + * + * + * I've had no time to add comments - hopefully the function names + * are comments enough. As with all file system checkers, this assumes + * the file system is quiescent - don't use it on a mounted device + * unless you can be sure nobody is writing to it (and remember that the + * kernel can write to it when it searches for files). + * + * Usuage: fsck [-larvsm] device + * -l for a listing of all the filenames + * -a for automatic repairs (not implemented) + * -r for repairs (interactive) (not implemented) + * -v for verbose (tells how many files) + * -s for super-block info + * -m for minix-like "mode not cleared" warnings + * -f force filesystem check even if filesystem marked as valid + * + * The device may be a block device or a image of one, but this isn't + * enforced (but it's not much fun on a character device :-). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +static const int MINIX_ROOT_INO = 1; +static const int MINIX_LINK_MAX = 250; +static const int MINIX2_LINK_MAX = 65530; + +static const int MINIX_I_MAP_SLOTS = 8; +static const int MINIX_Z_MAP_SLOTS = 64; +static const int MINIX_SUPER_MAGIC = 0x137F; /* original minix fs */ +static const int MINIX_SUPER_MAGIC2 = 0x138F; /* minix fs, 30 char names */ +static const int MINIX2_SUPER_MAGIC = 0x2468; /* minix V2 fs */ +static const int MINIX2_SUPER_MAGIC2 = 0x2478; /* minix V2 fs, 30 char names */ +static const int MINIX_VALID_FS = 0x0001; /* Clean fs. */ +static const int MINIX_ERROR_FS = 0x0002; /* fs has errors. */ + +#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) +#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode))) + +static const int MINIX_V1 = 0x0001; /* original minix fs */ +static const int MINIX_V2 = 0x0002; /* minix V2 fs */ + +#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version + +/* + * This is the original minix inode layout on disk. + * Note the 8-bit gid and atime and ctime. + */ +struct minix_inode { + u_int16_t i_mode; + u_int16_t i_uid; + u_int32_t i_size; + u_int32_t i_time; + u_int8_t i_gid; + u_int8_t i_nlinks; + u_int16_t i_zone[9]; +}; + +/* + * The new minix inode has all the time entries, as well as + * long block numbers and a third indirect block (7+1+1+1 + * instead of 7+1+1). Also, some previously 8-bit values are + * now 16-bit. The inode is now 64 bytes instead of 32. + */ +struct minix2_inode { + u_int16_t i_mode; + u_int16_t i_nlinks; + u_int16_t i_uid; + u_int16_t i_gid; + u_int32_t i_size; + u_int32_t i_atime; + u_int32_t i_mtime; + u_int32_t i_ctime; + u_int32_t i_zone[10]; +}; + +/* + * minix super-block data on disk + */ +struct minix_super_block { + u_int16_t s_ninodes; + u_int16_t s_nzones; + u_int16_t s_imap_blocks; + u_int16_t s_zmap_blocks; + u_int16_t s_firstdatazone; + u_int16_t s_log_zone_size; + u_int32_t s_max_size; + u_int16_t s_magic; + u_int16_t s_state; + u_int32_t s_zones; +}; + +struct minix_dir_entry { + u_int16_t inode; + char name[0]; +}; + +#define BLOCK_SIZE_BITS 10 +#define BLOCK_SIZE (1<> 3] & (1<<(i & 7))) != 0; +} +#define inode_in_use(x) (bit(inode_map,(x))) +#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1)) + +#define mark_inode(x) (setbit(inode_map,(x)),changed=1) +#define unmark_inode(x) (clrbit(inode_map,(x)),changed=1) + +#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1),changed=1) +#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1),changed=1) + +static void leave(int) __attribute__ ((noreturn)); +static void leave(int status) +{ + if (termios_set) + tcsetattr(0, TCSANOW, &termios); + exit(status); +} + +static void die(const char *str) +{ + error_msg("%s", str); + leave(8); +} + +/* + * This simply goes through the file-name data and prints out the + * current file. + */ +static void print_current_name(void) +{ + int i = 0; + + while (i < name_depth) + printf("/%.*s", namelen, name_list[i++]); + if (i == 0) + printf("/"); +} + +static int ask(const char *string, int def) +{ + int c; + + if (!repair) { + printf("\n"); + errors_uncorrected = 1; + return 0; + } + if (automatic) { + printf("\n"); + if (!def) + errors_uncorrected = 1; + return def; + } + printf(def ? "%s (y/n)? " : "%s (n/y)? ", string); + for (;;) { + fflush(stdout); + if ((c = getchar()) == EOF) { + if (!def) + errors_uncorrected = 1; + return def; + } + c = toupper(c); + if (c == 'Y') { + def = 1; + break; + } else if (c == 'N') { + def = 0; + break; + } else if (c == ' ' || c == '\n') + break; + } + if (def) + printf("y\n"); + else { + printf("n\n"); + errors_uncorrected = 1; + } + return def; +} + +/* + * Make certain that we aren't checking a filesystem that is on a + * mounted partition. Code adapted from e2fsck, Copyright (C) 1993, + * 1994 Theodore Ts'o. Also licensed under GPL. + */ +static void check_mount(void) +{ + FILE *f; + struct mntent *mnt; + int cont; + int fd; + + if ((f = setmntent(MOUNTED, "r")) == NULL) + return; + while ((mnt = getmntent(f)) != NULL) + if (strcmp(device_name, mnt->mnt_fsname) == 0) + break; + endmntent(f); + if (!mnt) + return; + + /* + * If the root is mounted read-only, then /etc/mtab is + * probably not correct; so we won't issue a warning based on + * it. + */ + fd = open(MOUNTED, O_RDWR); + if (fd < 0 && errno == EROFS) + return; + else + close(fd); + + printf("%s is mounted. ", device_name); + if (isatty(0) && isatty(1)) + cont = ask("Do you really want to continue", 0); + else + cont = 0; + if (!cont) { + printf("check aborted.\n"); + exit(0); + } + return; +} + +/* + * check_zone_nr checks to see that *nr is a valid zone nr. If it + * isn't, it will possibly be repaired. Check_zone_nr sets *corrected + * if an error was corrected, and returns the zone (0 for no zone + * or a bad zone-number). + */ +static int check_zone_nr(unsigned short *nr, int *corrected) +{ + if (!*nr) + return 0; + if (*nr < FIRSTZONE) + printf("Zone nr < FIRSTZONE in file `"); + else if (*nr >= ZONES) + printf("Zone nr >= ZONES in file `"); + else + return *nr; + print_current_name(); + printf("'."); + if (ask("Remove block", 1)) { + *nr = 0; + *corrected = 1; + } + return 0; +} + +#ifdef BB_FEATURE_MINIX2 +static int check_zone_nr2(unsigned int *nr, int *corrected) +{ + if (!*nr) + return 0; + if (*nr < FIRSTZONE) + printf("Zone nr < FIRSTZONE in file `"); + else if (*nr >= ZONES) + printf("Zone nr >= ZONES in file `"); + else + return *nr; + print_current_name(); + printf("'."); + if (ask("Remove block", 1)) { + *nr = 0; + *corrected = 1; + } + return 0; +} +#endif + +/* + * read-block reads block nr into the buffer at addr. + */ +static void read_block(unsigned int nr, char *addr) +{ + if (!nr) { + memset(addr, 0, BLOCK_SIZE); + return; + } + if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) { + printf("Read error: unable to seek to block in file '"); + print_current_name(); + printf("'\n"); + memset(addr, 0, BLOCK_SIZE); + errors_uncorrected = 1; + } else if (BLOCK_SIZE != read(IN, addr, BLOCK_SIZE)) { + printf("Read error: bad block in file '"); + print_current_name(); + printf("'\n"); + memset(addr, 0, BLOCK_SIZE); + errors_uncorrected = 1; + } +} + +/* + * write_block writes block nr to disk. + */ +static void write_block(unsigned int nr, char *addr) +{ + if (!nr) + return; + if (nr < FIRSTZONE || nr >= ZONES) { + printf("Internal error: trying to write bad block\n" + "Write request ignored\n"); + errors_uncorrected = 1; + return; + } + if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) + die("seek failed in write_block"); + if (BLOCK_SIZE != write(IN, addr, BLOCK_SIZE)) { + printf("Write error: bad block in file '"); + print_current_name(); + printf("'\n"); + errors_uncorrected = 1; + } +} + +/* + * map-block calculates the absolute block nr of a block in a file. + * It sets 'changed' if the inode has needed changing, and re-writes + * any indirect blocks with errors. + */ +static int map_block(struct minix_inode *inode, unsigned int blknr) +{ + unsigned short ind[BLOCK_SIZE >> 1]; + unsigned short dind[BLOCK_SIZE >> 1]; + int blk_chg, block, result; + + if (blknr < 7) + return check_zone_nr(inode->i_zone + blknr, &changed); + blknr -= 7; + if (blknr < 512) { + block = check_zone_nr(inode->i_zone + 7, &changed); + read_block(block, (char *) ind); + blk_chg = 0; + result = check_zone_nr(blknr + ind, &blk_chg); + if (blk_chg) + write_block(block, (char *) ind); + return result; + } + blknr -= 512; + block = check_zone_nr(inode->i_zone + 8, &changed); + read_block(block, (char *) dind); + blk_chg = 0; + result = check_zone_nr(dind + (blknr / 512), &blk_chg); + if (blk_chg) + write_block(block, (char *) dind); + block = result; + read_block(block, (char *) ind); + blk_chg = 0; + result = check_zone_nr(ind + (blknr % 512), &blk_chg); + if (blk_chg) + write_block(block, (char *) ind); + return result; +} + +#ifdef BB_FEATURE_MINIX2 +static int map_block2(struct minix2_inode *inode, unsigned int blknr) +{ + unsigned int ind[BLOCK_SIZE >> 2]; + unsigned int dind[BLOCK_SIZE >> 2]; + unsigned int tind[BLOCK_SIZE >> 2]; + int blk_chg, block, result; + + if (blknr < 7) + return check_zone_nr2(inode->i_zone + blknr, &changed); + blknr -= 7; + if (blknr < 256) { + block = check_zone_nr2(inode->i_zone + 7, &changed); + read_block(block, (char *) ind); + blk_chg = 0; + result = check_zone_nr2(blknr + ind, &blk_chg); + if (blk_chg) + write_block(block, (char *) ind); + return result; + } + blknr -= 256; + if (blknr >= 256 * 256) { + block = check_zone_nr2(inode->i_zone + 8, &changed); + read_block(block, (char *) dind); + blk_chg = 0; + result = check_zone_nr2(dind + blknr / 256, &blk_chg); + if (blk_chg) + write_block(block, (char *) dind); + block = result; + read_block(block, (char *) ind); + blk_chg = 0; + result = check_zone_nr2(ind + blknr % 256, &blk_chg); + if (blk_chg) + write_block(block, (char *) ind); + return result; + } + blknr -= 256 * 256; + block = check_zone_nr2(inode->i_zone + 9, &changed); + read_block(block, (char *) tind); + blk_chg = 0; + result = check_zone_nr2(tind + blknr / (256 * 256), &blk_chg); + if (blk_chg) + write_block(block, (char *) tind); + block = result; + read_block(block, (char *) dind); + blk_chg = 0; + result = check_zone_nr2(dind + (blknr / 256) % 256, &blk_chg); + if (blk_chg) + write_block(block, (char *) dind); + block = result; + read_block(block, (char *) ind); + blk_chg = 0; + result = check_zone_nr2(ind + blknr % 256, &blk_chg); + if (blk_chg) + write_block(block, (char *) ind); + return result; +} +#endif + +static void write_super_block(void) +{ + /* + * Set the state of the filesystem based on whether or not there + * are uncorrected errors. The filesystem valid flag is + * unconditionally set if we get this far. + */ + Super.s_state |= MINIX_VALID_FS; + if (errors_uncorrected) + Super.s_state |= MINIX_ERROR_FS; + else + Super.s_state &= ~MINIX_ERROR_FS; + + if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET)) + die("seek failed in write_super_block"); + if (BLOCK_SIZE != write(IN, super_block_buffer, BLOCK_SIZE)) + die("unable to write super-block"); + + return; +} + +static void write_tables(void) +{ + write_super_block(); + + if (IMAPS * BLOCK_SIZE != write(IN, inode_map, IMAPS * BLOCK_SIZE)) + die("Unable to write inode map"); + if (ZMAPS * BLOCK_SIZE != write(IN, zone_map, ZMAPS * BLOCK_SIZE)) + die("Unable to write zone map"); + if (INODE_BUFFER_SIZE != write(IN, inode_buffer, INODE_BUFFER_SIZE)) + die("Unable to write inodes"); +} + +static void get_dirsize(void) +{ + int block; + char blk[BLOCK_SIZE]; + int size; + +#ifdef BB_FEATURE_MINIX2 + if (version2) + block = Inode2[ROOT_INO].i_zone[0]; + else +#endif + block = Inode[ROOT_INO].i_zone[0]; + read_block(block, blk); + for (size = 16; size < BLOCK_SIZE; size <<= 1) { + if (strcmp(blk + size + 2, "..") == 0) { + dirsize = size; + namelen = size - 2; + return; + } + } + /* use defaults */ +} + +static void read_superblock(void) +{ + if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET)) + die("seek failed"); + if (BLOCK_SIZE != read(IN, super_block_buffer, BLOCK_SIZE)) + die("unable to read super block"); + if (MAGIC == MINIX_SUPER_MAGIC) { + namelen = 14; + dirsize = 16; + version2 = 0; + } else if (MAGIC == MINIX_SUPER_MAGIC2) { + namelen = 30; + dirsize = 32; + version2 = 0; +#ifdef BB_FEATURE_MINIX2 + } else if (MAGIC == MINIX2_SUPER_MAGIC) { + namelen = 14; + dirsize = 16; + version2 = 1; + } else if (MAGIC == MINIX2_SUPER_MAGIC2) { + namelen = 30; + dirsize = 32; + version2 = 1; +#endif + } else + die("bad magic number in super-block"); + if (ZONESIZE != 0 || BLOCK_SIZE != 1024) + die("Only 1k blocks/zones supported"); + if (IMAPS * BLOCK_SIZE * 8 < INODES + 1) + die("bad s_imap_blocks field in super-block"); + if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1) + die("bad s_zmap_blocks field in super-block"); +} + +static void read_tables(void) +{ + inode_map = xmalloc(IMAPS * BLOCK_SIZE); + zone_map = xmalloc(ZMAPS * BLOCK_SIZE); + memset(inode_map, 0, sizeof(inode_map)); + memset(zone_map, 0, sizeof(zone_map)); + inode_buffer = xmalloc(INODE_BUFFER_SIZE); + inode_count = xmalloc(INODES + 1); + zone_count = xmalloc(ZONES); + if (IMAPS * BLOCK_SIZE != read(IN, inode_map, IMAPS * BLOCK_SIZE)) + die("Unable to read inode map"); + if (ZMAPS * BLOCK_SIZE != read(IN, zone_map, ZMAPS * BLOCK_SIZE)) + die("Unable to read zone map"); + if (INODE_BUFFER_SIZE != read(IN, inode_buffer, INODE_BUFFER_SIZE)) + die("Unable to read inodes"); + if (NORM_FIRSTZONE != FIRSTZONE) { + printf("Warning: Firstzone != Norm_firstzone\n"); + errors_uncorrected = 1; + } + get_dirsize(); + if (show) { + printf("%ld inodes\n", INODES); + printf("%ld blocks\n", ZONES); + printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE); + printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE); + printf("Maxsize=%ld\n", MAXSIZE); + printf("Filesystem state=%d\n", Super.s_state); + printf("namelen=%d\n\n", namelen); + } +} + +static struct minix_inode *get_inode(unsigned int nr) +{ + struct minix_inode *inode; + + if (!nr || nr > INODES) + return NULL; + total++; + inode = Inode + nr; + if (!inode_count[nr]) { + if (!inode_in_use(nr)) { + printf("Inode %d marked not used, but used for file '", nr); + print_current_name(); + printf("'\n"); + if (repair) { + if (ask("Mark in use", 1)) + mark_inode(nr); + } else { + errors_uncorrected = 1; + } + } + if (S_ISDIR(inode->i_mode)) + directory++; + else if (S_ISREG(inode->i_mode)) + regular++; + else if (S_ISCHR(inode->i_mode)) + chardev++; + else if (S_ISBLK(inode->i_mode)) + blockdev++; + else if (S_ISLNK(inode->i_mode)) + symlinks++; + else if (S_ISSOCK(inode->i_mode)); + else if (S_ISFIFO(inode->i_mode)); + else { + print_current_name(); + printf(" has mode %05o\n", inode->i_mode); + } + + } else + links++; + if (!++inode_count[nr]) { + printf("Warning: inode count too big.\n"); + inode_count[nr]--; + errors_uncorrected = 1; + } + return inode; +} + +#ifdef BB_FEATURE_MINIX2 +static struct minix2_inode *get_inode2(unsigned int nr) +{ + struct minix2_inode *inode; + + if (!nr || nr > INODES) + return NULL; + total++; + inode = Inode2 + nr; + if (!inode_count[nr]) { + if (!inode_in_use(nr)) { + printf("Inode %d marked not used, but used for file '", nr); + print_current_name(); + printf("'\n"); + if (repair) { + if (ask("Mark in use", 1)) + mark_inode(nr); + else + errors_uncorrected = 1; + } + } + if (S_ISDIR(inode->i_mode)) + directory++; + else if (S_ISREG(inode->i_mode)) + regular++; + else if (S_ISCHR(inode->i_mode)) + chardev++; + else if (S_ISBLK(inode->i_mode)) + blockdev++; + else if (S_ISLNK(inode->i_mode)) + symlinks++; + else if (S_ISSOCK(inode->i_mode)); + else if (S_ISFIFO(inode->i_mode)); + else { + print_current_name(); + printf(" has mode %05o\n", inode->i_mode); + } + } else + links++; + if (!++inode_count[nr]) { + printf("Warning: inode count too big.\n"); + inode_count[nr]--; + errors_uncorrected = 1; + } + return inode; +} +#endif + +static void check_root(void) +{ + struct minix_inode *inode = Inode + ROOT_INO; + + if (!inode || !S_ISDIR(inode->i_mode)) + die("root inode isn't a directory"); +} + +#ifdef BB_FEATURE_MINIX2 +static void check_root2(void) +{ + struct minix2_inode *inode = Inode2 + ROOT_INO; + + if (!inode || !S_ISDIR(inode->i_mode)) + die("root inode isn't a directory"); +} +#endif + +static int add_zone(unsigned short *znr, int *corrected) +{ + int result; + int block; + + result = 0; + block = check_zone_nr(znr, corrected); + if (!block) + return 0; + if (zone_count[block]) { + printf("Block has been used before. Now in file `"); + print_current_name(); + printf("'."); + if (ask("Clear", 1)) { + *znr = 0; + block = 0; + *corrected = 1; + } + } + if (!block) + return 0; + if (!zone_in_use(block)) { + printf("Block %d in file `", block); + print_current_name(); + printf("' is marked not in use."); + if (ask("Correct", 1)) + mark_zone(block); + } + if (!++zone_count[block]) + zone_count[block]--; + return block; +} + +#ifdef BB_FEATURE_MINIX2 +static int add_zone2(unsigned int *znr, int *corrected) +{ + int result; + int block; + + result = 0; + block = check_zone_nr2(znr, corrected); + if (!block) + return 0; + if (zone_count[block]) { + printf("Block has been used before. Now in file `"); + print_current_name(); + printf("'."); + if (ask("Clear", 1)) { + *znr = 0; + block = 0; + *corrected = 1; + } + } + if (!block) + return 0; + if (!zone_in_use(block)) { + printf("Block %d in file `", block); + print_current_name(); + printf("' is marked not in use."); + if (ask("Correct", 1)) + mark_zone(block); + } + if (!++zone_count[block]) + zone_count[block]--; + return block; +} +#endif + +static void add_zone_ind(unsigned short *znr, int *corrected) +{ + static char blk[BLOCK_SIZE]; + int i, chg_blk = 0; + int block; + + block = add_zone(znr, corrected); + if (!block) + return; + read_block(block, blk); + for (i = 0; i < (BLOCK_SIZE >> 1); i++) + add_zone(i + (unsigned short *) blk, &chg_blk); + if (chg_blk) + write_block(block, blk); +} + +#ifdef BB_FEATURE_MINIX2 +static void add_zone_ind2(unsigned int *znr, int *corrected) +{ + static char blk[BLOCK_SIZE]; + int i, chg_blk = 0; + int block; + + block = add_zone2(znr, corrected); + if (!block) + return; + read_block(block, blk); + for (i = 0; i < BLOCK_SIZE >> 2; i++) + add_zone2(i + (unsigned int *) blk, &chg_blk); + if (chg_blk) + write_block(block, blk); +} +#endif + +static void add_zone_dind(unsigned short *znr, int *corrected) +{ + static char blk[BLOCK_SIZE]; + int i, blk_chg = 0; + int block; + + block = add_zone(znr, corrected); + if (!block) + return; + read_block(block, blk); + for (i = 0; i < (BLOCK_SIZE >> 1); i++) + add_zone_ind(i + (unsigned short *) blk, &blk_chg); + if (blk_chg) + write_block(block, blk); +} + +#ifdef BB_FEATURE_MINIX2 +static void add_zone_dind2(unsigned int *znr, int *corrected) +{ + static char blk[BLOCK_SIZE]; + int i, blk_chg = 0; + int block; + + block = add_zone2(znr, corrected); + if (!block) + return; + read_block(block, blk); + for (i = 0; i < BLOCK_SIZE >> 2; i++) + add_zone_ind2(i + (unsigned int *) blk, &blk_chg); + if (blk_chg) + write_block(block, blk); +} + +static void add_zone_tind2(unsigned int *znr, int *corrected) +{ + static char blk[BLOCK_SIZE]; + int i, blk_chg = 0; + int block; + + block = add_zone2(znr, corrected); + if (!block) + return; + read_block(block, blk); + for (i = 0; i < BLOCK_SIZE >> 2; i++) + add_zone_dind2(i + (unsigned int *) blk, &blk_chg); + if (blk_chg) + write_block(block, blk); +} +#endif + +static void check_zones(unsigned int i) +{ + struct minix_inode *inode; + + if (!i || i > INODES) + return; + if (inode_count[i] > 1) /* have we counted this file already? */ + return; + inode = Inode + i; + if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) && + !S_ISLNK(inode->i_mode)) return; + for (i = 0; i < 7; i++) + add_zone(i + inode->i_zone, &changed); + add_zone_ind(7 + inode->i_zone, &changed); + add_zone_dind(8 + inode->i_zone, &changed); +} + +#ifdef BB_FEATURE_MINIX2 +static void check_zones2(unsigned int i) +{ + struct minix2_inode *inode; + + if (!i || i > INODES) + return; + if (inode_count[i] > 1) /* have we counted this file already? */ + return; + inode = Inode2 + i; + if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) + && !S_ISLNK(inode->i_mode)) + return; + for (i = 0; i < 7; i++) + add_zone2(i + inode->i_zone, &changed); + add_zone_ind2(7 + inode->i_zone, &changed); + add_zone_dind2(8 + inode->i_zone, &changed); + add_zone_tind2(9 + inode->i_zone, &changed); +} +#endif + +static void check_file(struct minix_inode *dir, unsigned int offset) +{ + static char blk[BLOCK_SIZE]; + struct minix_inode *inode; + int ino; + char *name; + int block; + + block = map_block(dir, offset / BLOCK_SIZE); + read_block(block, blk); + name = blk + (offset % BLOCK_SIZE) + 2; + ino = *(unsigned short *) (name - 2); + if (ino > INODES) { + print_current_name(); + printf(" contains a bad inode number for file '"); + printf("%.*s'.", namelen, name); + if (ask(" Remove", 1)) { + *(unsigned short *) (name - 2) = 0; + write_block(block, blk); + } + ino = 0; + } + if (name_depth < MAX_DEPTH) + strncpy(name_list[name_depth], name, namelen); + name_depth++; + inode = get_inode(ino); + name_depth--; + if (!offset) { + if (!inode || strcmp(".", name)) { + print_current_name(); + printf(": bad directory: '.' isn't first\n"); + errors_uncorrected = 1; + } else + return; + } + if (offset == dirsize) { + if (!inode || strcmp("..", name)) { + print_current_name(); + printf(": bad directory: '..' isn't second\n"); + errors_uncorrected = 1; + } else + return; + } + if (!inode) + return; + if (name_depth < MAX_DEPTH) + strncpy(name_list[name_depth], name, namelen); + name_depth++; + if (list) { + if (verbose) + printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks); + print_current_name(); + if (S_ISDIR(inode->i_mode)) + printf(":\n"); + else + printf("\n"); + } + check_zones(ino); + if (inode && S_ISDIR(inode->i_mode)) + recursive_check(ino); + name_depth--; + return; +} + +#ifdef BB_FEATURE_MINIX2 +static void check_file2(struct minix2_inode *dir, unsigned int offset) +{ + static char blk[BLOCK_SIZE]; + struct minix2_inode *inode; + int ino; + char *name; + int block; + + block = map_block2(dir, offset / BLOCK_SIZE); + read_block(block, blk); + name = blk + (offset % BLOCK_SIZE) + 2; + ino = *(unsigned short *) (name - 2); + if (ino > INODES) { + print_current_name(); + printf(" contains a bad inode number for file '"); + printf("%.*s'.", namelen, name); + if (ask(" Remove", 1)) { + *(unsigned short *) (name - 2) = 0; + write_block(block, blk); + } + ino = 0; + } + if (name_depth < MAX_DEPTH) + strncpy(name_list[name_depth], name, namelen); + name_depth++; + inode = get_inode2(ino); + name_depth--; + if (!offset) { + if (!inode || strcmp(".", name)) { + print_current_name(); + printf(": bad directory: '.' isn't first\n"); + errors_uncorrected = 1; + } else + return; + } + if (offset == dirsize) { + if (!inode || strcmp("..", name)) { + print_current_name(); + printf(": bad directory: '..' isn't second\n"); + errors_uncorrected = 1; + } else + return; + } + if (!inode) + return; + name_depth++; + if (list) { + if (verbose) + printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks); + print_current_name(); + if (S_ISDIR(inode->i_mode)) + printf(":\n"); + else + printf("\n"); + } + check_zones2(ino); + if (inode && S_ISDIR(inode->i_mode)) + recursive_check2(ino); + name_depth--; + return; +} +#endif + +static void recursive_check(unsigned int ino) +{ + struct minix_inode *dir; + unsigned int offset; + + dir = Inode + ino; + if (!S_ISDIR(dir->i_mode)) + die("internal error"); + if (dir->i_size < 2 * dirsize) { + print_current_name(); + printf(": bad directory: size<32"); + errors_uncorrected = 1; + } + for (offset = 0; offset < dir->i_size; offset += dirsize) + check_file(dir, offset); +} + +#ifdef BB_FEATURE_MINIX2 +static void recursive_check2(unsigned int ino) +{ + struct minix2_inode *dir; + unsigned int offset; + + dir = Inode2 + ino; + if (!S_ISDIR(dir->i_mode)) + die("internal error"); + if (dir->i_size < 2 * dirsize) { + print_current_name(); + printf(": bad directory: size < 32"); + errors_uncorrected = 1; + } + for (offset = 0; offset < dir->i_size; offset += dirsize) + check_file2(dir, offset); +} +#endif + +static int bad_zone(int i) +{ + char buffer[1024]; + + if (BLOCK_SIZE * i != lseek(IN, BLOCK_SIZE * i, SEEK_SET)) + die("seek failed in bad_zone"); + return (BLOCK_SIZE != read(IN, buffer, BLOCK_SIZE)); +} + +static void check_counts(void) +{ + int i; + + for (i = 1; i <= INODES; i++) { + if (!inode_in_use(i) && Inode[i].i_mode && warn_mode) { + printf("Inode %d mode not cleared.", i); + if (ask("Clear", 1)) { + Inode[i].i_mode = 0; + changed = 1; + } + } + if (!inode_count[i]) { + if (!inode_in_use(i)) + continue; + printf("Inode %d not used, marked used in the bitmap.", i); + if (ask("Clear", 1)) + unmark_inode(i); + continue; + } + if (!inode_in_use(i)) { + printf("Inode %d used, marked unused in the bitmap.", i); + if (ask("Set", 1)) + mark_inode(i); + } + if (Inode[i].i_nlinks != inode_count[i]) { + printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.", + i, Inode[i].i_mode, Inode[i].i_nlinks, inode_count[i]); + if (ask("Set i_nlinks to count", 1)) { + Inode[i].i_nlinks = inode_count[i]; + changed = 1; + } + } + } + for (i = FIRSTZONE; i < ZONES; i++) { + if (zone_in_use(i) == zone_count[i]) + continue; + if (!zone_count[i]) { + if (bad_zone(i)) + continue; + printf("Zone %d: marked in use, no file uses it.", i); + if (ask("Unmark", 1)) + unmark_zone(i); + continue; + } + printf("Zone %d: %sin use, counted=%d\n", + i, zone_in_use(i) ? "" : "not ", zone_count[i]); + } +} + +#ifdef BB_FEATURE_MINIX2 +static void check_counts2(void) +{ + int i; + + for (i = 1; i <= INODES; i++) { + if (!inode_in_use(i) && Inode2[i].i_mode && warn_mode) { + printf("Inode %d mode not cleared.", i); + if (ask("Clear", 1)) { + Inode2[i].i_mode = 0; + changed = 1; + } + } + if (!inode_count[i]) { + if (!inode_in_use(i)) + continue; + printf("Inode %d not used, marked used in the bitmap.", i); + if (ask("Clear", 1)) + unmark_inode(i); + continue; + } + if (!inode_in_use(i)) { + printf("Inode %d used, marked unused in the bitmap.", i); + if (ask("Set", 1)) + mark_inode(i); + } + if (Inode2[i].i_nlinks != inode_count[i]) { + printf("Inode %d (mode = %07o), i_nlinks=%d, counted=%d.", + i, Inode2[i].i_mode, Inode2[i].i_nlinks, + inode_count[i]); + if (ask("Set i_nlinks to count", 1)) { + Inode2[i].i_nlinks = inode_count[i]; + changed = 1; + } + } + } + for (i = FIRSTZONE; i < ZONES; i++) { + if (zone_in_use(i) == zone_count[i]) + continue; + if (!zone_count[i]) { + if (bad_zone(i)) + continue; + printf("Zone %d: marked in use, no file uses it.", i); + if (ask("Unmark", 1)) + unmark_zone(i); + continue; + } + printf("Zone %d: %sin use, counted=%d\n", + i, zone_in_use(i) ? "" : "not ", zone_count[i]); + } +} +#endif + +static void check(void) +{ + memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count)); + memset(zone_count, 0, ZONES * sizeof(*zone_count)); + check_zones(ROOT_INO); + recursive_check(ROOT_INO); + check_counts(); +} + +#ifdef BB_FEATURE_MINIX2 +static void check2(void) +{ + memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count)); + memset(zone_count, 0, ZONES * sizeof(*zone_count)); + check_zones2(ROOT_INO); + recursive_check2(ROOT_INO); + check_counts2(); +} +#endif + +/* Wed Feb 9 15:17:06 MST 2000 */ +/* dynamically allocate name_list (instead of making it static) */ +static void alloc_name_list(void) +{ + int i; + + name_list = xmalloc(sizeof(char *) * MAX_DEPTH); + for (i = 0; i < MAX_DEPTH; i++) + name_list[i] = xmalloc(sizeof(char) * BUFSIZ + 1); +} + +#ifdef BB_FEATURE_CLEAN_UP +/* execute this atexit() to deallocate name_list[] */ +/* piptigger was here */ +static void free_name_list(void) +{ + int i; + + if (name_list) { + for (i = 0; i < MAX_DEPTH; i++) { + if (name_list[i]) { + free(name_list[i]); + } + } + free(name_list); + } +} +#endif + +extern int fsck_minix_main(int argc, char **argv) +{ + struct termios tmp; + int count; + int retcode = 0; + + alloc_name_list(); +#ifdef BB_FEATURE_CLEAN_UP + /* Don't bother to free memory. Exit does + * that automagically, so we can save a few bytes */ + atexit(free_name_list); +#endif + + if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) + die("bad inode size"); +#ifdef BB_FEATURE_MINIX2 + if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) + die("bad v2 inode size"); +#endif + while (argc-- > 1) { + argv++; + if (argv[0][0] != '-') { + if (device_name) + show_usage(); + else + device_name = argv[0]; + } else + while (*++argv[0]) + switch (argv[0][0]) { + case 'l': + list = 1; + break; + case 'a': + automatic = 1; + repair = 1; + break; + case 'r': + automatic = 0; + repair = 1; + break; + case 'v': + verbose = 1; + break; + case 's': + show = 1; + break; + case 'm': + warn_mode = 1; + break; + case 'f': + force = 1; + break; + default: + show_usage(); + } + } + if (!device_name) + show_usage(); + check_mount(); /* trying to check a mounted filesystem? */ + if (repair && !automatic) { + if (!isatty(0) || !isatty(1)) + die("need terminal for interactive repairs"); + } + IN = open(device_name, repair ? O_RDWR : O_RDONLY); + if (IN < 0){ + fprintf(stderr,"unable to open device '%s'.\n",device_name); + leave(8); + } + for (count = 0; count < 3; count++) + sync(); + read_superblock(); + + /* + * Determine whether or not we should continue with the checking. + * This is based on the status of the filesystem valid and error + * flags and whether or not the -f switch was specified on the + * command line. + */ + printf("%s, %s\n", applet_name, program_version); + if (!(Super.s_state & MINIX_ERROR_FS) && + (Super.s_state & MINIX_VALID_FS) && !force) { + if (repair) + printf("%s is clean, no check.\n", device_name); + return retcode; + } else if (force) + printf("Forcing filesystem check on %s.\n", device_name); + else if (repair) + printf("Filesystem on %s is dirty, needs checking.\n", + device_name); + + read_tables(); + + if (repair && !automatic) { + tcgetattr(0, &termios); + tmp = termios; + tmp.c_lflag &= ~(ICANON | ECHO); + tcsetattr(0, TCSANOW, &tmp); + termios_set = 1; + } +#ifdef BB_FEATURE_MINIX2 + if (version2) { + check_root2(); + check2(); + } else +#endif + { + check_root(); + check(); + } + if (verbose) { + int i, free_cnt; + + for (i = 1, free_cnt = 0; i <= INODES; i++) + if (!inode_in_use(i)) + free_cnt++; + printf("\n%6ld inodes used (%ld%%)\n", (INODES - free_cnt), + 100 * (INODES - free_cnt) / INODES); + for (i = FIRSTZONE, free_cnt = 0; i < ZONES; i++) + if (!zone_in_use(i)) + free_cnt++; + printf("%6ld zones used (%ld%%)\n", (ZONES - free_cnt), + 100 * (ZONES - free_cnt) / ZONES); + printf("\n%6d regular files\n" + "%6d directories\n" + "%6d character device files\n" + "%6d block device files\n" + "%6d links\n" + "%6d symbolic links\n" + "------\n" + "%6d files\n", + regular, directory, chardev, blockdev, + links - 2 * directory + 1, symlinks, + total - 2 * directory + 1); + } + if (changed) { + write_tables(); + printf("----------------------------\n" + "FILE SYSTEM HAS BEEN CHANGED\n" + "----------------------------\n"); + for (count = 0; count < 3; count++) + sync(); + } else if (repair) + write_super_block(); + + if (repair && !automatic) + tcsetattr(0, TCSANOW, &termios); + + if (changed) + retcode += 3; + if (errors_uncorrected) + retcode += 4; + return retcode; +} diff --git a/getopt.c b/getopt.c new file mode 100644 index 000000000..95ecba6e6 --- /dev/null +++ b/getopt.c @@ -0,0 +1,402 @@ +/* + * getopt.c - Enhanced implementation of BSD getopt(1) + * Copyright (c) 1997, 1998, 1999, 2000 Frodo Looijaard + * + * 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. + */ + +/* + * Version 1.0-b4: Tue Sep 23 1997. First public release. + * Version 1.0: Wed Nov 19 1997. + * Bumped up the version number to 1.0 + * Fixed minor typo (CSH instead of TCSH) + * Version 1.0.1: Tue Jun 3 1998 + * Fixed sizeof instead of strlen bug + * Bumped up the version number to 1.0.1 + * Version 1.0.2: Thu Jun 11 1998 (not present) + * Fixed gcc-2.8.1 warnings + * Fixed --version/-V option (not present) + * Version 1.0.5: Tue Jun 22 1999 + * Make -u option work (not present) + * Version 1.0.6: Tue Jun 27 2000 + * No important changes + * Version 1.1.0: Tue Jun 30 2000 + * Added NLS support (partly written by Arkadiusz Mikiewicz + * ) + * Ported to Busybox - Alfred M. Szmidt + * Removed --version/-V and --help/-h in + * Removed prase_error(), using error_msg() from Busybox instead + * Replaced our_malloc with xmalloc and our_realloc with xrealloc + * + */ + +#include +#include +#include +#include +#include +#include + +#include "busybox.h" + +/* NON_OPT is the code that is returned when a non-option is found in '+' + mode */ +static const int NON_OPT = 1; +/* LONG_OPT is the code that is returned when a long option is found. */ +static const int LONG_OPT = 2; + +/* The shells recognized. */ +typedef enum {BASH,TCSH} shell_t; + + +/* Some global variables that tells us how to parse. */ +static shell_t shell=BASH; /* The shell we generate output for. */ +static int quiet_errors=0; /* 0 is not quiet. */ +static int quiet_output=0; /* 0 is not quiet. */ +static int quote=1; /* 1 is do quote. */ +static int alternative=0; /* 0 is getopt_long, 1 is getopt_long_only */ + +/* Function prototypes */ +static const char *normalize(const char *arg); +static int generate_output(char * argv[],int argc,const char *optstr, + const struct option *longopts); +static void add_long_options(char *options); +static void add_longopt(const char *name,int has_arg); +static void set_shell(const char *new_shell); + + +/* + * This function 'normalizes' a single argument: it puts single quotes around + * it and escapes other special characters. If quote is false, it just + * returns its argument. + * Bash only needs special treatment for single quotes; tcsh also recognizes + * exclamation marks within single quotes, and nukes whitespace. + * This function returns a pointer to a buffer that is overwritten by + * each call. + */ +const char *normalize(const char *arg) +{ + static char *BUFFER=NULL; + const char *argptr=arg; + char *bufptr; + + if (BUFFER != NULL) + free(BUFFER); + + if (!quote) { /* Just copy arg */ + BUFFER=xmalloc(strlen(arg)+1); + + strcpy(BUFFER,arg); + return BUFFER; + } + + /* Each character in arg may take upto four characters in the result: + For a quote we need a closing quote, a backslash, a quote and an + opening quote! We need also the global opening and closing quote, + and one extra character for '\0'. */ + BUFFER=xmalloc(strlen(arg)*4+3); + + bufptr=BUFFER; + *bufptr++='\''; + + while (*argptr) { + if (*argptr == '\'') { + /* Quote: replace it with: '\'' */ + *bufptr++='\''; + *bufptr++='\\'; + *bufptr++='\''; + *bufptr++='\''; + } else if (shell==TCSH && *argptr=='!') { + /* Exclamation mark: replace it with: \! */ + *bufptr++='\''; + *bufptr++='\\'; + *bufptr++='!'; + *bufptr++='\''; + } else if (shell==TCSH && *argptr=='\n') { + /* Newline: replace it with: \n */ + *bufptr++='\\'; + *bufptr++='n'; + } else if (shell==TCSH && isspace(*argptr)) { + /* Non-newline whitespace: replace it with \ */ + *bufptr++='\''; + *bufptr++='\\'; + *bufptr++=*argptr; + *bufptr++='\''; + } else + /* Just copy */ + *bufptr++=*argptr; + argptr++; + } + *bufptr++='\''; + *bufptr++='\0'; + return BUFFER; +} + +/* + * Generate the output. argv[0] is the program name (used for reporting errors). + * argv[1..] contains the options to be parsed. argc must be the number of + * elements in argv (ie. 1 if there are no options, only the program name), + * optstr must contain the short options, and longopts the long options. + * Other settings are found in global variables. + */ +int generate_output(char * argv[],int argc,const char *optstr, + const struct option *longopts) +{ + int exit_code = 0; /* We assume everything will be OK */ + int opt; + int longindex; + const char *charptr; + + if (quiet_errors) /* No error reporting from getopt(3) */ + opterr=0; + optind=0; /* Reset getopt(3) */ + + while ((opt = (alternative? + getopt_long_only(argc,argv,optstr,longopts,&longindex): + getopt_long(argc,argv,optstr,longopts,&longindex))) + != EOF) + if (opt == '?' || opt == ':' ) + exit_code = 1; + else if (!quiet_output) { + if (opt == LONG_OPT) { + printf(" --%s",longopts[longindex].name); + if (longopts[longindex].has_arg) + printf(" %s", + normalize(optarg?optarg:"")); + } else if (opt == NON_OPT) + printf(" %s",normalize(optarg)); + else { + printf(" -%c",opt); + charptr = strchr(optstr,opt); + if (charptr != NULL && *++charptr == ':') + printf(" %s", + normalize(optarg?optarg:"")); + } + } + + if (! quiet_output) { + printf(" --"); + while (optind < argc) + printf(" %s",normalize(argv[optind++])); + printf("\n"); + } + return exit_code; +} + +static struct option *long_options=NULL; +static int long_options_length=0; /* Length of array */ +static int long_options_nr=0; /* Nr of used elements in array */ +static const int LONG_OPTIONS_INCR = 10; +#define init_longopt() add_longopt(NULL,0) + +/* Register a long option. The contents of name is copied. */ +void add_longopt(const char *name,int has_arg) +{ + char *tmp; + if (!name) { /* init */ + free(long_options); + long_options=NULL; + long_options_length=0; + long_options_nr=0; + } + + if (long_options_nr == long_options_length) { + long_options_length += LONG_OPTIONS_INCR; + long_options=xrealloc(long_options, + sizeof(struct option) * + long_options_length); + } + + long_options[long_options_nr].name=NULL; + long_options[long_options_nr].has_arg=0; + long_options[long_options_nr].flag=NULL; + long_options[long_options_nr].val=0; + + if (long_options_nr) { /* Not for init! */ + long_options[long_options_nr-1].has_arg=has_arg; + long_options[long_options_nr-1].flag=NULL; + long_options[long_options_nr-1].val=LONG_OPT; + tmp = xmalloc(strlen(name)+1); + strcpy(tmp,name); + long_options[long_options_nr-1].name=tmp; + } + long_options_nr++; +} + + +/* + * Register several long options. options is a string of long options, + * separated by commas or whitespace. + * This nukes options! + */ +void add_long_options(char *options) +{ + int arg_opt, tlen; + char *tokptr=strtok(options,", \t\n"); + while (tokptr) { + arg_opt=no_argument; + tlen=strlen(tokptr); + if (tlen > 0) { + if (tokptr[tlen-1] == ':') { + if (tlen > 1 && tokptr[tlen-2] == ':') { + tokptr[tlen-2]='\0'; + tlen -= 2; + arg_opt=optional_argument; + } else { + tokptr[tlen-1]='\0'; + tlen -= 1; + arg_opt=required_argument; + } + if (tlen == 0) + error_msg("empty long option after -l or --long argument"); + } + add_longopt(tokptr,arg_opt); + } + tokptr=strtok(NULL,", \t\n"); + } +} + +void set_shell(const char *new_shell) +{ + if (!strcmp(new_shell,"bash")) + shell=BASH; + else if (!strcmp(new_shell,"tcsh")) + shell=TCSH; + else if (!strcmp(new_shell,"sh")) + shell=BASH; + else if (!strcmp(new_shell,"csh")) + shell=TCSH; + else + error_msg("unknown shell after -s or --shell argument"); +} + + +/* Exit codes: + * 0) No errors, succesful operation. + * 1) getopt(3) returned an error. + * 2) A problem with parameter parsing for getopt(1). + * 3) Internal error, out of memory + * 4) Returned for -T + */ + +static struct option longopts[]= +{ + {"options",required_argument,NULL,'o'}, + {"longoptions",required_argument,NULL,'l'}, + {"quiet",no_argument,NULL,'q'}, + {"quiet-output",no_argument,NULL,'Q'}, + {"shell",required_argument,NULL,'s'}, + {"test",no_argument,NULL,'T'}, + {"unquoted",no_argument,NULL,'u'}, + {"alternative",no_argument,NULL,'a'}, + {"name",required_argument,NULL,'n'}, + {NULL,0,NULL,0} +}; + +/* Stop scanning as soon as a non-option argument is found! */ +static const char *shortopts="+ao:l:n:qQs:Tu"; + + +int getopt_main(int argc, char *argv[]) +{ + char *optstr=NULL; + char *name=NULL; + int opt; + int compatible=0; + + init_longopt(); + + if (getenv("GETOPT_COMPATIBLE")) + compatible=1; + + if (argc == 1) { + if (compatible) { + /* For some reason, the original getopt gave no error + when there were no arguments. */ + printf(" --\n"); + exit(0); + } else + error_msg_and_die("missing optstring argument"); + } + + if (argv[1][0] != '-' || compatible) { + quote=0; + optstr=xmalloc(strlen(argv[1])+1); + strcpy(optstr,argv[1]+strspn(argv[1],"-+")); + argv[1]=argv[0]; + exit(generate_output(argv+1,argc-1,optstr,long_options)); + } + + while ((opt=getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF) + switch (opt) { + case 'a': + alternative=1; + break; + case 'o': + if (optstr) + free(optstr); + optstr=xmalloc(strlen(optarg)+1); + strcpy(optstr,optarg); + break; + case 'l': + add_long_options(optarg); + break; + case 'n': + if (name) + free(name); + name=xmalloc(strlen(optarg)+1); + strcpy(name,optarg); + break; + case 'q': + quiet_errors=1; + break; + case 'Q': + quiet_output=1; + break; + case 's': + set_shell(optarg); + break; + case 'T': + exit(4); + case 'u': + quote=0; + break; + default: + show_usage(); + } + + if (!optstr) { + if (optind >= argc) + error_msg_and_die("missing optstring argument"); + else { + optstr=xmalloc(strlen(argv[optind])+1); + strcpy(optstr,argv[optind]); + optind++; + } + } + if (name) + argv[optind-1]=name; + else + argv[optind-1]=argv[0]; + exit(generate_output(argv+optind-1,argc-optind+1,optstr,long_options)); +} + +/* + Local Variables: + c-file-style: "linux" + c-basic-offset: 4 + tab-width: 4 + End: +*/ diff --git a/grep.c b/grep.c new file mode 100644 index 000000000..712d8dce6 --- /dev/null +++ b/grep.c @@ -0,0 +1,372 @@ +/* + * Mini grep implementation for busybox using libc regex. + * + * Copyright (C) 1999,2000 by Lineo, inc. and Mark Whitley + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include +#include +#include /* for strerror() */ +#include +#include "busybox.h" + + +extern int optind; /* in unistd.h */ +extern void xregcomp(regex_t *preg, const char *regex, int cflags); /* in busybox.h */ + +/* options */ +static int reflags = REG_NOSUB; +static int print_filename = 0; +static int print_line_num = 0; +static int print_match_counts = 0; +static int be_quiet = 0; +static int invert_search = 0; +static int suppress_err_msgs = 0; +static int print_files_with_matches = 0; + +#ifdef BB_FEATURE_GREP_CONTEXT +extern char *optarg; /* in getopt.h */ +static int lines_before = 0; +static int lines_after = 0; +static char **before_buf = NULL; +static int last_line_printed = 0; +#endif /* BB_FEATURE_GREP_CONTEXT */ + +/* globals used internally */ +static regex_t *regexes = NULL; /* growable array of compiled regular expressions */ +static int nregexes = 0; /* number of elements in above arrary */ +static int matched; /* keeps track of whether we ever matched */ +static char *cur_file = NULL; /* the current file we are reading */ + + +static void print_line(const char *line, int linenum, char decoration) +{ +#ifdef BB_FEATURE_GREP_CONTEXT + /* possibly print the little '--' seperator */ + if ((lines_before || lines_after) && last_line_printed && + last_line_printed < linenum - 1) { + puts("--"); + } + last_line_printed = linenum; +#endif + if (print_filename) + printf("%s%c", cur_file, decoration); + if (print_line_num) + printf("%i%c", linenum, decoration); + puts(line); +} + + +static void grep_file(FILE *file) +{ + char *line = NULL; + int ret; + int linenum = 0; + int nmatches = 0; + int i; +#ifdef BB_FEATURE_GREP_CONTEXT + int print_n_lines_after = 0; + int curpos = 0; /* track where we are in the circular 'before' buffer */ + int idx = 0; /* used for iteration through the circular buffer */ +#endif /* BB_FEATURE_GREP_CONTEXT */ + + while ((line = get_line_from_file(file)) != NULL) { + chomp(line); + linenum++; + + for (i = 0; i < nregexes; i++) { + /* + * test for a postitive-assertion match (regexec returns success (0) + * and the user did not specify invert search), or a negative-assertion + * match (regexec returns failure (REG_NOMATCH) and the user specified + * invert search) + */ + ret = regexec(®exes[i], line, 0, NULL, 0); + if ((ret == 0 && !invert_search) || (ret == REG_NOMATCH && invert_search)) { + + /* if we found a match but were told to be quiet, stop here and + * return success */ + if (be_quiet) + exit(0); + + /* keep track of matches */ + nmatches++; + + /* if we're just printing filenames, we stop after the first match */ + if (print_files_with_matches) + break; + + /* print the matched line */ + if (print_match_counts == 0) { +#ifdef BB_FEATURE_GREP_CONTEXT + int prevpos = (curpos == 0) ? lines_before - 1 : curpos - 1; + + /* if we were told to print 'before' lines and there is at least + * one line in the circular buffer, print them */ + if (lines_before && before_buf[prevpos] != NULL) { + int first_buf_entry_line_num = linenum - lines_before; + + /* advance to the first entry in the circular buffer, and + * figure out the line number is of the first line in the + * buffer */ + idx = curpos; + while (before_buf[idx] == NULL) { + idx = (idx + 1) % lines_before; + first_buf_entry_line_num++; + } + + /* now print each line in the buffer, clearing them as we go */ + while (before_buf[idx] != NULL) { + print_line(before_buf[idx], first_buf_entry_line_num, '-'); + free(before_buf[idx]); + before_buf[idx] = NULL; + idx = (idx + 1) % lines_before; + first_buf_entry_line_num++; + } + } + + /* make a note that we need to print 'after' lines */ + print_n_lines_after = lines_after; +#endif /* BB_FEATURE_GREP_CONTEXT */ + print_line(line, linenum, ':'); + } + } +#ifdef BB_FEATURE_GREP_CONTEXT + else { /* no match */ + /* Add the line to the circular 'before' buffer */ + if(lines_before) { + if(before_buf[curpos]) + free(before_buf[curpos]); + before_buf[curpos] = xstrdup(line); + curpos = (curpos + 1) % lines_before; + } + } + + /* if we need to print some context lines after the last match, do so */ + if (print_n_lines_after && (last_line_printed != linenum)) { + print_line(line, linenum, '-'); + print_n_lines_after--; + } +#endif /* BB_FEATURE_GREP_CONTEXT */ + } /* for */ + free(line); + } + + + /* special-case file post-processing for options where we don't print line + * matches, just filenames and possibly match counts */ + + /* grep -c: print [filename:]count, even if count is zero */ + if (print_match_counts) { + if (print_filename) + printf("%s:", cur_file); + if (print_files_with_matches && nmatches > 0) + printf("1\n"); + else + printf("%d\n", nmatches); + } + + /* grep -l: print just the filename, but only if we grepped the line in the file */ + if (print_files_with_matches && nmatches > 0) { + puts(cur_file); + } + + + /* remember if we matched */ + if (nmatches != 0) + matched = 1; +} + + +static void add_regex(const char *restr) +{ + regexes = xrealloc(regexes, sizeof(regex_t) * (++nregexes)); + xregcomp(®exes[nregexes-1], restr, reflags); +} + + +static void load_regexes_from_file(const char *filename) +{ + char *line; + FILE *f = xfopen(filename, "r"); + while ((line = get_line_from_file(f)) != NULL) { + chomp(line); + add_regex(line); + free(line); + } +} + + +#ifdef BB_FEATURE_CLEAN_UP +static void destroy_regexes() +{ + if (regexes == NULL) + return; + + /* destroy all the elments in the array */ + while (--nregexes >= 0) { + regfree(&(regexes[nregexes])); + } + if (regexes) + free(regexes); +} +#endif + + +extern int grep_main(int argc, char **argv) +{ + int opt; +#if defined BB_FEATURE_GREP_CONTEXT || defined BB_FEATURE_GREP_EGREP_ALIAS + char *junk; +#endif + +#ifdef BB_FEATURE_CLEAN_UP + /* destroy command strings on exit */ + atexit(destroy_regexes); +#endif + +#ifdef BB_FEATURE_GREP_EGREP_ALIAS + junk = get_last_path_component(argv[0]); + if (junk && strcmp(junk, "egrep") == 0) + reflags |= REG_EXTENDED; +#endif + + /* do normal option parsing */ + while ((opt = getopt(argc, argv, "iHhlnqvsce:f:" +#ifdef BB_FEATURE_GREP_CONTEXT +"A:B:C:" +#endif +#ifdef BB_FEATURE_GREP_EGREP_ALIAS +"E" +#endif +)) > 0) { + switch (opt) { + case 'i': + reflags |= REG_ICASE; + break; + case 'l': + print_files_with_matches++; + break; + case 'H': + print_filename++; + break; + case 'h': + print_filename--; + break; + case 'n': + print_line_num++; + break; + case 'q': + be_quiet++; + break; + case 'v': + invert_search++; + break; + case 's': + suppress_err_msgs++; + break; + case 'c': + print_match_counts++; + break; + case 'e': + add_regex(optarg); + break; +#ifdef BB_FEATURE_GREP_EGREP_ALIAS + case 'E': + reflags |= REG_EXTENDED; + break; +#endif + case 'f': + load_regexes_from_file(optarg); + break; +#ifdef BB_FEATURE_GREP_CONTEXT + case 'A': + lines_after = strtoul(optarg, &junk, 10); + if(*junk != '\0') + error_msg_and_die("invalid context length argument"); + break; + case 'B': + lines_before = strtoul(optarg, &junk, 10); + if(*junk != '\0') + error_msg_and_die("invalid context length argument"); + before_buf = (char **)xcalloc(lines_before, sizeof(char *)); + break; + case 'C': + lines_after = lines_before = strtoul(optarg, &junk, 10); + if(*junk != '\0') + error_msg_and_die("invalid context length argument"); + before_buf = (char **)xcalloc(lines_before, sizeof(char *)); + break; +#endif /* BB_FEATURE_GREP_CONTEXT */ + default: + show_usage(); + } + } + + /* if we didn't get a pattern from a -e and no command file was specified, + * argv[optind] should be the pattern. no pattern, no worky */ + if (nregexes == 0) { + if (argv[optind] == NULL) + show_usage(); + else { + add_regex(argv[optind]); + optind++; + } + } + + /* sanity checks */ + if (print_match_counts || be_quiet || print_files_with_matches) { + print_line_num = 0; +#ifdef BB_FEATURE_GREP_CONTEXT + lines_before = 0; + lines_after = 0; +#endif + } + + /* argv[(optind)..(argc-1)] should be names of file to grep through. If + * there is more than one file to grep, we will print the filenames */ + if ((argc-1) - (optind) > 0) + print_filename++; + + /* If no files were specified, or '-' was specified, take input from + * stdin. Otherwise, we grep through all the files specified. */ + if (argv[optind] == NULL || (strcmp(argv[optind], "-") == 0)) { + grep_file(stdin); + } + else { + int i; + FILE *file; + for (i = optind; i < argc; i++) { + cur_file = argv[i]; + file = fopen(cur_file, "r"); + if (file == NULL) { + if (!suppress_err_msgs) + perror_msg("%s", cur_file); + } + else { + grep_file(file); + fclose(file); + } + } + } + + return !matched; /* invert return value 0 = success, 1 = failed */ +} diff --git a/gunzip.c b/gunzip.c new file mode 100644 index 000000000..5a7b10386 --- /dev/null +++ b/gunzip.c @@ -0,0 +1,203 @@ +/* vi: set sw=4 ts=4: */ +/* + * Gzip implementation for busybox + * + * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly. + * + * Originally adjusted for busybox by Sven Rudolph + * based on gzip sources + * + * Adjusted further by Erik Andersen to support files as + * well as stdin/stdout, and to generally behave itself wrt command line + * handling. + * + * General cleanup to better adhere to the style guide and make use of standard + * busybox functions by 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 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 + * + * + * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface + * Copyright (C) 1992-1993 Jean-loup Gailly + * The unzip code was written and put in the public domain by Mark Adler. + * Portions of the lzw code are derived from the public domain 'compress' + * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, + * Ken Turkowski, Dave Mack and Peter Jannesen. + * + * See the license_msg below and the file COPYING for the software license. + * See the file algorithm.doc for the compression algorithms and file formats. + */ + +#if 0 +static char *license_msg[] = { + " Copyright (C) 1992-1993 Jean-loup Gailly", + " 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., 675 Mass Ave, Cambridge, MA 02139, USA.", + 0 +}; +#endif + +#include +#include +#include +#include +#include "busybox.h" + +const int gunzip_to_stdout = 1; +const int gunzip_force = 2; +const int gunzip_test = 4; +const int gunzip_verbose = 8; + +static int gunzip_file (const char *path, int flags) +{ + FILE *in_file, *out_file; + struct stat stat_buf; + const char *delete_path = NULL; + char *out_path = NULL; + + if (path == NULL || strcmp (path, "-") == 0) { + in_file = stdin; + flags |= gunzip_to_stdout; + } else { + if ((in_file = wfopen(path, "r")) == NULL) + return -1; + + if (flags & gunzip_verbose) { + fprintf(stderr, "%s:\t", path); + } + + /* set the buffer size */ + setvbuf(in_file, NULL, _IOFBF, 0x8000); + + /* Get the time stamp on the input file. */ + if (stat(path, &stat_buf) < 0) { + error_msg_and_die("Couldn't stat file %s", path); + } + } + + /* Check that the input is sane. */ + if (isatty(fileno(in_file)) && (flags & gunzip_force) == 0) + error_msg_and_die("compressed data not read from terminal. Use -f to force it."); + + /* Set output filename and number */ + if (flags & gunzip_test) { + out_file = xfopen("/dev/null", "w"); /* why does test use filenum 2 ? */ + } else if (flags & gunzip_to_stdout) { + out_file = stdout; + } else { + char *extension; + int length = strlen(path); + + extension = strrchr(path, '.'); + if (extension && strcmp(extension, ".gz") == 0) { + length -= 3; + } else if (extension && strcmp(extension, ".tgz") == 0) { + length -= 4; + } else { + error_msg_and_die("Invalid extension"); + } + out_path = (char *) xcalloc(sizeof(char), length + 1); + strncpy(out_path, path, length); + + /* Open output file */ + out_file = xfopen(out_path, "w"); + + /* Set permissions on the file */ + chmod(out_path, stat_buf.st_mode); + } + + /* do the decompression, and cleanup */ + if (unzip(in_file, out_file) == 0) { + /* Success, remove .gz file */ + if ( !(flags & gunzip_to_stdout )) + delete_path = path; + if (flags & gunzip_verbose) { + fprintf(stderr, "OK\n"); + } + } else { + /* remove failed attempt */ + delete_path = out_path; + } + + fclose(out_file); + fclose(in_file); + + if (delete_path && !(flags & gunzip_test)) { + if (unlink(delete_path) < 0) { + error_msg_and_die("Couldn't remove %s", delete_path); + } + } + + free(out_path); + + return 0; +} + +extern int gunzip_main(int argc, char **argv) +{ + int flags = 0; + int i, opt; + int status = EXIT_SUCCESS; + + /* if called as zcat */ + if (strcmp(applet_name, "zcat") == 0) + flags |= gunzip_to_stdout; + + while ((opt = getopt(argc, argv, "ctfhdqv")) != -1) { + switch (opt) { + case 'c': + flags |= gunzip_to_stdout; + break; + case 'f': + flags |= gunzip_force; + break; + case 't': + flags |= gunzip_test; + break; + case 'v': + flags |= gunzip_verbose; + break; + case 'd': /* Used to convert gzip to gunzip. */ + break; + case 'q': + error_msg("-q option not supported, ignored"); + break; + case 'h': + default: + show_usage(); /* exit's inside usage */ + } + } + + if (optind == argc) { + if (gunzip_file (NULL, flags) < 0) + status = EXIT_FAILURE; + } else + for (i = optind; i < argc; i++) + if (gunzip_file (argv[i], flags) < 0) + status = EXIT_FAILURE; + + return status; +} diff --git a/gzip.c b/gzip.c new file mode 100644 index 000000000..413ebd595 --- /dev/null +++ b/gzip.c @@ -0,0 +1,2552 @@ +/* vi: set sw=4 ts=4: */ +/* + * Gzip implementation for busybox + * + * Based on GNU gzip Copyright (C) 1992-1993 Jean-loup Gailly. + * + * Originally adjusted for busybox by Charles P. Wright + * "this is a stripped down version of gzip I put into busybox, it does + * only standard in to standard out with -9 compression. It also requires + * the zcat module for some important functions." + * + * Adjusted further by Erik Andersen + * to support files as well as stdin/stdout, and to generally behave itself wrt + * command line handling. + * + * 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 + * + */ + +/* These defines are very important for BusyBox. Without these, + * huge chunks of ram are pre-allocated making the BusyBox bss + * size Freaking Huge(tm), which is a bad thing.*/ +#define SMALL_MEM +#define DYN_ALLOC + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +#define memzero(s, n) memset ((void *)(s), 0, (n)) + +#ifndef RETSIGTYPE +# define RETSIGTYPE void +#endif + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +/* Return codes from gzip */ +#define OK 0 +#define ERROR 1 +#define WARNING 2 + +/* Compression methods (see algorithm.doc) */ +/* Only STORED and DEFLATED are supported by this BusyBox module */ +#define STORED 0 +/* methods 4 to 7 reserved */ +#define DEFLATED 8 +static int method; /* compression method */ + +/* To save memory for 16 bit systems, some arrays are overlaid between + * the various modules: + * deflate: prev+head window d_buf l_buf outbuf + * unlzw: tab_prefix tab_suffix stack inbuf outbuf + * For compression, input is done in window[]. For decompression, output + * is done in window except for unlzw. + */ + +#ifndef INBUFSIZ +# ifdef SMALL_MEM +# define INBUFSIZ 0x2000 /* input buffer size */ +# else +# define INBUFSIZ 0x8000 /* input buffer size */ +# endif +#endif +#define INBUF_EXTRA 64 /* required by unlzw() */ + +#ifndef OUTBUFSIZ +# ifdef SMALL_MEM +# define OUTBUFSIZ 8192 /* output buffer size */ +# else +# define OUTBUFSIZ 16384 /* output buffer size */ +# endif +#endif +#define OUTBUF_EXTRA 2048 /* required by unlzw() */ + +#ifndef DIST_BUFSIZE +# ifdef SMALL_MEM +# define DIST_BUFSIZE 0x2000 /* buffer for distances, see trees.c */ +# else +# define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */ +# endif +#endif + +#ifdef DYN_ALLOC +# define DECLARE(type, array, size) static type * array +# define ALLOC(type, array, size) { \ + array = (type*)calloc((size_t)(((size)+1L)/2), 2*sizeof(type)); \ + if (array == NULL) error_msg(memory_exhausted); \ + } +# define FREE(array) {if (array != NULL) free(array), array=NULL;} +#else +# define DECLARE(type, array, size) static type array[size] +# define ALLOC(type, array, size) +# define FREE(array) +#endif + +#define tab_suffix window +#define tab_prefix prev /* hash link (see deflate.c) */ +#define head (prev+WSIZE) /* hash head (see deflate.c) */ + +static long bytes_in; /* number of input bytes */ + +#define isize bytes_in +/* for compatibility with old zip sources (to be cleaned) */ + +typedef int file_t; /* Do not use stdio */ + +#define NO_FILE (-1) /* in memory compression */ + + +#define PACK_MAGIC "\037\036" /* Magic header for packed files */ +#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */ +#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */ +#define LZH_MAGIC "\037\240" /* Magic header for SCO LZH Compress files */ +#define PKZIP_MAGIC "\120\113\003\004" /* Magic header for pkzip files */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +/* internal file attribute */ +#define UNKNOWN 0xffff +#define BINARY 0 +#define ASCII 1 + +#ifndef WSIZE +# define WSIZE 0x8000 /* window size--must be a power of two, and */ +#endif /* at least 32K for zip's deflate method */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST (WSIZE-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +/* put_byte is used for the compressed output */ +#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\ + flush_outbuf();} + +/* Output a 16 bit value, lsb first */ +#define put_short(w) \ +{ if (outcnt < OUTBUFSIZ-2) { \ + outbuf[outcnt++] = (uch) ((w) & 0xff); \ + outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \ + } else { \ + put_byte((uch)((w) & 0xff)); \ + put_byte((uch)((ush)(w) >> 8)); \ + } \ +} + +/* Output a 32 bit value to the bit stream, lsb first */ +#define put_long(n) { \ + put_short((n) & 0xffff); \ + put_short(((ulg)(n)) >> 16); \ +} + +#define seekable() 0 /* force sequential output */ +#define translate_eol 0 /* no option -a yet */ + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error_msg(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +#define WARN(msg) {if (!quiet) fprintf msg ; \ + if (exit_code == OK) exit_code = WARNING;} + +#ifndef MAX_PATH_LEN +# define MAX_PATH_LEN 1024 /* max pathname length */ +#endif + + + + /* from zip.c: */ +static int zip (int in, int out); +static int file_read (char *buf, unsigned size); + + /* from gzip.c */ +static RETSIGTYPE abort_gzip (void); + + /* from deflate.c */ +static void lm_init (ush * flags); +static ulg deflate (void); + + /* from trees.c */ +static void ct_init (ush * attr, int *methodp); +static int ct_tally (int dist, int lc); +static ulg flush_block (char *buf, ulg stored_len, int eof); + + /* from bits.c */ +static void bi_init (file_t zipfile); +static void send_bits (int value, int length); +static unsigned bi_reverse (unsigned value, int length); +static void bi_windup (void); +static void copy_block (char *buf, unsigned len, int header); +static int (*read_buf) (char *buf, unsigned size); + + /* from util.c: */ +static void flush_outbuf (void); + +/* lzw.h -- define the lzw functions. + * Copyright (C) 1992-1993 Jean-loup Gailly. + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License, see the file COPYING. + */ + +#if !defined(OF) && defined(lint) +# include "gzip.h" +#endif + +#ifndef BITS +# define BITS 16 +#endif +#define INIT_BITS 9 /* Initial number of bits per code */ + +#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */ +/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free. + * It's a pity that old uncompress does not check bit 0x20. That makes + * extension of the format actually undesirable because old compress + * would just crash on the new format instead of giving a meaningful + * error message. It does check the number of bits, but it's more + * helpful to say "unsupported format, get a new version" than + * "can only handle 16 bits". + */ + +/* tailor.h -- target dependent definitions + * Copyright (C) 1992-1993 Jean-loup Gailly. + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License, see the file COPYING. + */ + +/* The target dependent definitions should be defined here only. + * The target dependent functions should be defined in tailor.c. + */ + + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef PATH_SEP +# define PATH_SEP '/' +#endif + +#ifndef OPTIONS_VAR +# define OPTIONS_VAR "GZIP" +#endif + +#ifndef Z_SUFFIX +# define Z_SUFFIX ".gz" +#endif + +#ifdef MAX_EXT_CHARS +# define MAX_SUFFIX MAX_EXT_CHARS +#else +# define MAX_SUFFIX 30 +#endif + + /* global buffers */ + +DECLARE(uch, inbuf, INBUFSIZ + INBUF_EXTRA); +DECLARE(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA); +DECLARE(ush, d_buf, DIST_BUFSIZE); +DECLARE(uch, window, 2L * WSIZE); +DECLARE(ush, tab_prefix, 1L << BITS); + +static int crc_table_empty = 1; + +static int foreground; /* set if program run in foreground */ +static int method = DEFLATED; /* compression method */ +static int exit_code = OK; /* program exit code */ +static int part_nb; /* number of parts in .gz file */ +static long time_stamp; /* original time stamp (modification time) */ +static long ifile_size; /* input file size, -1 for devices (debug only) */ + +static char ifname[MAX_PATH_LEN]; /* input file name */ +static char ofname[MAX_PATH_LEN]; /* output file name */ +static int ifd; /* input file descriptor */ +static int ofd; /* output file descriptor */ +static unsigned insize; /* valid bytes in inbuf */ +static unsigned outcnt; /* bytes in output buffer */ + +/* ======================================================================== + * Signal and error handler. + */ +static void abort_gzip() +{ + exit(ERROR); +} + +/* =========================================================================== + * Clear input and output buffers + */ +static void clear_bufs(void) +{ + outcnt = 0; + insize = 0; + bytes_in = 0L; +} + +static void write_error_msg() +{ + fprintf(stderr, "\n"); + perror(""); + abort_gzip(); +} + +/* =========================================================================== + * Does the same as write(), but also handles partial pipe writes and checks + * for error return. + */ +static void write_buf(int fd, void *buf, unsigned cnt) +{ + unsigned n; + + while ((n = write(fd, buf, cnt)) != cnt) { + if (n == (unsigned) (-1)) { + write_error_msg(); + } + cnt -= n; + buf = (void *) ((char *) buf + n); + } +} + +/* =========================================================================== + * Run a set of bytes through the crc shift register. If s is a NULL + * pointer, then initialize the crc shift register contents instead. + * Return the current crc in either case. + */ +static ulg updcrc(uch *s, unsigned n) +{ + static ulg crc = (ulg) 0xffffffffL; /* shift register contents */ + register ulg c; /* temporary variable */ + static unsigned long crc_32_tab[256]; + if (crc_table_empty) { + unsigned long csr; /* crc shift register */ + unsigned long e=0; /* polynomial exclusive-or pattern */ + int i; /* counter for all possible eight bit values */ + int k; /* byte being shifted into crc apparatus */ + + /* terms of polynomial defining this crc (except x^32): */ + static const int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* Make exclusive-or pattern from polynomial (0xedb88320) */ + for (i = 0; i < sizeof(p)/sizeof(int); i++) + e |= 1L << (31 - p[i]); + + /* Compute and print table of CRC's, five per line */ + crc_32_tab[0] = 0x00000000L; + for (i = 1; i < 256; i++) { + csr = i; + /* The idea to initialize the register with the byte instead of + * zero was stolen from Haruhiko Okumura's ar002 + */ + for (k = 8; k; k--) + csr = csr & 1 ? (csr >> 1) ^ e : csr >> 1; + crc_32_tab[i]=csr; + } + } + + if (s == NULL) { + c = 0xffffffffL; + } else { + c = crc; + if (n) + do { + c = crc_32_tab[((int) c ^ (*s++)) & 0xff] ^ (c >> 8); + } while (--n); + } + crc = c; + return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */ +} + +/* bits.c -- output variable-length bit strings + * Copyright (C) 1992-1993 Jean-loup Gailly + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License, see the file COPYING. + */ + + +/* + * PURPOSE + * + * Output variable-length bit strings. Compression can be done + * to a file or to memory. (The latter is not supported in this version.) + * + * DISCUSSION + * + * The PKZIP "deflate" file format interprets compressed file data + * as a sequence of bits. Multi-bit strings in the file may cross + * byte boundaries without restriction. + * + * The first bit of each byte is the low-order bit. + * + * The routines in this file allow a variable-length bit value to + * be output right-to-left (useful for literal values). For + * left-to-right output (useful for code strings from the tree routines), + * the bits must have been reversed first with bi_reverse(). + * + * For in-memory compression, the compressed bit stream goes directly + * into the requested output buffer. The input data is read in blocks + * by the mem_read() function. The buffer is limited to 64K on 16 bit + * machines. + * + * INTERFACE + * + * void bi_init (FILE *zipfile) + * Initialize the bit string routines. + * + * void send_bits (int value, int length) + * Write out a bit string, taking the source bits right to + * left. + * + * int bi_reverse (int value, int length) + * Reverse the bits of a bit string, taking the source bits left to + * right and emitting them right to left. + * + * void bi_windup (void) + * Write out any remaining bits in an incomplete byte. + * + * void copy_block(char *buf, unsigned len, int header) + * Copy a stored block to the zip file, storing first the length and + * its one's complement if requested. + * + */ + +/* =========================================================================== + * Local data used by the "bit string" routines. + */ + +static file_t zfile; /* output gzip file */ + +static unsigned short bi_buf; + +/* Output buffer. bits are inserted starting at the bottom (least significant + * bits). + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +static int bi_valid; + +/* Current input function. Set to mem_read for in-memory compression */ + +#ifdef DEBUG +ulg bits_sent; /* bit length of the compressed data */ +#endif + +/* =========================================================================== + * Initialize the bit string routines. + */ +static void bi_init(file_t zipfile) +{ + zfile = zipfile; + bi_buf = 0; + bi_valid = 0; +#ifdef DEBUG + bits_sent = 0L; +#endif + + /* Set the defaults for file compression. They are set by memcompress + * for in-memory compression. + */ + if (zfile != NO_FILE) { + read_buf = file_read; + } +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +static void send_bits(int value, int length) +{ +#ifdef DEBUG + Tracev((stderr, " l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + bits_sent += (ulg) length; +#endif + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (bi_valid > (int) Buf_size - length) { + bi_buf |= (value << bi_valid); + put_short(bi_buf); + bi_buf = (ush) value >> (Buf_size - bi_valid); + bi_valid += length - Buf_size; + } else { + bi_buf |= value << bi_valid; + bi_valid += length; + } +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +static unsigned bi_reverse(unsigned code, int len) +{ + register unsigned res = 0; + + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Write out any remaining bits in an incomplete byte. + */ +static void bi_windup() +{ + if (bi_valid > 8) { + put_short(bi_buf); + } else if (bi_valid > 0) { + put_byte(bi_buf); + } + bi_buf = 0; + bi_valid = 0; +#ifdef DEBUG + bits_sent = (bits_sent + 7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block to the zip file, storing first the length and its + * one's complement if requested. + */ +static void copy_block(char *buf, unsigned len, int header) +{ + bi_windup(); /* align on byte boundary */ + + if (header) { + put_short((ush) len); + put_short((ush) ~ len); +#ifdef DEBUG + bits_sent += 2 * 16; +#endif + } +#ifdef DEBUG + bits_sent += (ulg) len << 3; +#endif + while (len--) { + put_byte(*buf++); + } +} + +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1992-1993 Jean-loup Gailly + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License, see the file COPYING. + */ + +/* + * PURPOSE + * + * Identify new text as repetitions of old text within a fixed- + * length sliding window trailing behind the new text. + * + * DISCUSSION + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many info-zippers for bug reports and testing. + * + * REFERENCES + * + * APPNOTE.TXT documentation file in PKZIP 1.93a distribution. + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + * INTERFACE + * + * void lm_init (int pack_level, ush *flags) + * Initialize the "longest match" routines for a new file + * + * ulg deflate (void) + * Processes a new input file and return its compressed length. Sets + * the compressed length, crc, deflate flags and internal file + * attributes. + */ + + +/* =========================================================================== + * Configuration parameters + */ + +/* Compile with MEDIUM_MEM to reduce the memory requirements or + * with SMALL_MEM to use as little memory as possible. Use BIG_MEM if the + * entire input file can be held in memory (not possible on 16 bit systems). + * Warning: defining these symbols affects HASH_BITS (see below) and thus + * affects the compression ratio. The compressed output + * is still correct, and might even be smaller in some cases. + */ + +#ifdef SMALL_MEM +# define HASH_BITS 13 /* Number of bits used to hash strings */ +#endif +#ifdef MEDIUM_MEM +# define HASH_BITS 14 +#endif +#ifndef HASH_BITS +# define HASH_BITS 15 + /* For portability to 16 bit machines, do not use values above 15. */ +#endif + +/* To save space (see unlzw.c), we overlay prev+head with tab_prefix and + * window with tab_suffix. Check that we can do this: + */ +#if (WSIZE<<1) > (1< BITS-1 +# error cannot overlay head with tab_prefix1 +#endif +#define HASH_SIZE (unsigned)(1<= HASH_BITS + */ + +static unsigned int prev_length; + +/* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + +static unsigned strstart; /* start of string to insert */ +static unsigned match_start; /* start of matching string */ +static int eofile; /* flag set at end of input file */ +static unsigned lookahead; /* number of valid bytes ahead in window */ + +static const unsigned max_chain_length=4096; + +/* To speed up deflation, hash chains are never searched beyond this length. + * A higher limit improves compression ratio but degrades the speed. + */ + +static const unsigned int max_lazy_match=258; + +/* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +#define max_insert_length max_lazy_match +/* Insert new strings in the hash table only if the match length + * is not greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + +static const unsigned good_match=32; + +/* Use a faster search when the previous match is longer than this */ + + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ + +static const int nice_match=258; /* Stop searching when current match exceeds this */ + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +/* =========================================================================== + * Prototypes for local functions. + */ +static void fill_window (void); + +static int longest_match (IPos cur_match); + +#ifdef DEBUG +static void check_match (IPos start, IPos match, int length); +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(h,c) (h = (((h)<= 1 + */ + +/* For MSDOS, OS/2 and 386 Unix, an optimized version is in match.asm or + * match.s. The code is functionally equivalent, so you can use the C version + * if desired. + */ +static int longest_match(IPos cur_match) +{ + unsigned chain_length = max_chain_length; /* max hash chain length */ + register uch *scan = window + strstart; /* current string */ + register uch *match; /* matched string */ + register int len; /* length of current match */ + int best_len = prev_length; /* best match length so far */ + IPos limit = + + strstart > (IPos) MAX_DIST ? strstart - (IPos) MAX_DIST : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + +/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ +#if HASH_BITS < 8 || MAX_MATCH != 258 +# error Code too clever +#endif + register uch *strend = window + strstart + MAX_MATCH; + register uch scan_end1 = scan[best_len - 1]; + register uch scan_end = scan[best_len]; + + /* Do not waste too much time if we already have a good match: */ + if (prev_length >= good_match) { + chain_length >>= 2; + } + Assert(strstart <= window_size - MIN_LOOKAHEAD, + "insufficient lookahead"); + + do { + Assert(cur_match < strstart, "no future"); + match = window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ + if (match[best_len] != scan_end || + match[best_len - 1] != scan_end1 || + *match != *scan || *++match != scan[1]) + continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + len = MAX_MATCH - (int) (strend - scan); + scan = strend - MAX_MATCH; + + if (len > best_len) { + match_start = cur_match; + best_len = len; + if (len >= nice_match) + break; + scan_end1 = scan[best_len - 1]; + scan_end = scan[best_len]; + } + } while ((cur_match = prev[cur_match & WMASK]) > limit + && --chain_length != 0); + + return best_len; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +static void check_match(IPos start, IPos match, int length) +{ + /* check that the match is indeed a match */ + if (memcmp((char *) window + match, + (char *) window + start, length) != EQUAL) { + fprintf(stderr, + " start %d, match %d, length %d\n", start, match, length); + error_msg("invalid match"); + } + if (verbose > 1) { + fprintf(stderr, "\\[%d,%d]", start - match, length); + do { + putc(window[start++], stderr); + } while (--length != 0); + } +} +#else +# define check_match(start, match, length) +#endif + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead, and sets eofile if end of input file. + * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0 + * OUT assertions: at least one byte has been read, or eofile is set; + * file reads are performed for at least two bytes (required for the + * translate_eol option). + */ +static void fill_window() +{ + register unsigned n, m; + unsigned more = + + (unsigned) (window_size - (ulg) lookahead - (ulg) strstart); + /* Amount of free space at the end of the window. */ + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (more == (unsigned) EOF) { + /* Very unlikely, but possible on 16 bit machine if strstart == 0 + * and lookahead == 1 (input done one byte at time) + */ + more--; + } else if (strstart >= WSIZE + MAX_DIST) { + /* By the IN assertion, the window is not empty so we can't confuse + * more == 0 with more == 64K on a 16 bit machine. + */ + Assert(window_size == (ulg) 2 * WSIZE, "no sliding with BIG_MEM"); + + memcpy((char *) window, (char *) window + WSIZE, (unsigned) WSIZE); + match_start -= WSIZE; + strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */ + + block_start -= (long) WSIZE; + + for (n = 0; n < HASH_SIZE; n++) { + m = head[n]; + head[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL); + } + for (n = 0; n < WSIZE; n++) { + m = prev[n]; + prev[n] = (Pos) (m >= WSIZE ? m - WSIZE : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } + more += WSIZE; + } + /* At this point, more >= 2 */ + if (!eofile) { + n = read_buf((char *) window + strstart + lookahead, more); + if (n == 0 || n == (unsigned) EOF) { + eofile = 1; + } else { + lookahead += n; + } + } +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK(eof) \ + flush_block(block_start >= 0L ? (char*)&window[(unsigned)block_start] : \ + (char*)NULL, (long)strstart - block_start, (eof)) + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +static ulg deflate() +{ + IPos hash_head; /* head of hash chain */ + IPos prev_match; /* previous match */ + int flush; /* set if current block must be flushed */ + int match_available = 0; /* set if previous match exists */ + register unsigned match_length = MIN_MATCH - 1; /* length of best match */ + + /* Process the input block. */ + while (lookahead != 0) { + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + INSERT_STRING(strstart, hash_head); + + /* Find the longest match, discarding those <= prev_length. + */ + prev_length = match_length, prev_match = match_start; + match_length = MIN_MATCH - 1; + + if (hash_head != NIL && prev_length < max_lazy_match && + strstart - hash_head <= MAX_DIST) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + match_length = longest_match(hash_head); + /* longest_match() sets match_start */ + if (match_length > lookahead) + match_length = lookahead; + + /* Ignore a length 3 match if it is too distant: */ + if (match_length == MIN_MATCH + && strstart - match_start > TOO_FAR) { + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + match_length--; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (prev_length >= MIN_MATCH && match_length <= prev_length) { + + check_match(strstart - 1, prev_match, prev_length); + + flush = + ct_tally(strstart - 1 - prev_match, + prev_length - MIN_MATCH); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. + */ + lookahead -= prev_length - 1; + prev_length -= 2; + do { + strstart++; + INSERT_STRING(strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH + * these bytes are garbage, but it does not matter since the + * next lookahead bytes will always be emitted as literals. + */ + } while (--prev_length != 0); + match_available = 0; + match_length = MIN_MATCH - 1; + strstart++; + if (flush) + FLUSH_BLOCK(0), block_start = strstart; + + } else if (match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr, "%c", window[strstart - 1])); + if (ct_tally(0, window[strstart - 1])) { + FLUSH_BLOCK(0), block_start = strstart; + } + strstart++; + lookahead--; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + match_available = 1; + strstart++; + lookahead--; + } + Assert(strstart <= isize && lookahead <= isize, "a bit too far"); + + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + while (lookahead < MIN_LOOKAHEAD && !eofile) + fill_window(); + } + if (match_available) + ct_tally(0, window[strstart - 1]); + + return FLUSH_BLOCK(1); /* eof */ +} + +/* gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface + * Copyright (C) 1992-1993 Jean-loup Gailly + * The unzip code was written and put in the public domain by Mark Adler. + * Portions of the lzw code are derived from the public domain 'compress' + * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, + * Ken Turkowski, Dave Mack and Peter Jannesen. + * + * See the license_msg below and the file COPYING for the software license. + * See the file algorithm.doc for the compression algorithms and file formats. + */ + +/* Compress files with zip algorithm and 'compress' interface. + * See usage() and help() functions below for all options. + * Outputs: + * file.gz: compressed file with same mode, owner, and utimes + * or stdout with -c option or if stdin used as input. + * If the output file name had to be truncated, the original name is kept + * in the compressed file. + */ + + /* configuration */ + +typedef struct dirent dir_type; + +typedef RETSIGTYPE(*sig_type) (int); + + +/* ======================================================================== */ +// int main (argc, argv) +// int argc; +// char **argv; +int gzip_main(int argc, char **argv) +{ + int result; + int inFileNum; + int outFileNum; + struct stat statBuf; + char *delFileName; + int tostdout = 0; + int force = 0; + int opt; + + while ((opt = getopt(argc, argv, "cf123456789dq")) != -1) { + switch (opt) { + case 'c': + tostdout = 1; + break; + case 'f': + force = 1; + break; + /* Ignore 1-9 (compression level) options */ + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + break; + case 'q': + break; +#ifdef BB_GUNZIP + case 'd': + optind = 1; + return gunzip_main(argc, argv); +#endif + default: + show_usage(); + } + } + if (optind == argc) { + optind--; + argv[optind] = "-"; + } + + for(opt = optind; opt < argc; opt++) + if (strcmp(argv[opt], "-") == 0) + tostdout |= 2; + + if (tostdout && force==0 && isatty(fileno(stdout))) + error_msg_and_die( "compressed data not written to terminal. Use -f to force it."); + + foreground = signal(SIGINT, SIG_IGN) != SIG_IGN; + if (foreground) { + (void) signal(SIGINT, (sig_type) abort_gzip); + } +#ifdef SIGTERM + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { + (void) signal(SIGTERM, (sig_type) abort_gzip); + } +#endif +#ifdef SIGHUP + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { + (void) signal(SIGHUP, (sig_type) abort_gzip); + } +#endif + + /* Allocate all global buffers (for DYN_ALLOC option) */ + ALLOC(uch, inbuf, INBUFSIZ + INBUF_EXTRA); + ALLOC(uch, outbuf, OUTBUFSIZ + OUTBUF_EXTRA); + ALLOC(ush, d_buf, DIST_BUFSIZE); + ALLOC(uch, window, 2L * WSIZE); + ALLOC(ush, tab_prefix, 1L << BITS); + + while (optind < argc) { + if (strcmp(argv[optind++], "-") == 0) { + strcpy(ofname, "stdin"); + + inFileNum = fileno(stdin); + time_stamp = 0; /* time unknown by default */ + ifile_size = -1L; /* convention for unknown size */ + tostdout |= 2; + } else { + tostdout &= ~2; + /* Open up the input file */ + strncpy(ifname, argv[optind++], MAX_PATH_LEN); + + /* Open input file */ + inFileNum = open(ifname, O_RDONLY); + if (inFileNum < 0) + perror_msg_and_die("%s", ifname); + /* Get the time stamp on the input file. */ + if (stat(ifname, &statBuf) < 0) + perror_msg_and_die("%s", ifname); + time_stamp = statBuf.st_ctime; + ifile_size = statBuf.st_size; + } + + + if (tostdout) { + /* And get to work */ + strcpy(ofname, "stdout"); + outFileNum = fileno(stdout); + + clear_bufs(); /* clear input and output buffers */ + part_nb = 0; + + /* Actually do the compression/decompression. */ + zip(inFileNum, outFileNum); + + } else { + + /* And get to work */ + strncpy(ofname, ifname, MAX_PATH_LEN - 4); + strcat(ofname, ".gz"); + + + /* Open output fille */ +#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) + outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW); +#else + outFileNum = open(ofname, O_RDWR | O_CREAT | O_EXCL); +#endif + if (outFileNum < 0) + perror_msg_and_die("%s", ofname); + /* Set permissions on the file */ + fchmod(outFileNum, statBuf.st_mode); + + clear_bufs(); /* clear input and output buffers */ + part_nb = 0; + + /* Actually do the compression/decompression. */ + result = zip(inFileNum, outFileNum); + close(outFileNum); + close(inFileNum); + /* Delete the original file */ + if (result == OK) + delFileName = ifname; + else + delFileName = ofname; + + if (unlink(delFileName) < 0) + perror_msg_and_die("%s", delFileName); + } + } /* while () */ + + return(exit_code); +} + +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1992-1993 Jean-loup Gailly + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License, see the file COPYING. + */ + +/* + * PURPOSE + * + * Encode various sets of source values using variable-length + * binary code trees. + * + * DISCUSSION + * + * The PKZIP "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in the ZIP file in a compressed form + * which is itself a Huffman encoding of the lengths of + * all the code strings (in ascending order by source values). + * The actual code strings are reconstructed from the lengths in + * the UNZIP process, as described in the "application note" + * (APPNOTE.TXT) distributed as part of PKWARE's PKZIP program. + * + * REFERENCES + * + * Lynch, Thomas J. + * Data Compression: Techniques and Applications, pp. 53-55. + * Lifetime Learning Publications, 1985. ISBN 0-534-03418-7. + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + * + * INTERFACE + * + * void ct_init (ush *attr, int *methodp) + * Allocate the match buffer, initialize the various tables and save + * the location of the internal file attribute (ascii/binary) and + * method (DEFLATE/STORE) + * + * void ct_tally (int dist, int lc); + * Save the match info and tally the frequency counts. + * + * long flush_block (char *buf, ulg stored_len, int eof) + * Determine the best encoding for the current block: dynamic trees, + * static trees or store, and output the encoded block to the zip + * file. Returns the total compressed length for the file so far. + * + */ + +/* =========================================================================== + * Constants + */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + + +static const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, + 4, 4, 5, 5, 5, 5, 0 }; + +static const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, + 10, 10, 11, 11, 12, 12, 13, 13 }; + +static const int extra_blbits[BL_CODES] /* extra bits for each bit length code */ += { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 }; + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#ifndef LIT_BUFSIZE +# ifdef SMALL_MEM +# define LIT_BUFSIZE 0x2000 +# else +# ifdef MEDIUM_MEM +# define LIT_BUFSIZE 0x4000 +# else +# define LIT_BUFSIZE 0x8000 +# endif +# endif +#endif +#ifndef DIST_BUFSIZE +# define DIST_BUFSIZE LIT_BUFSIZE +#endif +/* Sizes of match buffers for literals/lengths and distances. There are + * 4 reasons for limiting LIT_BUFSIZE to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input data is + * still in the window so we can still emit a stored block even when input + * comes from standard input. (This can also be done for all blocks if + * LIT_BUFSIZE is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting trees + * more frequently. + * - I can't count above 4 + * The current code is general and allows DIST_BUFSIZE < LIT_BUFSIZE (to save + * memory at the expense of compression). Some optimizations would be possible + * if we rely on DIST_BUFSIZE == LIT_BUFSIZE. + */ +#if LIT_BUFSIZE > INBUFSIZ +error cannot overlay l_buf and inbuf +#endif +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) *//* =========================================================================== + * Local data + *//* Data structure describing a single value and its code string. */ typedef struct ct_data { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +static ct_data dyn_ltree[HEAP_SIZE]; /* literal and length tree */ +static ct_data dyn_dtree[2 * D_CODES + 1]; /* distance tree */ + +static ct_data static_ltree[L_CODES + 2]; + +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see ct_init + * below). + */ + +static ct_data static_dtree[D_CODES]; + +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +static ct_data bl_tree[2 * BL_CODES + 1]; + +/* Huffman tree for the bit lengths */ + +typedef struct tree_desc { + ct_data *dyn_tree; /* the dynamic tree */ + ct_data *static_tree; /* corresponding static tree or NULL */ + const int *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ + int max_code; /* largest code with non zero frequency */ +} tree_desc; + +static tree_desc l_desc = + { dyn_ltree, static_ltree, extra_lbits, LITERALS + 1, L_CODES, + MAX_BITS, 0 }; + +static tree_desc d_desc = + { dyn_dtree, static_dtree, extra_dbits, 0, D_CODES, MAX_BITS, 0 }; + +static tree_desc bl_desc = + { bl_tree, (ct_data *) 0, extra_blbits, 0, BL_CODES, MAX_BL_BITS, + 0 }; + + +static ush bl_count[MAX_BITS + 1]; + +/* number of codes at each bit length for an optimal tree */ + +static const uch bl_order[BL_CODES] += { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +static int heap[2 * L_CODES + 1]; /* heap used to build the Huffman trees */ +static int heap_len; /* number of elements in the heap */ +static int heap_max; /* element of largest frequency */ + +/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + +static uch depth[2 * L_CODES + 1]; + +/* Depth of each subtree used as tie breaker for trees of equal frequency */ + +static uch length_code[MAX_MATCH - MIN_MATCH + 1]; + +/* length code for each normalized match length (0 == MIN_MATCH) */ + +static uch dist_code[512]; + +/* distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +static int base_length[LENGTH_CODES]; + +/* First normalized length for each code (0 = MIN_MATCH) */ + +static int base_dist[D_CODES]; + +/* First normalized distance for each code (0 = distance of 1) */ + +#define l_buf inbuf +/* DECLARE(uch, l_buf, LIT_BUFSIZE); buffer for literals or lengths */ + +/* DECLARE(ush, d_buf, DIST_BUFSIZE); buffer for distances */ + +static uch flag_buf[(LIT_BUFSIZE / 8)]; + +/* flag_buf is a bit array distinguishing literals from lengths in + * l_buf, thus indicating the presence or absence of a distance. + */ + +static unsigned last_lit; /* running index in l_buf */ +static unsigned last_dist; /* running index in d_buf */ +static unsigned last_flags; /* running index in flag_buf */ +static uch flags; /* current flags not yet saved in flag_buf */ +static uch flag_bit; /* current bit used in flags */ + +/* bits are filled in flags starting at bit 0 (least significant). + * Note: these flags are overkill in the current code since we don't + * take advantage of DIST_BUFSIZE == LIT_BUFSIZE. + */ + +static ulg opt_len; /* bit length of current block with optimal trees */ +static ulg static_len; /* bit length of current block with static trees */ + +static ulg compressed_len; /* total bit length of compressed file */ + + +static ush *file_type; /* pointer to UNKNOWN, BINARY or ASCII */ +static int *file_method; /* pointer to DEFLATE or STORE */ + +/* =========================================================================== + * Local (static) routines in this file. + */ + +static void init_block (void); +static void pqdownheap (ct_data * tree, int k); +static void gen_bitlen (tree_desc * desc); +static void gen_codes (ct_data * tree, int max_code); +static void build_tree (tree_desc * desc); +static void scan_tree (ct_data * tree, int max_code); +static void send_tree (ct_data * tree, int max_code); +static int build_bl_tree (void); +static void send_all_trees (int lcodes, int dcodes, int blcodes); +static void compress_block (ct_data * ltree, ct_data * dtree); +static void set_file_type (void); + + +#ifndef DEBUG +# define send_code(c, tree) send_bits(tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(c, tree) \ + { if (verbose>1) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(tree[c].Code, tree[c].Len); } +#endif + +#define d_code(dist) \ + ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. dist_code[256] and dist_code[257] are never + * used. + */ + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Allocate the match buffer, initialize the various tables and save the + * location of the internal file attribute (ascii/binary) and method + * (DEFLATE/STORE). + */ +static void ct_init(ush *attr, int *methodp) +{ + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + + file_type = attr; + file_method = methodp; + compressed_len = 0L; + + if (static_dtree[0].Len != 0) + return; /* ct_init already called */ + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES - 1; code++) { + base_length[code] = length; + for (n = 0; n < (1 << extra_lbits[code]); n++) { + length_code[length++] = (uch) code; + } + } + Assert(length == 256, "ct_init: length != 256"); + /* Note that the length 255 (match length 258) can be represented + * in two different ways: code 284 + 5 bits or code 285, so we + * overwrite length_code[255] to use the best encoding: + */ + length_code[length - 1] = (uch) code; + + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1 << extra_dbits[code]); n++) { + dist_code[dist++] = (uch) code; + } + } + Assert(dist == 256, "ct_init: dist != 256"); + dist >>= 7; /* from now on, all distances are divided by 128 */ + for (; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { + dist_code[256 + dist++] = (uch) code; + } + } + Assert(dist == 256, "ct_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) + bl_count[bits] = 0; + n = 0; + while (n <= 143) + static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) + static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) + static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) + static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *) static_ltree, L_CODES + 1); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse(n, 5); + } + + /* Initialize the first block of the first file: */ + init_block(); +} + +/* =========================================================================== + * Initialize a new block. + */ +static void init_block() +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) + dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) + dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) + bl_tree[n].Freq = 0; + + dyn_ltree[END_BLOCK].Freq = 1; + opt_len = static_len = 0L; + last_lit = last_dist = last_flags = 0; + flags = 0; + flag_bit = 1; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(tree, top) \ +{\ + top = heap[SMALLEST]; \ + heap[SMALLEST] = heap[heap_len--]; \ + pqdownheap(tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +static void pqdownheap(ct_data *tree, int k) +{ + int v = heap[k]; + int j = k << 1; /* left son of k */ + + while (j <= heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < heap_len && smaller(tree, heap[j + 1], heap[j])) + j++; + + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, heap[j])) + break; + + /* Exchange v with the smallest son */ + heap[k] = heap[j]; + k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +static void gen_bitlen(tree_desc *desc) +{ + ct_data *tree = desc->dyn_tree; + const int *extra = desc->extra_bits; + int base = desc->extra_base; + int max_code = desc->max_code; + int max_length = desc->max_length; + ct_data *stree = desc->static_tree; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) + bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[heap[heap_max]].Len = 0; /* root of the heap */ + + for (h = heap_max + 1; h < HEAP_SIZE; h++) { + n = heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) + bits = max_length, overflow++; + tree[n].Len = (ush) bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) + continue; /* not a leaf node */ + + bl_count[bits]++; + xbits = 0; + if (n >= base) + xbits = extra[n - base]; + f = tree[n].Freq; + opt_len += (ulg) f *(bits + xbits); + + if (stree) + static_len += (ulg) f *(stree[n].Len + xbits); + } + if (overflow == 0) + return; + + Trace((stderr, "\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length - 1; + while (bl_count[bits] == 0) + bits--; + bl_count[bits]--; /* move one leaf down the tree */ + bl_count[bits + 1] += 2; /* move one overflow item as its brother */ + bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = bl_count[bits]; + while (n != 0) { + m = heap[--h]; + if (m > max_code) + continue; + if (tree[m].Len != (unsigned) bits) { + Trace( + (stderr, "code %d bits %d->%d\n", m, tree[m].Len, + bits)); + opt_len += + ((long) bits - + (long) tree[m].Len) * (long) tree[m].Freq; + tree[m].Len = (ush) bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +static void gen_codes(ct_data *tree, int max_code) +{ + ush next_code[MAX_BITS + 1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits - 1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert(code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, + "inconsistent bit counts"); + Tracev((stderr, "\ngen_codes: max_code %d ", max_code)); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].Len; + + if (len == 0) + continue; + /* Now reverse the bits */ + tree[n].Code = bi_reverse(next_code[len]++, len); + + Tracec(tree != static_ltree, + (stderr, "\nn %3d %c l %2d c %4x (%x) ", n, + (isgraph(n) ? n : ' '), len, tree[n].Code, + next_code[len] - 1)); + } +} + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +static void build_tree(tree_desc *desc) +{ + ct_data *tree = desc->dyn_tree; + ct_data *stree = desc->static_tree; + int elems = desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node = elems; /* next internal node of the tree */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + heap_len = 0, heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + heap[++heap_len] = max_code = n; + depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (heap_len < 2) { + int new = heap[++heap_len] = (max_code < 2 ? ++max_code : 0); + + tree[new].Freq = 1; + depth[new] = 0; + opt_len--; + if (stree) + static_len -= stree[new].Len; + /* new is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = heap_len / 2; n >= 1; n--) + pqdownheap(tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + do { + pqremove(tree, n); /* n = node of least frequency */ + m = heap[SMALLEST]; /* m = node of next least frequency */ + + heap[--heap_max] = n; /* keep the nodes sorted by frequency */ + heap[--heap_max] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + depth[node] = (uch) (MAX(depth[n], depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush) node; +#ifdef DUMP_BL_TREE + if (tree == bl_tree) { + fprintf(stderr, "\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, + tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + heap[SMALLEST] = node++; + pqdownheap(tree, SMALLEST); + + } while (heap_len >= 2); + + heap[--heap_max] = heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen((tree_desc *) desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes((ct_data *) tree, max_code); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. Updates opt_len to take into account the repeat + * counts. (The contribution of the bit length codes will be added later + * during the construction of bl_tree.) + */ +static void scan_tree(ct_data *tree, int max_code) +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) + max_count = 138, min_count = 3; + tree[max_code + 1].Len = (ush) 0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[n + 1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) + bl_tree[curlen].Freq++; + bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + bl_tree[REPZ_3_10].Freq++; + } else { + bl_tree[REPZ_11_138].Freq++; + } + count = 0; + prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +static void send_tree(ct_data *tree, int max_code) +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + +/* tree[max_code+1].Len = -1; *//* guard already set */ + if (nextlen == 0) + max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[n + 1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { + send_code(curlen, bl_tree); + } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(curlen, bl_tree); + count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(REP_3_6, bl_tree); + send_bits(count - 3, 2); + + } else if (count <= 10) { + send_code(REPZ_3_10, bl_tree); + send_bits(count - 3, 3); + + } else { + send_code(REPZ_11_138, bl_tree); + send_bits(count - 11, 7); + } + count = 0; + prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +static const int build_bl_tree() +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree((ct_data *) dyn_ltree, l_desc.max_code); + scan_tree((ct_data *) dyn_dtree, d_desc.max_code); + + /* Build the bit length tree: */ + build_tree((tree_desc *) (&bl_desc)); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) { + if (bl_tree[bl_order[max_blindex]].Len != 0) + break; + } + /* Update opt_len to include the bit length tree and counts */ + opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; + Tracev( + (stderr, "\ndyn trees: dyn %ld, stat %ld", opt_len, + static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +static void send_all_trees(int lcodes, int dcodes, int blcodes) +{ + int rank; /* index in bl_order */ + + Assert(lcodes >= 257 && dcodes >= 1 + && blcodes >= 4, "not enough codes"); + Assert(lcodes <= L_CODES && dcodes <= D_CODES + && blcodes <= BL_CODES, "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(lcodes - 257, 5); /* not +255 as stated in appnote.txt */ + send_bits(dcodes - 1, 5); + send_bits(blcodes - 4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", bits_sent)); + + send_tree((ct_data *) dyn_ltree, lcodes - 1); /* send the literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", bits_sent)); + + send_tree((ct_data *) dyn_dtree, dcodes - 1); /* send the distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", bits_sent)); +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. This function + * returns the total compressed length for the file so far. + */ +static ulg flush_block(char *buf, ulg stored_len, int eof) +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex; /* index of last bit length code of non zero freq */ + + flag_buf[last_flags] = flags; /* Save the flags for the last 8 items */ + + /* Check if the file is ascii or binary */ + if (*file_type == (ush) UNKNOWN) + set_file_type(); + + /* Construct the literal and distance trees */ + build_tree((tree_desc *) (&l_desc)); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", opt_len, static_len)); + + build_tree((tree_desc *) (&d_desc)); + Tracev( + (stderr, "\ndist data: dyn %ld, stat %ld", opt_len, + static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(); + + /* Determine the best encoding. Compute first the block length in bytes */ + opt_lenb = (opt_len + 3 + 7) >> 3; + static_lenb = (static_len + 3 + 7) >> 3; + + Trace( + (stderr, + "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ", + opt_lenb, opt_len, static_lenb, static_len, stored_len, + last_lit, last_dist)); + + if (static_lenb <= opt_lenb) + opt_lenb = static_lenb; + + /* If compression failed and this is the first and last block, + * and if the zip file can be seeked (to rewrite the local header), + * the whole file is transformed into a stored file: + */ + if (stored_len <= opt_lenb && eof && compressed_len == 0L + && seekable()) { + /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */ + if (buf == (char *) 0) + error_msg("block vanished"); + + copy_block(buf, (unsigned) stored_len, 0); /* without header */ + compressed_len = stored_len << 3; + *file_method = STORED; + + } else if (stored_len + 4 <= opt_lenb && buf != (char *) 0) { + /* 4: two words for the lengths */ + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + send_bits((STORED_BLOCK << 1) + eof, 3); /* send block type */ + compressed_len = (compressed_len + 3 + 7) & ~7L; + compressed_len += (stored_len + 4) << 3; + + copy_block(buf, (unsigned) stored_len, 1); /* with header */ + + } else if (static_lenb == opt_lenb) { + send_bits((STATIC_TREES << 1) + eof, 3); + compress_block((ct_data *) static_ltree, + (ct_data *) static_dtree); + compressed_len += 3 + static_len; + } else { + send_bits((DYN_TREES << 1) + eof, 3); + send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1, + max_blindex + 1); + compress_block((ct_data *) dyn_ltree, + (ct_data *) dyn_dtree); + compressed_len += 3 + opt_len; + } + Assert(compressed_len == bits_sent, "bad compressed size"); + init_block(); + + if (eof) { + bi_windup(); + compressed_len += 7; /* align on byte boundary */ + } + Tracev((stderr, "\ncomprlen %lu(%lu) ", compressed_len >> 3, + compressed_len - 7 * eof)); + + return compressed_len >> 3; +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +static int ct_tally(int dist, int lc) +{ + l_buf[last_lit++] = (uch) lc; + if (dist == 0) { + /* lc is the unmatched char */ + dyn_ltree[lc].Freq++; + } else { + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush) dist < (ush) MAX_DIST && + (ush) lc <= (ush) (MAX_MATCH - MIN_MATCH) && + (ush) d_code(dist) < (ush) D_CODES, "ct_tally: bad match"); + + dyn_ltree[length_code[lc] + LITERALS + 1].Freq++; + dyn_dtree[d_code(dist)].Freq++; + + d_buf[last_dist++] = (ush) dist; + flags |= flag_bit; + } + flag_bit <<= 1; + + /* Output the flags if they fill a byte: */ + if ((last_lit & 7) == 0) { + flag_buf[last_flags++] = flags; + flags = 0, flag_bit = 1; + } + /* Try to guess if it is profitable to stop the current block here */ + if ((last_lit & 0xfff) == 0) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg) last_lit * 8L; + ulg in_length = (ulg) strstart - block_start; + int dcode; + + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += + (ulg) dyn_dtree[dcode].Freq * (5L + extra_dbits[dcode]); + } + out_length >>= 3; + Trace( + (stderr, + "\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ", + last_lit, last_dist, in_length, out_length, + 100L - out_length * 100L / in_length)); + if (last_dist < last_lit / 2 && out_length < in_length / 2) + return 1; + } + return (last_lit == LIT_BUFSIZE - 1 || last_dist == DIST_BUFSIZE); + /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +static void compress_block(ct_data *ltree, ct_data *dtree) +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned dx = 0; /* running index in d_buf */ + unsigned fx = 0; /* running index in flag_buf */ + uch flag = 0; /* current flags */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (last_lit != 0) + do { + if ((lx & 7) == 0) + flag = flag_buf[fx++]; + lc = l_buf[lx++]; + if ((flag & 1) == 0) { + send_code(lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr, " '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = length_code[lc]; + send_code(code + LITERALS + 1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(lc, extra); /* send the extra length bits */ + } + dist = d_buf[dx++]; + /* Here, dist is the match distance - 1 */ + code = d_code(dist); + Assert(code < D_CODES, "bad d_code"); + + send_code(code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + flag >>= 1; + } while (lx < last_lit); + + send_code(END_BLOCK, ltree); +} + +/* =========================================================================== + * Set the file type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +static void set_file_type() +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + + while (n < 7) + bin_freq += dyn_ltree[n++].Freq; + while (n < 128) + ascii_freq += dyn_ltree[n++].Freq; + while (n < LITERALS) + bin_freq += dyn_ltree[n++].Freq; + *file_type = bin_freq > (ascii_freq >> 2) ? BINARY : ASCII; + if (*file_type == BINARY && translate_eol) { + error_msg("-l used on binary file"); + } +} + +/* zip.c -- compress files to the gzip or pkzip format + * Copyright (C) 1992-1993 Jean-loup Gailly + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License, see the file COPYING. + */ + + +static ulg crc; /* crc on uncompressed file data */ +static long header_bytes; /* number of bytes in gzip header */ + +/* =========================================================================== + * Deflate in to out. + * IN assertions: the input and output buffers are cleared. + * The variables time_stamp and save_orig_name are initialized. + */ +static int zip(int in, int out) +{ + uch my_flags = 0; /* general purpose bit flags */ + ush attr = 0; /* ascii/binary flag */ + ush deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */ + + ifd = in; + ofd = out; + outcnt = 0; + + /* Write the header to the gzip file. See algorithm.doc for the format */ + + + method = DEFLATED; + put_byte(GZIP_MAGIC[0]); /* magic header */ + put_byte(GZIP_MAGIC[1]); + put_byte(DEFLATED); /* compression method */ + + put_byte(my_flags); /* general flags */ + put_long(time_stamp); + + /* Write deflated file to zip file */ + crc = updcrc(0, 0); + + bi_init(out); + ct_init(&attr, &method); + lm_init(&deflate_flags); + + put_byte((uch) deflate_flags); /* extra flags */ + put_byte(OS_CODE); /* OS identifier */ + + header_bytes = (long) outcnt; + + (void) deflate(); + + /* Write the crc and uncompressed size */ + put_long(crc); + put_long(isize); + header_bytes += 2 * sizeof(long); + + flush_outbuf(); + return OK; +} + + +/* =========================================================================== + * Read a new buffer from the current input file, perform end-of-line + * translation, and update the crc and input file size. + * IN assertion: size >= 2 (for end-of-line translation) + */ +static int file_read(char *buf, unsigned size) +{ + unsigned len; + + Assert(insize == 0, "inbuf not empty"); + + len = read(ifd, buf, size); + if (len == (unsigned) (-1) || len == 0) + return (int) len; + + crc = updcrc((uch *) buf, len); + isize += (ulg) len; + return (int) len; +} + +/* =========================================================================== + * Write the output buffer outbuf[0..outcnt-1] and update bytes_out. + * (used for the compressed data only) + */ +static void flush_outbuf() +{ + if (outcnt == 0) + return; + + write_buf(ofd, (char *) outbuf, outcnt); + outcnt = 0; +} diff --git a/halt.c b/halt.c new file mode 100644 index 000000000..8f7cc67e0 --- /dev/null +++ b/halt.c @@ -0,0 +1,41 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini halt implementation for busybox + * + * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 1999-2002 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 + * + */ + +#include "busybox.h" +#include + +extern int halt_main(int argc, char **argv) +{ +#ifdef BB_FEATURE_LINUXRC + /* don't assume init's pid == 1 */ + long *pid = find_pid_by_name("init"); + if (!pid || *pid<=0) { + pid = find_pid_by_name("linuxrc"); + if (!pid || *pid<=0) + error_msg_and_die("no process killed"); + } + return(kill(*pid, SIGUSR1)); +#else + return(kill(1, SIGUSR1)); +#endif +} diff --git a/head.c b/head.c new file mode 100644 index 000000000..ad21e1b95 --- /dev/null +++ b/head.c @@ -0,0 +1,102 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini head implementation for busybox + * + * Copyright (C) 1999 by Lineo, inc. and John Beppu + * Copyright (C) 1999,2000,2001 by John Beppu + * + * 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 "busybox.h" + +static int head(int len, FILE *fp) +{ + int i; + char *input; + + for (i = 0; i < len; i++) { + if ((input = get_line_from_file(fp)) == NULL) + break; + fputs(input, stdout); + free(input); + } + return 0; +} + +/* BusyBoxed head(1) */ +int head_main(int argc, char **argv) +{ + FILE *fp; + int need_headers, opt, len = 10, status = EXIT_SUCCESS; + + if (( argc >= 2 ) && ( argv [1][0] == '-' ) && isdigit ( argv [1][1] )) { + len = atoi ( &argv [1][1] ); + optind = 2; + } + + /* parse argv[] */ + while ((opt = getopt(argc, argv, "n:")) > 0) { + switch (opt) { + case 'n': + len = atoi(optarg); + if (len >= 0) + break; + /* fallthrough */ + default: + show_usage(); + } + } + + /* get rest of argv[] or stdin if nothing's left */ + if (argv[optind] == NULL) { + head(len, stdin); + return status; + } + + need_headers = optind != (argc - 1); + while (argv[optind]) { + if (strcmp(argv[optind], "-") == 0) { + fp = stdin; + argv[optind] = "standard input"; + } else { + if ((fp = wfopen(argv[optind], "r")) == NULL) + status = EXIT_FAILURE; + } + if (fp) { + if (need_headers) { + printf("==> %s <==\n", argv[optind]); + } + head(len, fp); + if (ferror(fp)) { + perror_msg("%s", argv[optind]); + status = EXIT_FAILURE; + } + if (optind < argc - 1) + putchar('\n'); + if (fp != stdin) + fclose(fp); + } + optind++; + } + + return status; +} diff --git a/hostid.c b/hostid.c new file mode 100644 index 000000000..68a2cc659 --- /dev/null +++ b/hostid.c @@ -0,0 +1,32 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini hostid implementation for busybox + * + * 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 + * + */ + +#include +#include +#include +#include "busybox.h" + +extern int hostid_main(int argc, char **argv) +{ + printf("%lx\n", gethostid()); + return EXIT_SUCCESS; +} diff --git a/hostname.c b/hostname.c new file mode 100644 index 000000000..3cb357afb --- /dev/null +++ b/hostname.c @@ -0,0 +1,130 @@ +/* vi: set sw=4 ts=4: */ +/* + * $Id: hostname.c,v 1.32 2002/10/18 22:07:41 andersen Exp $ + * Mini hostname implementation for busybox + * + * Copyright (C) 1999 by Randolph Chung + * + * adjusted by Erik Andersen to remove + * use of long options and GNU getopt. Improved the usage info. + * + * 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 "busybox.h" + +extern char *optarg; /* in unistd.h */ +extern int optind, opterr, optopt; /* in unistd.h */ + +static void do_sethostname(char *s, int isfile) +{ + FILE *f; + char buf[255]; + + if (!s) + return; + if (!isfile) { + if (sethostname(s, strlen(s)) < 0) { + if (errno == EPERM) + error_msg_and_die("you must be root to change the hostname"); + else + perror_msg_and_die("sethostname"); + } + } else { + f = xfopen(s, "r"); + while (fgets(buf, 255, f) != NULL) { + if (buf[0] =='#') { + continue; + } + chomp(buf); + do_sethostname(buf, 0); + } +#ifdef BB_FEATURE_CLEAN_UP + fclose(f); +#endif + } +} + +int hostname_main(int argc, char **argv) +{ + int opt; + int type = 0; + struct hostent *hp; + char *filename = NULL; + char buf[255]; + char *p = NULL; + + if (argc < 1) + show_usage(); + + while ((opt = getopt(argc, argv, "dfisF:")) > 0) { + switch (opt) { + case 'd': + case 'f': + case 'i': + case 's': + type = opt; + break; + case 'F': + filename = optarg; + break; + default: + show_usage(); + } + } + + /* Output in desired format */ + if (type != 0) { + gethostname(buf, 255); + hp = xgethostbyname(buf); + p = strchr(hp->h_name, '.'); + if (type == 'f') { + puts(hp->h_name); + } else if (type == 's') { + if (p != NULL) { + *p = 0; + } + puts(buf); + } else if (type == 'd') { + if (p) puts(p + 1); + } else if (type == 'i') { + while (hp->h_addr_list[0]) { + printf("%s ", inet_ntoa(*(struct in_addr *) (*hp->h_addr_list++))); + } + printf("\n"); + } + } + /* Set the hostname */ + else if (filename != NULL) { + do_sethostname(filename, 1); + } else if (optind < argc) { + do_sethostname(argv[optind], 0); + } + /* Or if all else fails, + * just print the current hostname */ + else { + gethostname(buf, 255); + puts(buf); + } + return(0); +} diff --git a/hush.c b/hush.c new file mode 100644 index 000000000..56df5e01d --- /dev/null +++ b/hush.c @@ -0,0 +1,2971 @@ +/* vi: set sw=4 ts=4: */ +/* + * sh.c -- a prototype Bourne shell grammar parser + * Intended to follow the original Thompson and Ritchie + * "small and simple is beautiful" philosophy, which + * incidentally is a good match to today's BusyBox. + * + * Copyright (C) 2000,2001 Larry Doolittle + * + * Credits: + * The parser routines proper are all original material, first + * written Dec 2000 and Jan 2001 by Larry Doolittle. The + * execution engine, the builtins, and much of the underlying + * support has been adapted from busybox-0.49pre's lash, which is + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * written by Erik Andersen . That, in turn, + * is based in part on ladsh.c, by Michael K. Johnson and Erik W. + * Troan, which they placed in the public domain. I don't know + * how much of the Johnson/Troan code has survived the repeated + * rewrites. + * + * Other credits: + * simple_itoa() was lifted from boa-0.93.15 + * b_addchr() derived from similar w_addchar function in glibc-2.2 + * setup_redirect(), redirect_opt_num(), and big chunks of main() + * and many builtins derived from contributions by Erik Andersen + * miscellaneous bugfixes from Matt Kraai + * + * There are two big (and related) architecture differences between + * this parser and the lash parser. One is that this version is + * actually designed from the ground up to understand nearly all + * of the Bourne grammar. The second, consequential change is that + * the parser and input reader have been turned inside out. Now, + * the parser is in control, and asks for input as needed. The old + * way had the input reader in control, and it asked for parsing to + * take place as needed. The new way makes it much easier to properly + * handle the recursion implicit in the various substitutions, especially + * across continuation lines. + * + * Bash grammar not implemented: (how many of these were in original sh?) + * $@ (those sure look like weird quoting rules) + * $_ + * ! negation operator for pipes + * &> and >& redirection of stdout+stderr + * Brace Expansion + * Tilde Expansion + * fancy forms of Parameter Expansion + * aliases + * Arithmetic Expansion + * <(list) and >(list) Process Substitution + * reserved words: case, esac, select, function + * Here Documents ( << word ) + * Functions + * Major bugs: + * job handling woefully incomplete and buggy + * reserved word execution woefully incomplete and buggy + * to-do: + * port selected bugfixes from post-0.49 busybox lash - done? + * finish implementing reserved words: for, while, until, do, done + * change { and } from special chars to reserved words + * builtins: break, continue, eval, return, set, trap, ulimit + * test magic exec + * handle children going into background + * clean up recognition of null pipes + * check setting of global_argc and global_argv + * control-C handling, probably with longjmp + * follow IFS rules more precisely, including update semantics + * figure out what to do with backslash-newline + * explain why we use signal instead of sigaction + * propagate syntax errors, die on resource errors? + * continuation lines, both explicit and implicit - done? + * memory leak finding and plugging - done? + * more testing, especially quoting rules and redirection + * document how quoting rules not precisely followed for variable assignments + * maybe change map[] to use 2-bit entries + * (eventually) remove all the printf's + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include /* isalpha, isdigit */ +#include /* getpid */ +#include /* getenv, atoi */ +#include /* strchr */ +#include /* popen etc. */ +#include /* glob, of course */ +#include /* va_list */ +#include +#include +#include /* should be pretty obvious */ + +#include /* ulimit */ +#include +#include +#include + +/* #include */ +/* #define DEBUG_SHELL */ + +#ifdef BB_VER +#include "busybox.h" +#include "cmdedit.h" +#else +#define applet_name "hush" +#include "standalone.h" +#define hush_main main +#undef BB_FEATURE_SH_FANCY_PROMPT +#endif +#define SPECIAL_VAR_SYMBOL 03 +#define FLAG_EXIT_FROM_LOOP 1 +#define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */ +#define FLAG_REPARSING (1 << 2) /* >=2nd pass */ + +typedef enum { + REDIRECT_INPUT = 1, + REDIRECT_OVERWRITE = 2, + REDIRECT_APPEND = 3, + REDIRECT_HEREIS = 4, + REDIRECT_IO = 5 +} redir_type; + +/* The descrip member of this structure is only used to make debugging + * output pretty */ +struct {int mode; int default_fd; char *descrip;} redir_table[] = { + { 0, 0, "()" }, + { O_RDONLY, 0, "<" }, + { O_CREAT|O_TRUNC|O_WRONLY, 1, ">" }, + { O_CREAT|O_APPEND|O_WRONLY, 1, ">>" }, + { O_RDONLY, -1, "<<" }, + { O_RDWR, 1, "<>" } +}; + +typedef enum { + PIPE_SEQ = 1, + PIPE_AND = 2, + PIPE_OR = 3, + PIPE_BG = 4, +} pipe_style; + +/* might eventually control execution */ +typedef enum { + RES_NONE = 0, + RES_IF = 1, + RES_THEN = 2, + RES_ELIF = 3, + RES_ELSE = 4, + RES_FI = 5, + RES_FOR = 6, + RES_WHILE = 7, + RES_UNTIL = 8, + RES_DO = 9, + RES_DONE = 10, + RES_XXXX = 11, + RES_IN = 12, + RES_SNTX = 13 +} reserved_style; +#define FLAG_END (1<, but protected with __USE_GNU */ + +/* "globals" within this file */ +static char *ifs; +static char map[256]; +static int fake_mode; +static int interactive; +static struct close_me *close_me_head; +static const char *cwd; +static struct pipe *job_list; +static unsigned int last_bg_pid; +static unsigned int last_jobid; +static unsigned int shell_terminal; +static char *PS1; +static char *PS2; +struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 }; +struct variables *top_vars = &shell_ver; + + +#define B_CHUNK (100) +#define B_NOSPAC 1 + +typedef struct { + char *data; + int length; + int maxlen; + int quote; + int nonnull; +} o_string; +#define NULL_O_STRING {NULL,0,0,0,0} +/* used for initialization: + o_string foo = NULL_O_STRING; */ + +/* I can almost use ordinary FILE *. Is open_memstream() universally + * available? Where is it documented? */ +struct in_str { + const char *p; + char peek_buf[2]; + int __promptme; + int promptmode; + FILE *file; + int (*get) (struct in_str *); + int (*peek) (struct in_str *); +}; +#define b_getch(input) ((input)->get(input)) +#define b_peek(input) ((input)->peek(input)) + +#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" + +struct built_in_command { + char *cmd; /* name */ + char *descr; /* description */ + int (*function) (struct child_prog *); /* function ptr */ +}; + +/* belongs in busybox.h */ +static inline int max(int a, int b) { + return (a>b)?a:b; +} + +/* This should be in utility.c */ +#ifdef DEBUG_SHELL +static void debug_printf(const char *format, ...) +{ + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); +} +#else +static inline void debug_printf(const char *format, ...) { } +#endif +#define final_printf debug_printf + +static void __syntax(char *file, int line) { + error_msg("syntax error %s:%d", file, line); +} +#define syntax() __syntax(__FILE__, __LINE__) + +/* Index of subroutines: */ +/* function prototypes for builtins */ +static int builtin_cd(struct child_prog *child); +static int builtin_env(struct child_prog *child); +static int builtin_eval(struct child_prog *child); +static int builtin_exec(struct child_prog *child); +static int builtin_exit(struct child_prog *child); +static int builtin_export(struct child_prog *child); +static int builtin_fg_bg(struct child_prog *child); +static int builtin_help(struct child_prog *child); +static int builtin_jobs(struct child_prog *child); +static int builtin_pwd(struct child_prog *child); +static int builtin_read(struct child_prog *child); +static int builtin_set(struct child_prog *child); +static int builtin_shift(struct child_prog *child); +static int builtin_source(struct child_prog *child); +static int builtin_umask(struct child_prog *child); +static int builtin_unset(struct child_prog *child); +static int builtin_not_written(struct child_prog *child); +/* o_string manipulation: */ +static int b_check_space(o_string *o, int len); +static int b_addchr(o_string *o, int ch); +static void b_reset(o_string *o); +static int b_addqchr(o_string *o, int ch, int quote); +static int b_adduint(o_string *o, unsigned int i); +/* in_str manipulations: */ +static int static_get(struct in_str *i); +static int static_peek(struct in_str *i); +static int file_get(struct in_str *i); +static int file_peek(struct in_str *i); +static void setup_file_in_str(struct in_str *i, FILE *f); +static void setup_string_in_str(struct in_str *i, const char *s); +/* close_me manipulations: */ +static void mark_open(int fd); +static void mark_closed(int fd); +static void close_all(); +/* "run" the final data structures: */ +static char *indenter(int i); +static int free_pipe_list(struct pipe *head, int indent); +static int free_pipe(struct pipe *pi, int indent); +/* really run the final data structures: */ +static int setup_redirects(struct child_prog *prog, int squirrel[]); +static int run_list_real(struct pipe *pi); +static void pseudo_exec(struct child_prog *child) __attribute__ ((noreturn)); +static int run_pipe_real(struct pipe *pi); +/* extended glob support: */ +static int globhack(const char *src, int flags, glob_t *pglob); +static int glob_needed(const char *s); +static int xglob(o_string *dest, int flags, glob_t *pglob); +/* variable assignment: */ +static int is_assignment(const char *s); +/* data structure manipulation: */ +static int setup_redirect(struct p_context *ctx, int fd, redir_type style, struct in_str *input); +static void initialize_context(struct p_context *ctx); +static int done_word(o_string *dest, struct p_context *ctx); +static int done_command(struct p_context *ctx); +static int done_pipe(struct p_context *ctx, pipe_style type); +/* primary string parsing: */ +static int redirect_dup_num(struct in_str *input); +static int redirect_opt_num(o_string *o); +static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end); +static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); +static char *lookup_param(char *src); +static char *make_string(char **inp); +static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); +static int parse_string(o_string *dest, struct p_context *ctx, const char *src); +static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger); +/* setup: */ +static int parse_stream_outer(struct in_str *inp, int flag); +static int parse_string_outer(const char *s, int flag); +static int parse_file_outer(FILE *f); +/* job management: */ +static int checkjobs(struct pipe* fg_pipe); +static void insert_bg_job(struct pipe *pi); +static void remove_bg_job(struct pipe *pi); +/* local variable support */ +static char **make_list_in(char **inp, char *name); +static char *insert_var_value(char *inp); +static char *get_local_var(const char *var); +static void unset_local_var(const char *name); +static int set_local_var(const char *s, int flg_export); + +/* Table of built-in functions. They can be forked or not, depending on + * context: within pipes, they fork. As simple commands, they do not. + * When used in non-forking context, they can change global variables + * in the parent shell process. If forked, of course they can not. + * For example, 'unset foo | whatever' will parse and run, but foo will + * still be set at the end. */ +static struct built_in_command bltins[] = { + {"bg", "Resume a job in the background", builtin_fg_bg}, + {"break", "Exit for, while or until loop", builtin_not_written}, + {"cd", "Change working directory", builtin_cd}, + {"continue", "Continue for, while or until loop", builtin_not_written}, + {"env", "Print all environment variables", builtin_env}, + {"eval", "Construct and run shell command", builtin_eval}, + {"exec", "Exec command, replacing this shell with the exec'd process", + builtin_exec}, + {"exit", "Exit from shell()", builtin_exit}, + {"export", "Set environment variable", builtin_export}, + {"fg", "Bring job into the foreground", builtin_fg_bg}, + {"jobs", "Lists the active jobs", builtin_jobs}, + {"pwd", "Print current directory", builtin_pwd}, + {"read", "Input environment variable", builtin_read}, + {"return", "Return from a function", builtin_not_written}, + {"set", "Set/unset shell local variables", builtin_set}, + {"shift", "Shift positional parameters", builtin_shift}, + {"trap", "Trap signals", builtin_not_written}, + {"ulimit","Controls resource limits", builtin_not_written}, + {"umask","Sets file creation mask", builtin_umask}, + {"unset", "Unset environment variable", builtin_unset}, + {".", "Source-in and run commands in a file", builtin_source}, + {"help", "List shell built-in commands", builtin_help}, + {NULL, NULL, NULL} +}; + +static const char *set_cwd(void) +{ + if(cwd==unknown) + cwd = NULL; /* xgetcwd(arg) called free(arg) */ + cwd = xgetcwd((char *)cwd); + if (!cwd) + cwd = unknown; + return cwd; +} + +/* built-in 'eval' handler */ +static int builtin_eval(struct child_prog *child) +{ + char *str = NULL; + int rcode = EXIT_SUCCESS; + + if (child->argv[1]) { + str = make_string(child->argv + 1); + parse_string_outer(str, FLAG_EXIT_FROM_LOOP | + FLAG_PARSE_SEMICOLON); + free(str); + rcode = last_return_code; + } + return rcode; +} + +/* built-in 'cd ' handler */ +static int builtin_cd(struct child_prog *child) +{ + char *newdir; + if (child->argv[1] == NULL) + newdir = getenv("HOME"); + else + newdir = child->argv[1]; + if (chdir(newdir)) { + printf("cd: %s: %s\n", newdir, strerror(errno)); + return EXIT_FAILURE; + } + set_cwd(); + return EXIT_SUCCESS; +} + +/* built-in 'env' handler */ +static int builtin_env(struct child_prog *dummy) +{ + char **e = environ; + if (e == NULL) return EXIT_FAILURE; + for (; *e; e++) { + puts(*e); + } + return EXIT_SUCCESS; +} + +/* built-in 'exec' handler */ +static int builtin_exec(struct child_prog *child) +{ + if (child->argv[1] == NULL) + return EXIT_SUCCESS; /* Really? */ + child->argv++; + pseudo_exec(child); + /* never returns */ +} + +/* built-in 'exit' handler */ +static int builtin_exit(struct child_prog *child) +{ + if (child->argv[1] == NULL) + exit(last_return_code); + exit (atoi(child->argv[1])); +} + +/* built-in 'export VAR=value' handler */ +static int builtin_export(struct child_prog *child) +{ + int res = 0; + char *name = child->argv[1]; + + if (name == NULL) { + return (builtin_env(child)); + } + + name = strdup(name); + + if(name) { + char *value = strchr(name, '='); + + if (!value) { + char *tmp; + /* They are exporting something without an =VALUE */ + + value = get_local_var(name); + if (value) { + size_t ln = strlen(name); + + tmp = realloc(name, ln+strlen(value)+2); + if(tmp==NULL) + res = -1; + else { + sprintf(tmp+ln, "=%s", value); + name = tmp; + } + } else { + /* bash does not return an error when trying to export + * an undefined variable. Do likewise. */ + res = 1; + } + } + } + if (res<0) + perror_msg("export"); + else if(res==0) + res = set_local_var(name, 1); + else + res = 0; + free(name); + return res; +} + +/* built-in 'fg' and 'bg' handler */ +static int builtin_fg_bg(struct child_prog *child) +{ + int i, jobnum; + struct pipe *pi=NULL; + + if (!interactive) + return EXIT_FAILURE; + /* If they gave us no args, assume they want the last backgrounded task */ + if (!child->argv[1]) { + for (pi = job_list; pi; pi = pi->next) { + if (pi->jobid == last_jobid) { + break; + } + } + if (!pi) { + error_msg("%s: no current job", child->argv[0]); + return EXIT_FAILURE; + } + } else { + if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { + error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]); + return EXIT_FAILURE; + } + for (pi = job_list; pi; pi = pi->next) { + if (pi->jobid == jobnum) { + break; + } + } + if (!pi) { + error_msg("%s: %d: no such job", child->argv[0], jobnum); + return EXIT_FAILURE; + } + } + + if (*child->argv[0] == 'f') { + /* Put the job into the foreground. */ + tcsetpgrp(shell_terminal, pi->pgrp); + } + + /* Restart the processes in the job */ + for (i = 0; i < pi->num_progs; i++) + pi->progs[i].is_stopped = 0; + + if ( (i=kill(- pi->pgrp, SIGCONT)) < 0) { + if (i == ESRCH) { + remove_bg_job(pi); + } else { + perror_msg("kill (SIGCONT)"); + } + } + + pi->stopped_progs = 0; + return EXIT_SUCCESS; +} + +/* built-in 'help' handler */ +static int builtin_help(struct child_prog *dummy) +{ + struct built_in_command *x; + + printf("\nBuilt-in commands:\n"); + printf("-------------------\n"); + for (x = bltins; x->cmd; x++) { + if (x->descr==NULL) + continue; + printf("%s\t%s\n", x->cmd, x->descr); + } + printf("\n\n"); + return EXIT_SUCCESS; +} + +/* built-in 'jobs' handler */ +static int builtin_jobs(struct child_prog *child) +{ + struct pipe *job; + char *status_string; + + for (job = job_list; job; job = job->next) { + if (job->running_progs == job->stopped_progs) + status_string = "Stopped"; + else + status_string = "Running"; + + printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text); + } + return EXIT_SUCCESS; +} + + +/* built-in 'pwd' handler */ +static int builtin_pwd(struct child_prog *dummy) +{ + puts(set_cwd()); + return EXIT_SUCCESS; +} + +/* built-in 'read VAR' handler */ +static int builtin_read(struct child_prog *child) +{ + int res; + + if (child->argv[1]) { + char string[BUFSIZ]; + char *var = 0; + + string[0] = 0; /* In case stdin has only EOF */ + /* read string */ + fgets(string, sizeof(string), stdin); + chomp(string); + var = malloc(strlen(child->argv[1])+strlen(string)+2); + if(var) { + sprintf(var, "%s=%s", child->argv[1], string); + res = set_local_var(var, 0); + } else + res = -1; + if (res) + fprintf(stderr, "read: %m\n"); + free(var); /* So not move up to avoid breaking errno */ + return res; + } else { + do res=getchar(); while(res!='\n' && res!=EOF); + return 0; + } +} + +/* built-in 'set VAR=value' handler */ +static int builtin_set(struct child_prog *child) +{ + char *temp = child->argv[1]; + struct variables *e; + + if (temp == NULL) + for(e = top_vars; e; e=e->next) + printf("%s=%s\n", e->name, e->value); + else + set_local_var(temp, 0); + + return EXIT_SUCCESS; +} + + +/* Built-in 'shift' handler */ +static int builtin_shift(struct child_prog *child) +{ + int n=1; + if (child->argv[1]) { + n=atoi(child->argv[1]); + } + if (n>=0 && nargv[1] == NULL) + return EXIT_FAILURE; + + /* XXX search through $PATH is missing */ + input = fopen(child->argv[1], "r"); + if (!input) { + error_msg("Couldn't open file '%s'", child->argv[1]); + return EXIT_FAILURE; + } + + /* Now run the file */ + /* XXX argv and argc are broken; need to save old global_argv + * (pointer only is OK!) on this stack frame, + * set global_argv=child->argv+1, recurse, and restore. */ + mark_open(fileno(input)); + status = parse_file_outer(input); + mark_closed(fileno(input)); + fclose(input); + return (status); +} + +static int builtin_umask(struct child_prog *child) +{ + mode_t new_umask; + const char *arg = child->argv[1]; + char *end; + if (arg) { + new_umask=strtoul(arg, &end, 8); + if (*end!='\0' || end == arg) { + return EXIT_FAILURE; + } + } else { + printf("%.3o\n", (unsigned int) (new_umask=umask(0))); + } + umask(new_umask); + return EXIT_SUCCESS; +} + +/* built-in 'unset VAR' handler */ +static int builtin_unset(struct child_prog *child) +{ + /* bash returned already true */ + unset_local_var(child->argv[1]); + return EXIT_SUCCESS; +} + +static int builtin_not_written(struct child_prog *child) +{ + printf("builtin_%s not written\n",child->argv[0]); + return EXIT_FAILURE; +} + +static int b_check_space(o_string *o, int len) +{ + /* It would be easy to drop a more restrictive policy + * in here, such as setting a maximum string length */ + if (o->length + len > o->maxlen) { + char *old_data = o->data; + /* assert (data == NULL || o->maxlen != 0); */ + o->maxlen += max(2*len, B_CHUNK); + o->data = realloc(o->data, 1 + o->maxlen); + if (o->data == NULL) { + free(old_data); + } + } + return o->data == NULL; +} + +static int b_addchr(o_string *o, int ch) +{ + debug_printf("b_addchr: %c %d %p\n", ch, o->length, o); + if (b_check_space(o, 1)) return B_NOSPAC; + o->data[o->length] = ch; + o->length++; + o->data[o->length] = '\0'; + return 0; +} + +static void b_reset(o_string *o) +{ + o->length = 0; + o->nonnull = 0; + if (o->data != NULL) *o->data = '\0'; +} + +static void b_free(o_string *o) +{ + b_reset(o); + if (o->data != NULL) free(o->data); + o->data = NULL; + o->maxlen = 0; +} + +/* My analysis of quoting semantics tells me that state information + * is associated with a destination, not a source. + */ +static int b_addqchr(o_string *o, int ch, int quote) +{ + if (quote && strchr("*?[\\",ch)) { + int rc; + rc = b_addchr(o, '\\'); + if (rc) return rc; + } + return b_addchr(o, ch); +} + +/* belongs in utility.c */ +char *simple_itoa(unsigned int i) +{ + /* 21 digits plus null terminator, good for 64-bit or smaller ints */ + static char local[22]; + char *p = &local[21]; + *p-- = '\0'; + do { + *p-- = '0' + i % 10; + i /= 10; + } while (i > 0); + return p + 1; +} + +static int b_adduint(o_string *o, unsigned int i) +{ + int r; + char *p = simple_itoa(i); + /* no escape checking necessary */ + do r=b_addchr(o, *p++); while (r==0 && *p); + return r; +} + +static int static_get(struct in_str *i) +{ + int ch=*i->p++; + if (ch=='\0') return EOF; + return ch; +} + +static int static_peek(struct in_str *i) +{ + return *i->p; +} + +static inline void cmdedit_set_initial_prompt(void) +{ +#ifndef BB_FEATURE_SH_FANCY_PROMPT + PS1 = NULL; +#else + PS1 = getenv("PS1"); + if(PS1==0) + PS1 = "\\w \\$ "; +#endif +} + +static inline void setup_prompt_string(int promptmode, char **prompt_str) +{ + debug_printf("setup_prompt_string %d ",promptmode); +#ifndef BB_FEATURE_SH_FANCY_PROMPT + /* Set up the prompt */ + if (promptmode == 1) { + if (PS1) + free(PS1); + PS1=xmalloc(strlen(cwd)+4); + sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); + *prompt_str = PS1; + } else { + *prompt_str = PS2; + } +#else + *prompt_str = (promptmode==1)? PS1 : PS2; +#endif + debug_printf("result %s\n",*prompt_str); +} + +static void get_user_input(struct in_str *i) +{ + char *prompt_str; + static char the_command[BUFSIZ]; + + setup_prompt_string(i->promptmode, &prompt_str); +#ifdef BB_FEATURE_COMMAND_EDITING + /* + ** enable command line editing only while a command line + ** is actually being read; otherwise, we'll end up bequeathing + ** atexit() handlers and other unwanted stuff to our + ** child processes (rob@sysgo.de) + */ + cmdedit_read_input(prompt_str, the_command); +#else + fputs(prompt_str, stdout); + fflush(stdout); + the_command[0]=fgetc(i->file); + the_command[1]='\0'; +#endif + fflush(stdout); + i->p = the_command; +} + +/* This is the magic location that prints prompts + * and gets data back from the user */ +static int file_get(struct in_str *i) +{ + int ch; + + ch = 0; + /* If there is data waiting, eat it up */ + if (i->p && *i->p) { + ch=*i->p++; + } else { + /* need to double check i->file because we might be doing something + * more complicated by now, like sourcing or substituting. */ + if (i->__promptme && interactive && i->file == stdin) { + while(! i->p || (interactive && strlen(i->p)==0) ) { + get_user_input(i); + } + i->promptmode=2; + i->__promptme = 0; + if (i->p && *i->p) { + ch=*i->p++; + } + } else { + ch = fgetc(i->file); + } + + debug_printf("b_getch: got a %d\n", ch); + } + if (ch == '\n') i->__promptme=1; + return ch; +} + +/* All the callers guarantee this routine will never be + * used right after a newline, so prompting is not needed. + */ +static int file_peek(struct in_str *i) +{ + if (i->p && *i->p) { + return *i->p; + } else { + i->peek_buf[0] = fgetc(i->file); + i->peek_buf[1] = '\0'; + i->p = i->peek_buf; + debug_printf("b_peek: got a %d\n", *i->p); + return *i->p; + } +} + +static void setup_file_in_str(struct in_str *i, FILE *f) +{ + i->peek = file_peek; + i->get = file_get; + i->__promptme=1; + i->promptmode=1; + i->file = f; + i->p = NULL; +} + +static void setup_string_in_str(struct in_str *i, const char *s) +{ + i->peek = static_peek; + i->get = static_get; + i->__promptme=1; + i->promptmode=1; + i->p = s; +} + +static void mark_open(int fd) +{ + struct close_me *new = xmalloc(sizeof(struct close_me)); + new->fd = fd; + new->next = close_me_head; + close_me_head = new; +} + +static void mark_closed(int fd) +{ + struct close_me *tmp; + if (close_me_head == NULL || close_me_head->fd != fd) + error_msg_and_die("corrupt close_me"); + tmp = close_me_head; + close_me_head = close_me_head->next; + free(tmp); +} + +static void close_all() +{ + struct close_me *c; + for (c=close_me_head; c; c=c->next) { + close(c->fd); + } + close_me_head = NULL; +} + +/* squirrel != NULL means we squirrel away copies of stdin, stdout, + * and stderr if they are redirected. */ +static int setup_redirects(struct child_prog *prog, int squirrel[]) +{ + int openfd, mode; + struct redir_struct *redir; + + for (redir=prog->redirects; redir; redir=redir->next) { + if (redir->dup == -1 && redir->word.gl_pathv == NULL) { + /* something went wrong in the parse. Pretend it didn't happen */ + continue; + } + if (redir->dup == -1) { + mode=redir_table[redir->type].mode; + openfd = open(redir->word.gl_pathv[0], mode, 0666); + if (openfd < 0) { + /* this could get lost if stderr has been redirected, but + bash and ash both lose it as well (though zsh doesn't!) */ + perror_msg("error opening %s", redir->word.gl_pathv[0]); + return 1; + } + } else { + openfd = redir->dup; + } + + if (openfd != redir->fd) { + if (squirrel && redir->fd < 3) { + squirrel[redir->fd] = dup(redir->fd); + } + if (openfd == -3) { + close(openfd); + } else { + dup2(openfd, redir->fd); + if (redir->dup == -1) + close (openfd); + } + } + } + return 0; +} + +static void restore_redirects(int squirrel[]) +{ + int i, fd; + for (i=0; i<3; i++) { + fd = squirrel[i]; + if (fd != -1) { + /* No error checking. I sure wouldn't know what + * to do with an error if I found one! */ + dup2(fd, i); + close(fd); + } + } +} + +/* never returns */ +/* XXX no exit() here. If you don't exec, use _exit instead. + * The at_exit handlers apparently confuse the calling process, + * in particular stdin handling. Not sure why? */ +static void pseudo_exec(struct child_prog *child) +{ + int i, rcode; + char *p; + struct built_in_command *x; + if (child->argv) { + for (i=0; is_assignment(child->argv[i]); i++) { + debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]); + p = insert_var_value(child->argv[i]); + putenv(strdup(p)); + if (p != child->argv[i]) free(p); + } + child->argv+=i; /* XXX this hack isn't so horrible, since we are about + to exit, and therefore don't need to keep data + structures consistent for free() use. */ + /* If a variable is assigned in a forest, and nobody listens, + * was it ever really set? + */ + if (child->argv[0] == NULL) { + _exit(EXIT_SUCCESS); + } + + /* + * Check if the command matches any of the builtins. + * Depending on context, this might be redundant. But it's + * easier to waste a few CPU cycles than it is to figure out + * if this is one of those cases. + */ + for (x = bltins; x->cmd; x++) { + if (strcmp(child->argv[0], x->cmd) == 0 ) { + debug_printf("builtin exec %s\n", child->argv[0]); + rcode = x->function(child); + fflush(stdout); + _exit(rcode); + } + } + + /* Check if the command matches any busybox internal commands + * ("applets") here. + * FIXME: This feature is not 100% safe, since + * BusyBox is not fully reentrant, so we have no guarantee the things + * from the .bss are still zeroed, or that things from .data are still + * at their defaults. We could exec ourself from /proc/self/exe, but I + * really dislike relying on /proc for things. We could exec ourself + * from global_argv[0], but if we are in a chroot, we may not be able + * to find ourself... */ +#ifdef BB_FEATURE_SH_STANDALONE_SHELL + { + int argc_l; + char** argv_l=child->argv; + char *name = child->argv[0]; + +#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN + /* Following discussions from November 2000 on the busybox mailing + * list, the default configuration, (without + * get_last_path_component()) lets the user force use of an + * external command by specifying the full (with slashes) filename. + * If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then applets + * _aways_ override external commands, so if you want to run + * /bin/cat, it will use BusyBox cat even if /bin/cat exists on the + * filesystem and is _not_ busybox. Some systems may want this, + * most do not. */ + name = get_last_path_component(name); +#endif + /* Count argc for use in a second... */ + for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++); + optind = 1; + debug_printf("running applet %s\n", name); + run_applet_by_name(name, argc_l, child->argv); + } +#endif + debug_printf("exec of %s\n",child->argv[0]); + execvp(child->argv[0],child->argv); + perror_msg("couldn't exec: %s",child->argv[0]); + _exit(1); + } else if (child->group) { + debug_printf("runtime nesting to group\n"); + interactive=0; /* crucial!!!! */ + rcode = run_list_real(child->group); + /* OK to leak memory by not calling free_pipe_list, + * since this process is about to exit */ + _exit(rcode); + } else { + /* Can happen. See what bash does with ">foo" by itself. */ + debug_printf("trying to pseudo_exec null command\n"); + _exit(EXIT_SUCCESS); + } +} + +static void insert_bg_job(struct pipe *pi) +{ + struct pipe *thejob; + + /* Linear search for the ID of the job to use */ + pi->jobid = 1; + for (thejob = job_list; thejob; thejob = thejob->next) + if (thejob->jobid >= pi->jobid) + pi->jobid = thejob->jobid + 1; + + /* add thejob to the list of running jobs */ + if (!job_list) { + thejob = job_list = xmalloc(sizeof(*thejob)); + } else { + for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */; + thejob->next = xmalloc(sizeof(*thejob)); + thejob = thejob->next; + } + + /* physically copy the struct job */ + memcpy(thejob, pi, sizeof(struct pipe)); + thejob->next = NULL; + thejob->running_progs = thejob->num_progs; + thejob->stopped_progs = 0; + thejob->text = xmalloc(BUFSIZ); /* cmdedit buffer size */ + + //if (pi->progs[0] && pi->progs[0].argv && pi->progs[0].argv[0]) + { + char *bar=thejob->text; + char **foo=pi->progs[0].argv; + while(foo && *foo) { + bar += sprintf(bar, "%s ", *foo++); + } + } + + /* we don't wait for background thejobs to return -- append it + to the list of backgrounded thejobs and leave it alone */ + printf("[%d] %d\n", thejob->jobid, thejob->progs[0].pid); + last_bg_pid = thejob->progs[0].pid; + last_jobid = thejob->jobid; +} + +/* remove a backgrounded job */ +static void remove_bg_job(struct pipe *pi) +{ + struct pipe *prev_pipe; + + if (pi == job_list) { + job_list = pi->next; + } else { + prev_pipe = job_list; + while (prev_pipe->next != pi) + prev_pipe = prev_pipe->next; + prev_pipe->next = pi->next; + } + if (job_list) + last_jobid = job_list->jobid; + else + last_jobid = 0; + + pi->stopped_progs = 0; + free_pipe(pi, 0); + free(pi); +} + +/* Checks to see if any processes have exited -- if they + have, figure out why and see if a job has completed */ +static int checkjobs(struct pipe* fg_pipe) +{ + int attributes; + int status; + int prognum = 0; + struct pipe *pi; + pid_t childpid; + + attributes = WUNTRACED; + if (fg_pipe==NULL) { + attributes |= WNOHANG; + } + + while ((childpid = waitpid(-1, &status, attributes)) > 0) { + if (fg_pipe) { + int i, rcode = 0; + for (i=0; i < fg_pipe->num_progs; i++) { + if (fg_pipe->progs[i].pid == childpid) { + if (i==fg_pipe->num_progs-1) + rcode=WEXITSTATUS(status); + (fg_pipe->num_progs)--; + return(rcode); + } + } + } + + for (pi = job_list; pi; pi = pi->next) { + prognum = 0; + while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) { + prognum++; + } + if (prognum < pi->num_progs) + break; + } + + if(pi==NULL) { + debug_printf("checkjobs: pid %d was not in our list!\n", childpid); + continue; + } + + if (WIFEXITED(status) || WIFSIGNALED(status)) { + /* child exited */ + pi->running_progs--; + pi->progs[prognum].pid = 0; + + if (!pi->running_progs) { + printf(JOB_STATUS_FORMAT, pi->jobid, "Done", pi->text); + remove_bg_job(pi); + } + } else { + /* child stopped */ + pi->stopped_progs++; + pi->progs[prognum].is_stopped = 1; + +#if 0 + /* Printing this stuff is a pain, since it tends to + * overwrite the prompt an inconveinient moments. So + * don't do that. */ + if (pi->stopped_progs == pi->num_progs) { + printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text); + } +#endif + } + } + + if (childpid == -1 && errno != ECHILD) + perror_msg("waitpid"); + + /* move the shell to the foreground */ + //if (interactive && tcsetpgrp(shell_terminal, getpgid(0))) + // perror_msg("tcsetpgrp-2"); + return -1; +} + +/* Figure out our controlling tty, checking in order stderr, + * stdin, and stdout. If check_pgrp is set, also check that + * we belong to the foreground process group associated with + * that tty. The value of shell_terminal is needed in order to call + * tcsetpgrp(shell_terminal, ...); */ +void controlling_tty(int check_pgrp) +{ + pid_t curpgrp; + + if ((curpgrp = tcgetpgrp(shell_terminal = 2)) < 0 + && (curpgrp = tcgetpgrp(shell_terminal = 0)) < 0 + && (curpgrp = tcgetpgrp(shell_terminal = 1)) < 0) + goto shell_terminal_error; + + if (check_pgrp && curpgrp != getpgid(0)) + goto shell_terminal_error; + + return; + +shell_terminal_error: + shell_terminal = -1; + return; +} + +/* run_pipe_real() starts all the jobs, but doesn't wait for anything + * to finish. See checkjobs(). + * + * return code is normally -1, when the caller has to wait for children + * to finish to determine the exit status of the pipe. If the pipe + * is a simple builtin command, however, the action is done by the + * time run_pipe_real returns, and the exit code is provided as the + * return value. + * + * The input of the pipe is always stdin, the output is always + * stdout. The outpipe[] mechanism in BusyBox-0.48 lash is bogus, + * because it tries to avoid running the command substitution in + * subshell, when that is in fact necessary. The subshell process + * now has its stdout directed to the input of the appropriate pipe, + * so this routine is noticeably simpler. + */ +static int run_pipe_real(struct pipe *pi) +{ + int i; + int nextin, nextout; + int pipefds[2]; /* pipefds[0] is for reading */ + struct child_prog *child; + struct built_in_command *x; + char *p; +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &i; + (void) &nextin; + (void) &nextout; + (void) &child; +#endif + + nextin = 0; + pi->pgrp = -1; + + /* Check if this is a simple builtin (not part of a pipe). + * Builtins within pipes have to fork anyway, and are handled in + * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. + */ + if (pi->num_progs == 1) child = & (pi->progs[0]); + if (pi->num_progs == 1 && child->group && child->subshell == 0) { + int squirrel[] = {-1, -1, -1}; + int rcode; + debug_printf("non-subshell grouping\n"); + setup_redirects(child, squirrel); + /* XXX could we merge code with following builtin case, + * by creating a pseudo builtin that calls run_list_real? */ + rcode = run_list_real(child->group); + restore_redirects(squirrel); + return rcode; + } else if (pi->num_progs == 1 && pi->progs[0].argv != NULL) { + for (i=0; is_assignment(child->argv[i]); i++) { /* nothing */ } + if (i!=0 && child->argv[i]==NULL) { + /* assignments, but no command: set the local environment */ + for (i=0; child->argv[i]!=NULL; i++) { + + /* Ok, this case is tricky. We have to decide if this is a + * local variable, or an already exported variable. If it is + * already exported, we have to export the new value. If it is + * not exported, we need only set this as a local variable. + * This junk is all to decide whether or not to export this + * variable. */ + int export_me=0; + char *name, *value; + name = xstrdup(child->argv[i]); + debug_printf("Local environment set: %s\n", name); + value = strchr(name, '='); + if (value) + *value=0; + if ( get_local_var(name)) { + export_me=1; + } + free(name); + p = insert_var_value(child->argv[i]); + set_local_var(p, export_me); + if (p != child->argv[i]) free(p); + } + return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ + } + for (i = 0; is_assignment(child->argv[i]); i++) { + p = insert_var_value(child->argv[i]); + putenv(strdup(p)); + if (p != child->argv[i]) { + child->sp--; + free(p); + } + } + if (child->sp) { + char * str = NULL; + + str = make_string((child->argv + i)); + parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING); + free(str); + return last_return_code; + } + for (x = bltins; x->cmd; x++) { + if (strcmp(child->argv[i], x->cmd) == 0 ) { + int squirrel[] = {-1, -1, -1}; + int rcode; + if (x->function == builtin_exec && child->argv[i+1]==NULL) { + debug_printf("magic exec\n"); + setup_redirects(child,NULL); + return EXIT_SUCCESS; + } + debug_printf("builtin inline %s\n", child->argv[0]); + /* XXX setup_redirects acts on file descriptors, not FILEs. + * This is perfect for work that comes after exec(). + * Is it really safe for inline use? Experimentally, + * things seem to work with glibc. */ + setup_redirects(child, squirrel); + child->argv+=i; /* XXX horrible hack */ + rcode = x->function(child); + child->argv-=i; /* XXX restore hack so free() can work right */ + restore_redirects(squirrel); + return rcode; + } + } + } + + for (i = 0; i < pi->num_progs; i++) { + child = & (pi->progs[i]); + + /* pipes are inserted between pairs of commands */ + if ((i + 1) < pi->num_progs) { + if (pipe(pipefds)<0) perror_msg_and_die("pipe"); + nextout = pipefds[1]; + } else { + nextout=1; + pipefds[0] = -1; + } + + /* XXX test for failed fork()? */ + if (!(child->pid = fork())) + { + /* Set the handling for job control signals back to the default. */ + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGTSTP, SIG_DFL); + signal(SIGTTIN, SIG_DFL); + signal(SIGTTOU, SIG_DFL); + signal(SIGCHLD, SIG_DFL); + + close_all(); + + if (nextin != 0) { + dup2(nextin, 0); + close(nextin); + } + if (nextout != 1) { + dup2(nextout, 1); + close(nextout); + } + if (pipefds[0]!=-1) { + close(pipefds[0]); /* opposite end of our output pipe */ + } + + /* Like bash, explicit redirects override pipes, + * and the pipe fd is available for dup'ing. */ + setup_redirects(child,NULL); + + if (interactive && pi->followup!=PIPE_BG) { + /* If we (the child) win the race, put ourselves in the process + * group whose leader is the first process in this pipe. */ + if (pi->pgrp < 0) { + pi->pgrp = getpid(); + } + if (setpgid(0, pi->pgrp) == 0) { + tcsetpgrp(2, pi->pgrp); + } + } + + pseudo_exec(child); + } + + + /* put our child in the process group whose leader is the + first process in this pipe */ + if (pi->pgrp < 0) { + pi->pgrp = child->pid; + } + /* Don't check for errors. The child may be dead already, + * in which case setpgid returns error code EACCES. */ + setpgid(child->pid, pi->pgrp); + + if (nextin != 0) + close(nextin); + if (nextout != 1) + close(nextout); + + /* If there isn't another process, nextin is garbage + but it doesn't matter */ + nextin = pipefds[0]; + } + return -1; +} + +static int run_list_real(struct pipe *pi) +{ + char *save_name = NULL; + char **list = NULL; + char **save_list = NULL; + struct pipe *rpipe; + int flag_rep = 0; + int save_num_progs; + int rcode=0, flag_skip=1; + int flag_restore = 0; + int if_code=0, next_if_code=0; /* need double-buffer to handle elif */ + reserved_style rmode, skip_more_in_this_rmode=RES_XXXX; + /* check syntax for "for" */ + for (rpipe = pi; rpipe; rpipe = rpipe->next) { + if ((rpipe->r_mode == RES_IN || + rpipe->r_mode == RES_FOR) && + (rpipe->next == NULL)) { + syntax(); + return 1; + } + if ((rpipe->r_mode == RES_IN && + (rpipe->next->r_mode == RES_IN && + rpipe->next->progs->argv != NULL))|| + (rpipe->r_mode == RES_FOR && + rpipe->next->r_mode != RES_IN)) { + syntax(); + return 1; + } + } + for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) { + if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL || + pi->r_mode == RES_FOR) { + flag_restore = 0; + if (!rpipe) { + flag_rep = 0; + rpipe = pi; + } + } + rmode = pi->r_mode; + debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode); + if (rmode == skip_more_in_this_rmode && flag_skip) { + if (pi->followup == PIPE_SEQ) flag_skip=0; + continue; + } + flag_skip = 1; + skip_more_in_this_rmode = RES_XXXX; + if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code; + if (rmode == RES_THEN && if_code) continue; + if (rmode == RES_ELSE && !if_code) continue; + if (rmode == RES_ELIF && !if_code) continue; + if (rmode == RES_FOR && pi->num_progs) { + if (!list) { + /* if no variable values after "in" we skip "for" */ + if (!pi->next->progs->argv) continue; + /* create list of variable values */ + list = make_list_in(pi->next->progs->argv, + pi->progs->argv[0]); + save_list = list; + save_name = pi->progs->argv[0]; + pi->progs->argv[0] = NULL; + flag_rep = 1; + } + if (!(*list)) { + free(pi->progs->argv[0]); + free(save_list); + list = NULL; + flag_rep = 0; + pi->progs->argv[0] = save_name; + pi->progs->glob_result.gl_pathv[0] = + pi->progs->argv[0]; + continue; + } else { + /* insert new value from list for variable */ + if (pi->progs->argv[0]) + free(pi->progs->argv[0]); + pi->progs->argv[0] = *list++; + pi->progs->glob_result.gl_pathv[0] = + pi->progs->argv[0]; + } + } + if (rmode == RES_IN) continue; + if (rmode == RES_DO) { + if (!flag_rep) continue; + } + if ((rmode == RES_DONE)) { + if (flag_rep) { + flag_restore = 1; + } else { + rpipe = NULL; + } + } + if (pi->num_progs == 0) continue; + save_num_progs = pi->num_progs; /* save number of programs */ + rcode = run_pipe_real(pi); + debug_printf("run_pipe_real returned %d\n",rcode); + if (rcode!=-1) { + /* We only ran a builtin: rcode was set by the return value + * of run_pipe_real(), and we don't need to wait for anything. */ + } else if (pi->followup==PIPE_BG) { + /* XXX check bash's behavior with nontrivial pipes */ + /* XXX compute jobid */ + /* XXX what does bash do with attempts to background builtins? */ + insert_bg_job(pi); + rcode = EXIT_SUCCESS; + } else { + if (interactive) { + /* move the new process group into the foreground */ + if (tcsetpgrp(shell_terminal, pi->pgrp) && errno != ENOTTY) + perror_msg("tcsetpgrp-3"); + rcode = checkjobs(pi); + /* move the shell to the foreground */ + if (tcsetpgrp(shell_terminal, getpgid(0)) && errno != ENOTTY) + perror_msg("tcsetpgrp-4"); + } else { + rcode = checkjobs(pi); + } + debug_printf("checkjobs returned %d\n",rcode); + } + last_return_code=rcode; + pi->num_progs = save_num_progs; /* restore number of programs */ + if ( rmode == RES_IF || rmode == RES_ELIF ) + next_if_code=rcode; /* can be overwritten a number of times */ + if (rmode == RES_WHILE) + flag_rep = !last_return_code; + if (rmode == RES_UNTIL) + flag_rep = last_return_code; + if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) || + (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) ) + skip_more_in_this_rmode=rmode; + checkjobs(NULL); + } + return rcode; +} + +/* broken, of course, but OK for testing */ +static char *indenter(int i) +{ + static char blanks[]=" "; + return &blanks[sizeof(blanks)-i-1]; +} + +/* return code is the exit status of the pipe */ +static int free_pipe(struct pipe *pi, int indent) +{ + char **p; + struct child_prog *child; + struct redir_struct *r, *rnext; + int a, i, ret_code=0; + char *ind = indenter(indent); + + if (pi->stopped_progs > 0) + return ret_code; + final_printf("%s run pipe: (pid %d)\n",ind,getpid()); + for (i=0; inum_progs; i++) { + child = &pi->progs[i]; + final_printf("%s command %d:\n",ind,i); + if (child->argv) { + for (a=0,p=child->argv; *p; a++,p++) { + final_printf("%s argv[%d] = %s\n",ind,a,*p); + } + globfree(&child->glob_result); + child->argv=NULL; + } else if (child->group) { + final_printf("%s begin group (subshell:%d)\n",ind, child->subshell); + ret_code = free_pipe_list(child->group,indent+3); + final_printf("%s end group\n",ind); + } else { + final_printf("%s (nil)\n",ind); + } + for (r=child->redirects; r; r=rnext) { + final_printf("%s redirect %d%s", ind, r->fd, redir_table[r->type].descrip); + if (r->dup == -1) { + /* guard against the case >$FOO, where foo is unset or blank */ + if (r->word.gl_pathv) { + final_printf(" %s\n", *r->word.gl_pathv); + globfree(&r->word); + } + } else { + final_printf("&%d\n", r->dup); + } + rnext=r->next; + free(r); + } + child->redirects=NULL; + } + free(pi->progs); /* children are an array, they get freed all at once */ + pi->progs=NULL; + return ret_code; +} + +static int free_pipe_list(struct pipe *head, int indent) +{ + int rcode=0; /* if list has no members */ + struct pipe *pi, *next; + char *ind = indenter(indent); + for (pi=head; pi; pi=next) { + final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode); + rcode = free_pipe(pi, indent); + final_printf("%s pipe followup code %d\n", ind, pi->followup); + next=pi->next; + pi->next=NULL; + free(pi); + } + return rcode; +} + +/* Select which version we will use */ +static int run_list(struct pipe *pi) +{ + int rcode=0; + if (fake_mode==0) { + rcode = run_list_real(pi); + } + /* free_pipe_list has the side effect of clearing memory + * In the long run that function can be merged with run_list_real, + * but doing that now would hobble the debugging effort. */ + free_pipe_list(pi,0); + return rcode; +} + +/* The API for glob is arguably broken. This routine pushes a non-matching + * string into the output structure, removing non-backslashed backslashes. + * If someone can prove me wrong, by performing this function within the + * original glob(3) api, feel free to rewrite this routine into oblivion. + * Return code (0 vs. GLOB_NOSPACE) matches glob(3). + * XXX broken if the last character is '\\', check that before calling. + */ +static int globhack(const char *src, int flags, glob_t *pglob) +{ + int cnt=0, pathc; + const char *s; + char *dest; + for (cnt=1, s=src; s && *s; s++) { + if (*s == '\\') s++; + cnt++; + } + dest = malloc(cnt); + if (!dest) return GLOB_NOSPACE; + if (!(flags & GLOB_APPEND)) { + pglob->gl_pathv=NULL; + pglob->gl_pathc=0; + pglob->gl_offs=0; + pglob->gl_offs=0; + } + pathc = ++pglob->gl_pathc; + pglob->gl_pathv = realloc(pglob->gl_pathv, (pathc+1)*sizeof(*pglob->gl_pathv)); + if (pglob->gl_pathv == NULL) return GLOB_NOSPACE; + pglob->gl_pathv[pathc-1]=dest; + pglob->gl_pathv[pathc]=NULL; + for (s=src; s && *s; s++, dest++) { + if (*s == '\\') s++; + *dest = *s; + } + *dest='\0'; + return 0; +} + +/* XXX broken if the last character is '\\', check that before calling */ +static int glob_needed(const char *s) +{ + for (; *s; s++) { + if (*s == '\\') s++; + if (strchr("*[?",*s)) return 1; + } + return 0; +} + +#if 0 +static void globprint(glob_t *pglob) +{ + int i; + debug_printf("glob_t at %p:\n", pglob); + debug_printf(" gl_pathc=%d gl_pathv=%p gl_offs=%d gl_flags=%d\n", + pglob->gl_pathc, pglob->gl_pathv, pglob->gl_offs, pglob->gl_flags); + for (i=0; igl_pathc; i++) + debug_printf("pglob->gl_pathv[%d] = %p = %s\n", i, + pglob->gl_pathv[i], pglob->gl_pathv[i]); +} +#endif + +static int xglob(o_string *dest, int flags, glob_t *pglob) +{ + int gr; + + /* short-circuit for null word */ + /* we can code this better when the debug_printf's are gone */ + if (dest->length == 0) { + if (dest->nonnull) { + /* bash man page calls this an "explicit" null */ + gr = globhack(dest->data, flags, pglob); + debug_printf("globhack returned %d\n",gr); + } else { + return 0; + } + } else if (glob_needed(dest->data)) { + gr = glob(dest->data, flags, NULL, pglob); + debug_printf("glob returned %d\n",gr); + if (gr == GLOB_NOMATCH) { + /* quote removal, or more accurately, backslash removal */ + gr = globhack(dest->data, flags, pglob); + debug_printf("globhack returned %d\n",gr); + } + } else { + gr = globhack(dest->data, flags, pglob); + debug_printf("globhack returned %d\n",gr); + } + if (gr == GLOB_NOSPACE) + error_msg_and_die("out of memory during glob"); + if (gr != 0) { /* GLOB_ABORTED ? */ + error_msg("glob(3) error %d",gr); + } + /* globprint(glob_target); */ + return gr; +} + +/* This is used to get/check local shell variables */ +static char *get_local_var(const char *s) +{ + struct variables *cur; + + if (!s) + return NULL; + for (cur = top_vars; cur; cur=cur->next) + if(strcmp(cur->name, s)==0) + return cur->value; + return NULL; +} + +/* This is used to set local shell variables + flg_export==0 if only local (not exporting) variable + flg_export==1 if "new" exporting environ + flg_export>1 if current startup environ (not call putenv()) */ +static int set_local_var(const char *s, int flg_export) +{ + char *name, *value; + int result=0; + struct variables *cur; + + name=strdup(s); + + /* Assume when we enter this function that we are already in + * NAME=VALUE format. So the first order of business is to + * split 's' on the '=' into 'name' and 'value' */ + value = strchr(name, '='); + if (value==0 && ++value==0) { + free(name); + return -1; + } + *value++ = 0; + + for(cur = top_vars; cur; cur = cur->next) { + if(strcmp(cur->name, name)==0) + break; + } + + if(cur) { + if(strcmp(cur->value, value)==0) { + if(flg_export>0 && cur->flg_export==0) + cur->flg_export=flg_export; + else + result++; + } else { + if(cur->flg_read_only) { + error_msg("%s: readonly variable", name); + result = -1; + } else { + if(flg_export>0 || cur->flg_export>1) + cur->flg_export=1; + free(cur->value); + + cur->value = strdup(value); + } + } + } else { + cur = malloc(sizeof(struct variables)); + if(!cur) { + result = -1; + } else { + cur->name = strdup(name); + if(cur->name == 0) { + free(cur); + result = -1; + } else { + struct variables *bottom = top_vars; + cur->value = strdup(value); + cur->next = 0; + cur->flg_export = flg_export; + cur->flg_read_only = 0; + while(bottom->next) bottom=bottom->next; + bottom->next = cur; + } + } + } + + if(result==0 && cur->flg_export==1) { + *(value-1) = '='; + result = putenv(name); + } else { + free(name); + if(result>0) /* equivalent to previous set */ + result = 0; + } + return result; +} + +static void unset_local_var(const char *name) +{ + struct variables *cur; + + if (name) { + for (cur = top_vars; cur; cur=cur->next) { + if(strcmp(cur->name, name)==0) + break; + } + if(cur!=0) { + struct variables *next = top_vars; + if(cur->flg_read_only) { + error_msg("%s: readonly variable", name); + return; + } else { + if(cur->flg_export) + unsetenv(cur->name); + free(cur->name); + free(cur->value); + while (next->next != cur) + next = next->next; + next->next = cur->next; + } + free(cur); + } + } +} + +static int is_assignment(const char *s) +{ + if (s==NULL || !isalpha(*s)) return 0; + ++s; + while(isalnum(*s) || *s=='_') ++s; + return *s=='='; +} + +/* the src parameter allows us to peek forward to a possible &n syntax + * for file descriptor duplication, e.g., "2>&1". + * Return code is 0 normally, 1 if a syntax error is detected in src. + * Resource errors (in xmalloc) cause the process to exit */ +static int setup_redirect(struct p_context *ctx, int fd, redir_type style, + struct in_str *input) +{ + struct child_prog *child=ctx->child; + struct redir_struct *redir = child->redirects; + struct redir_struct *last_redir=NULL; + + /* Create a new redir_struct and drop it onto the end of the linked list */ + while(redir) { + last_redir=redir; + redir=redir->next; + } + redir = xmalloc(sizeof(struct redir_struct)); + redir->next=NULL; + redir->word.gl_pathv=NULL; + if (last_redir) { + last_redir->next=redir; + } else { + child->redirects=redir; + } + + redir->type=style; + redir->fd= (fd==-1) ? redir_table[style].default_fd : fd ; + + debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip); + + /* Check for a '2>&1' type redirect */ + redir->dup = redirect_dup_num(input); + if (redir->dup == -2) return 1; /* syntax error */ + if (redir->dup != -1) { + /* Erik had a check here that the file descriptor in question + * is legit; I postpone that to "run time" + * A "-" representation of "close me" shows up as a -3 here */ + debug_printf("Duplicating redirect '%d>&%d'\n", redir->fd, redir->dup); + } else { + /* We do _not_ try to open the file that src points to, + * since we need to return and let src be expanded first. + * Set ctx->pending_redirect, so we know what to do at the + * end of the next parsed word. + */ + ctx->pending_redirect = redir; + } + return 0; +} + +struct pipe *new_pipe(void) { + struct pipe *pi; + pi = xmalloc(sizeof(struct pipe)); + pi->num_progs = 0; + pi->progs = NULL; + pi->next = NULL; + pi->followup = 0; /* invalid */ + return pi; +} + +static void initialize_context(struct p_context *ctx) +{ + ctx->pipe=NULL; + ctx->pending_redirect=NULL; + ctx->child=NULL; + ctx->list_head=new_pipe(); + ctx->pipe=ctx->list_head; + ctx->w=RES_NONE; + ctx->stack=NULL; + ctx->old_flag=0; + done_command(ctx); /* creates the memory for working child */ +} + +/* normal return is 0 + * if a reserved word is found, and processed, return 1 + * should handle if, then, elif, else, fi, for, while, until, do, done. + * case, function, and select are obnoxious, save those for later. + */ +int reserved_word(o_string *dest, struct p_context *ctx) +{ + struct reserved_combo { + char *literal; + int code; + long flag; + }; + /* Mostly a list of accepted follow-up reserved words. + * FLAG_END means we are done with the sequence, and are ready + * to turn the compound list into a command. + * FLAG_START means the word must start a new compound list. + */ + static struct reserved_combo reserved_list[] = { + { "if", RES_IF, FLAG_THEN | FLAG_START }, + { "then", RES_THEN, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, + { "elif", RES_ELIF, FLAG_THEN }, + { "else", RES_ELSE, FLAG_FI }, + { "fi", RES_FI, FLAG_END }, + { "for", RES_FOR, FLAG_IN | FLAG_START }, + { "while", RES_WHILE, FLAG_DO | FLAG_START }, + { "until", RES_UNTIL, FLAG_DO | FLAG_START }, + { "in", RES_IN, FLAG_DO }, + { "do", RES_DO, FLAG_DONE }, + { "done", RES_DONE, FLAG_END } + }; + struct reserved_combo *r; + for (r=reserved_list; +#define NRES sizeof(reserved_list)/sizeof(struct reserved_combo) + rdata, r->literal) == 0) { + debug_printf("found reserved word %s, code %d\n",r->literal,r->code); + if (r->flag & FLAG_START) { + struct p_context *new = xmalloc(sizeof(struct p_context)); + debug_printf("push stack\n"); + if (ctx->w == RES_IN || ctx->w == RES_FOR) { + syntax(); + free(new); + ctx->w = RES_SNTX; + b_reset(dest); + return 1; + } + *new = *ctx; /* physical copy */ + initialize_context(ctx); + ctx->stack=new; + } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<code))) { + syntax(); + ctx->w = RES_SNTX; + b_reset(dest); + return 1; + } + ctx->w=r->code; + ctx->old_flag = r->flag; + if (ctx->old_flag & FLAG_END) { + struct p_context *old; + debug_printf("pop stack\n"); + done_pipe(ctx,PIPE_SEQ); + old = ctx->stack; + old->child->group = ctx->list_head; + old->child->subshell = 0; + *ctx = *old; /* physical copy */ + free(old); + } + b_reset (dest); + return 1; + } + } + return 0; +} + +/* normal return is 0. + * Syntax or xglob errors return 1. */ +static int done_word(o_string *dest, struct p_context *ctx) +{ + struct child_prog *child=ctx->child; + glob_t *glob_target; + int gr, flags = 0; + + debug_printf("done_word: %s %p\n", dest->data, child); + if (dest->length == 0 && !dest->nonnull) { + debug_printf(" true null, ignored\n"); + return 0; + } + if (ctx->pending_redirect) { + glob_target = &ctx->pending_redirect->word; + } else { + if (child->group) { + syntax(); + return 1; /* syntax error, groups and arglists don't mix */ + } + if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) { + debug_printf("checking %s for reserved-ness\n",dest->data); + if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX; + } + glob_target = &child->glob_result; + if (child->argv) flags |= GLOB_APPEND; + } + gr = xglob(dest, flags, glob_target); + if (gr != 0) return 1; + + b_reset(dest); + if (ctx->pending_redirect) { + ctx->pending_redirect=NULL; + if (glob_target->gl_pathc != 1) { + error_msg("ambiguous redirect"); + return 1; + } + } else { + child->argv = glob_target->gl_pathv; + } + if (ctx->w == RES_FOR) { + done_word(dest,ctx); + done_pipe(ctx,PIPE_SEQ); + } + return 0; +} + +/* The only possible error here is out of memory, in which case + * xmalloc exits. */ +static int done_command(struct p_context *ctx) +{ + /* The child is really already in the pipe structure, so + * advance the pipe counter and make a new, null child. + * Only real trickiness here is that the uncommitted + * child structure, to which ctx->child points, is not + * counted in pi->num_progs. */ + struct pipe *pi=ctx->pipe; + struct child_prog *prog=ctx->child; + + if (prog && prog->group == NULL + && prog->argv == NULL + && prog->redirects == NULL) { + debug_printf("done_command: skipping null command\n"); + return 0; + } else if (prog) { + pi->num_progs++; + debug_printf("done_command: num_progs incremented to %d\n",pi->num_progs); + } else { + debug_printf("done_command: initializing\n"); + } + pi->progs = xrealloc(pi->progs, sizeof(*pi->progs) * (pi->num_progs+1)); + + prog = pi->progs + pi->num_progs; + prog->redirects = NULL; + prog->argv = NULL; + prog->is_stopped = 0; + prog->group = NULL; + prog->glob_result.gl_pathv = NULL; + prog->family = pi; + prog->sp = 0; + ctx->child = prog; + prog->type = ctx->type; + + /* but ctx->pipe and ctx->list_head remain unchanged */ + return 0; +} + +static int done_pipe(struct p_context *ctx, pipe_style type) +{ + struct pipe *new_p; + done_command(ctx); /* implicit closure of previous command */ + debug_printf("done_pipe, type %d\n", type); + ctx->pipe->followup = type; + ctx->pipe->r_mode = ctx->w; + new_p=new_pipe(); + ctx->pipe->next = new_p; + ctx->pipe = new_p; + ctx->child = NULL; + done_command(ctx); /* set up new pipe to accept commands */ + return 0; +} + +/* peek ahead in the in_str to find out if we have a "&n" construct, + * as in "2>&1", that represents duplicating a file descriptor. + * returns either -2 (syntax error), -1 (no &), or the number found. + */ +static int redirect_dup_num(struct in_str *input) +{ + int ch, d=0, ok=0; + ch = b_peek(input); + if (ch != '&') return -1; + + b_getch(input); /* get the & */ + ch=b_peek(input); + if (ch == '-') { + b_getch(input); + return -3; /* "-" represents "close me" */ + } + while (isdigit(ch)) { + d = d*10+(ch-'0'); + ok=1; + b_getch(input); + ch = b_peek(input); + } + if (ok) return d; + + error_msg("ambiguous redirect"); + return -2; +} + +/* If a redirect is immediately preceded by a number, that number is + * supposed to tell which file descriptor to redirect. This routine + * looks for such preceding numbers. In an ideal world this routine + * needs to handle all the following classes of redirects... + * echo 2>foo # redirects fd 2 to file "foo", nothing passed to echo + * echo 49>foo # redirects fd 49 to file "foo", nothing passed to echo + * echo -2>foo # redirects fd 1 to file "foo", "-2" passed to echo + * echo 49x>foo # redirects fd 1 to file "foo", "49x" passed to echo + * A -1 output from this program means no valid number was found, so the + * caller should use the appropriate default for this redirection. + */ +static int redirect_opt_num(o_string *o) +{ + int num; + + if (o->length==0) return -1; + for(num=0; numlength; num++) { + if (!isdigit(*(o->data+num))) { + return -1; + } + } + /* reuse num (and save an int) */ + num=atoi(o->data); + b_reset(o); + return num; +} + +FILE *generate_stream_from_list(struct pipe *head) +{ + FILE *pf; +#if 1 + int pid, channel[2]; + if (pipe(channel)<0) perror_msg_and_die("pipe"); + pid=fork(); + if (pid<0) { + perror_msg_and_die("fork"); + } else if (pid==0) { + close(channel[0]); + if (channel[1] != 1) { + dup2(channel[1],1); + close(channel[1]); + } +#if 0 +#define SURROGATE "surrogate response" + write(1,SURROGATE,sizeof(SURROGATE)); + _exit(run_list(head)); +#else + _exit(run_list_real(head)); /* leaks memory */ +#endif + } + debug_printf("forked child %d\n",pid); + close(channel[1]); + pf = fdopen(channel[0],"r"); + debug_printf("pipe on FILE *%p\n",pf); +#else + free_pipe_list(head,0); + pf=popen("echo surrogate response","r"); + debug_printf("started fake pipe on FILE *%p\n",pf); +#endif + return pf; +} + +/* this version hacked for testing purposes */ +/* return code is exit status of the process that is run. */ +static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end) +{ + int retcode; + o_string result=NULL_O_STRING; + struct p_context inner; + FILE *p; + struct in_str pipe_str; + initialize_context(&inner); + + /* recursion to generate command */ + retcode = parse_stream(&result, &inner, input, subst_end); + if (retcode != 0) return retcode; /* syntax error or EOF */ + done_word(&result, &inner); + done_pipe(&inner, PIPE_SEQ); + b_free(&result); + + p=generate_stream_from_list(inner.list_head); + if (p==NULL) return 1; + mark_open(fileno(p)); + setup_file_in_str(&pipe_str, p); + + /* now send results of command back into original context */ + retcode = parse_stream(dest, ctx, &pipe_str, '\0'); + /* XXX In case of a syntax error, should we try to kill the child? + * That would be tough to do right, so just read until EOF. */ + if (retcode == 1) { + while (b_getch(&pipe_str)!=EOF) { /* discard */ }; + } + + debug_printf("done reading from pipe, pclose()ing\n"); + /* This is the step that wait()s for the child. Should be pretty + * safe, since we just read an EOF from its stdout. We could try + * to better, by using wait(), and keeping track of background jobs + * at the same time. That would be a lot of work, and contrary + * to the KISS philosophy of this program. */ + mark_closed(fileno(p)); + retcode=pclose(p); + free_pipe_list(inner.list_head,0); + debug_printf("pclosed, retcode=%d\n",retcode); + /* XXX this process fails to trim a single trailing newline */ + return retcode; +} + +static int parse_group(o_string *dest, struct p_context *ctx, + struct in_str *input, int ch) +{ + int rcode, endch=0; + struct p_context sub; + struct child_prog *child = ctx->child; + if (child->argv) { + syntax(); + return 1; /* syntax error, groups and arglists don't mix */ + } + initialize_context(&sub); + switch(ch) { + case '(': endch=')'; child->subshell=1; break; + case '{': endch='}'; break; + default: syntax(); /* really logic error */ + } + rcode=parse_stream(dest,&sub,input,endch); + done_word(dest,&sub); /* finish off the final word in the subcontext */ + done_pipe(&sub, PIPE_SEQ); /* and the final command there, too */ + child->group = sub.list_head; + return rcode; + /* child remains "open", available for possible redirects */ +} + +/* basically useful version until someone wants to get fancier, + * see the bash man page under "Parameter Expansion" */ +static char *lookup_param(char *src) +{ + char *p=NULL; + if (src) { + p = getenv(src); + if (!p) + p = get_local_var(src); + } + return p; +} + +/* return code: 0 for OK, 1 for syntax error */ +static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input) +{ + int i, advance=0; + char sep[]=" "; + int ch = input->peek(input); /* first character after the $ */ + debug_printf("handle_dollar: ch=%c\n",ch); + if (isalpha(ch)) { + b_addchr(dest, SPECIAL_VAR_SYMBOL); + ctx->child->sp++; + while(ch=b_peek(input),isalnum(ch) || ch=='_') { + b_getch(input); + b_addchr(dest,ch); + } + b_addchr(dest, SPECIAL_VAR_SYMBOL); + } else if (isdigit(ch)) { + i = ch-'0'; /* XXX is $0 special? */ + if (i 0) b_adduint(dest, last_bg_pid); + advance = 1; + break; + case '?': + b_adduint(dest,last_return_code); + advance = 1; + break; + case '#': + b_adduint(dest,global_argc ? global_argc-1 : 0); + advance = 1; + break; + case '{': + b_addchr(dest, SPECIAL_VAR_SYMBOL); + ctx->child->sp++; + b_getch(input); + /* XXX maybe someone will try to escape the '}' */ + while(ch=b_getch(input),ch!=EOF && ch!='}') { + b_addchr(dest,ch); + } + if (ch != '}') { + syntax(); + return 1; + } + b_addchr(dest, SPECIAL_VAR_SYMBOL); + break; + case '(': + b_getch(input); + process_command_subs(dest, ctx, input, ')'); + break; + case '*': + sep[0]=ifs[0]; + for (i=1; iquote); + } + /* Eat the character if the flag was set. If the compiler + * is smart enough, we could substitute "b_getch(input);" + * for all the "advance = 1;" above, and also end up with + * a nice size-optimized program. Hah! That'll be the day. + */ + if (advance) b_getch(input); + return 0; +} + +int parse_string(o_string *dest, struct p_context *ctx, const char *src) +{ + struct in_str foo; + setup_string_in_str(&foo, src); + return parse_stream(dest, ctx, &foo, '\0'); +} + +/* return code is 0 for normal exit, 1 for syntax error */ +int parse_stream(o_string *dest, struct p_context *ctx, + struct in_str *input, int end_trigger) +{ + unsigned int ch, m; + int redir_fd; + redir_type redir_style; + int next; + + /* Only double-quote state is handled in the state variable dest->quote. + * A single-quote triggers a bypass of the main loop until its mate is + * found. When recursing, quote state is passed in via dest->quote. */ + + debug_printf("parse_stream, end_trigger=%d\n",end_trigger); + while ((ch=b_getch(input))!=EOF) { + m = map[ch]; + next = (ch == '\n') ? 0 : b_peek(input); + debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d\n", + ch,ch,m,dest->quote); + if (m==0 || ((m==1 || m==2) && dest->quote)) { + b_addqchr(dest, ch, dest->quote); + } else { + if (m==2) { /* unquoted IFS */ + if (done_word(dest, ctx)) { + return 1; + } + /* If we aren't performing a substitution, treat a newline as a + * command separator. */ + if (end_trigger != '\0' && ch=='\n') + done_pipe(ctx,PIPE_SEQ); + } + if (ch == end_trigger && !dest->quote && ctx->w==RES_NONE) { + debug_printf("leaving parse_stream (triggered)\n"); + return 0; + } +#if 0 + if (ch=='\n') { + /* Yahoo! Time to run with it! */ + done_pipe(ctx,PIPE_SEQ); + run_list(ctx->list_head); + initialize_context(ctx); + } +#endif + if (m!=2) switch (ch) { + case '#': + if (dest->length == 0 && !dest->quote) { + while(ch=b_peek(input),ch!=EOF && ch!='\n') { b_getch(input); } + } else { + b_addqchr(dest, ch, dest->quote); + } + break; + case '\\': + if (next == EOF) { + syntax(); + return 1; + } + b_addqchr(dest, '\\', dest->quote); + b_addqchr(dest, b_getch(input), dest->quote); + break; + case '$': + if (handle_dollar(dest, ctx, input)!=0) return 1; + break; + case '\'': + dest->nonnull = 1; + while(ch=b_getch(input),ch!=EOF && ch!='\'') { + b_addchr(dest,ch); + } + if (ch==EOF) { + syntax(); + return 1; + } + break; + case '"': + dest->nonnull = 1; + dest->quote = !dest->quote; + break; + case '`': + process_command_subs(dest, ctx, input, '`'); + break; + case '>': + redir_fd = redirect_opt_num(dest); + done_word(dest, ctx); + redir_style=REDIRECT_OVERWRITE; + if (next == '>') { + redir_style=REDIRECT_APPEND; + b_getch(input); + } else if (next == '(') { + syntax(); /* until we support >(list) Process Substitution */ + return 1; + } + setup_redirect(ctx, redir_fd, redir_style, input); + break; + case '<': + redir_fd = redirect_opt_num(dest); + done_word(dest, ctx); + redir_style=REDIRECT_INPUT; + if (next == '<') { + redir_style=REDIRECT_HEREIS; + b_getch(input); + } else if (next == '>') { + redir_style=REDIRECT_IO; + b_getch(input); + } else if (next == '(') { + syntax(); /* until we support <(list) Process Substitution */ + return 1; + } + setup_redirect(ctx, redir_fd, redir_style, input); + break; + case ';': + done_word(dest, ctx); + done_pipe(ctx,PIPE_SEQ); + break; + case '&': + done_word(dest, ctx); + if (next=='&') { + b_getch(input); + done_pipe(ctx,PIPE_AND); + } else { + done_pipe(ctx,PIPE_BG); + } + break; + case '|': + done_word(dest, ctx); + if (next=='|') { + b_getch(input); + done_pipe(ctx,PIPE_OR); + } else { + /* we could pick up a file descriptor choice here + * with redirect_opt_num(), but bash doesn't do it. + * "echo foo 2| cat" yields "foo 2". */ + done_command(ctx); + } + break; + case '(': + case '{': + if (parse_group(dest, ctx, input, ch)!=0) return 1; + break; + case ')': + case '}': + syntax(); /* Proper use of this character caught by end_trigger */ + return 1; + break; + default: + syntax(); /* this is really an internal logic error */ + return 1; + } + } + } + /* complain if quote? No, maybe we just finished a command substitution + * that was quoted. Example: + * $ echo "`cat foo` plus more" + * and we just got the EOF generated by the subshell that ran "cat foo" + * The only real complaint is if we got an EOF when end_trigger != '\0', + * that is, we were really supposed to get end_trigger, and never got + * one before the EOF. Can't use the standard "syntax error" return code, + * so that parse_stream_outer can distinguish the EOF and exit smoothly. */ + debug_printf("leaving parse_stream (EOF)\n"); + if (end_trigger != '\0') return -1; + return 0; +} + +void mapset(const unsigned char *set, int code) +{ + const unsigned char *s; + for (s=set; *s; s++) map[*s] = code; +} + +void update_ifs_map(void) +{ + /* char *ifs and char map[256] are both globals. */ + ifs = getenv("IFS"); + if (ifs == NULL) ifs=" \t\n"; + /* Precompute a list of 'flow through' behavior so it can be treated + * quickly up front. Computation is necessary because of IFS. + * Special case handling of IFS == " \t\n" is not implemented. + * The map[] array only really needs two bits each, and on most machines + * that would be faster because of the reduced L1 cache footprint. + */ + memset(map,0,sizeof(map)); /* most characters flow through always */ + mapset("\\$'\"`", 3); /* never flow through */ + mapset("<>;&|(){}#", 1); /* flow through if quoted */ + mapset(ifs, 2); /* also flow through if quoted */ +} + +/* most recursion does not come through here, the exeception is + * from builtin_source() */ +int parse_stream_outer(struct in_str *inp, int flag) +{ + + struct p_context ctx; + o_string temp=NULL_O_STRING; + int rcode; + do { + ctx.type = flag; + initialize_context(&ctx); + update_ifs_map(); + if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset(";$&|", 0); + inp->promptmode=1; + rcode = parse_stream(&temp, &ctx, inp, '\n'); + if (rcode != 1 && ctx.old_flag != 0) { + syntax(); + } + if (rcode != 1 && ctx.old_flag == 0) { + done_word(&temp, &ctx); + done_pipe(&ctx,PIPE_SEQ); + run_list(ctx.list_head); + } else { + if (ctx.old_flag != 0) { + free(ctx.stack); + b_reset(&temp); + } + temp.nonnull = 0; + temp.quote = 0; + inp->p = NULL; + free_pipe_list(ctx.list_head,0); + } + b_free(&temp); + } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */ + return 0; +} + +static int parse_string_outer(const char *s, int flag) +{ + struct in_str input; + setup_string_in_str(&input, s); + return parse_stream_outer(&input, flag); +} + +static int parse_file_outer(FILE *f) +{ + int rcode; + struct in_str input; + setup_file_in_str(&input, f); + rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON); + return rcode; +} + +/* Make sure we have a controlling tty. If we get started under a job + * aware app (like bash for example), make sure we are now in charge so + * we don't fight over who gets the foreground */ +static void setup_job_control() +{ + static pid_t shell_pgrp; + /* Loop until we are in the foreground. */ + while (tcgetpgrp (shell_terminal) != (shell_pgrp = getpgrp ())) + kill (- shell_pgrp, SIGTTIN); + + /* Ignore interactive and job-control signals. */ + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + signal(SIGCHLD, SIG_IGN); + + /* Put ourselves in our own process group. */ + setsid(); + shell_pgrp = getpid (); + setpgid (shell_pgrp, shell_pgrp); + + /* Grab control of the terminal. */ + tcsetpgrp(shell_terminal, shell_pgrp); +} + +int hush_main(int argc, char **argv) +{ + int opt; + FILE *input; + char **e = environ; + + /* XXX what should these be while sourcing /etc/profile? */ + global_argc = argc; + global_argv = argv; + + /* (re?) initialize globals. Sometimes hush_main() ends up calling + * hush_main(), therefore we cannot rely on the BSS to zero out this + * stuff. Reset these to 0 every time. */ + ifs = NULL; + /* map[] is taken care of with call to update_ifs_map() */ + fake_mode = 0; + interactive = 0; + close_me_head = NULL; + last_bg_pid = 0; + job_list = NULL; + last_jobid = 0; + + /* Initialize some more globals to non-zero values */ + set_cwd(); +#ifdef BB_FEATURE_COMMAND_EDITING + cmdedit_set_initial_prompt(); +#else + PS1 = NULL; +#endif + PS2 = "> "; + + /* initialize our shell local variables with the values + * currently living in the environment */ + if (e) { + for (; *e; e++) + set_local_var(*e, 2); /* without call putenv() */ + } + + last_return_code=EXIT_SUCCESS; + + + if (argv[0] && argv[0][0] == '-') { + debug_printf("\nsourcing /etc/profile\n"); + if ((input = fopen("/etc/profile", "r")) != NULL) { + mark_open(fileno(input)); + parse_file_outer(input); + mark_closed(fileno(input)); + fclose(input); + } + } + input=stdin; + + while ((opt = getopt(argc, argv, "c:xif")) > 0) { + switch (opt) { + case 'c': + { + global_argv = argv+optind; + global_argc = argc-optind; + opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON); + goto final_return; + } + break; + case 'i': + interactive++; + break; + case 'f': + fake_mode++; + break; + default: +#ifndef BB_VER + fprintf(stderr, "Usage: sh [FILE]...\n" + " or: sh -c command [args]...\n\n"); + exit(EXIT_FAILURE); +#else + show_usage(); +#endif + } + } + /* A shell is interactive if the `-i' flag was given, or if all of + * the following conditions are met: + * no -c command + * no arguments remaining or the -s flag given + * standard input is a terminal + * standard output is a terminal + * Refer to Posix.2, the description of the `sh' utility. */ + if (argv[optind]==NULL && input==stdin && + isatty(fileno(stdin)) && isatty(fileno(stdout))) { + interactive++; + } + + debug_printf("\ninteractive=%d\n", interactive); + if (interactive) { + /* Looks like they want an interactive shell */ + fprintf(stdout, "\nhush -- the humble shell v0.01 (testing)\n\n"); + setup_job_control(); + } + + if (argv[optind]==NULL) { + opt=parse_file_outer(stdin); + goto final_return; + } + + debug_printf("\nrunning script '%s'\n", argv[optind]); + global_argv = argv+optind; + global_argc = argc-optind; + input = xfopen(argv[optind], "r"); + opt = parse_file_outer(input); + +#ifdef BB_FEATURE_CLEAN_UP + fclose(input); + if (cwd && cwd != unknown) + free((char*)cwd); + { + struct variables *cur, *tmp; + for(cur = top_vars; cur; cur = tmp) { + tmp = cur->next; + if (!cur->flg_read_only) { + free(cur->name); + free(cur->value); + free(cur); + } + } + } +#endif + +final_return: + return(opt?opt:last_return_code); +} + +static char *insert_var_value(char *inp) +{ + int res_str_len = 0; + int len; + int done = 0; + char *p, *p1, *res_str = NULL; + + while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) { + if (p != inp) { + len = p - inp; + res_str = xrealloc(res_str, (res_str_len + len)); + strncpy((res_str + res_str_len), inp, len); + res_str_len += len; + } + inp = ++p; + p = strchr(inp, SPECIAL_VAR_SYMBOL); + *p = '\0'; + if ((p1 = lookup_param(inp))) { + len = res_str_len + strlen(p1); + res_str = xrealloc(res_str, (1 + len)); + strcpy((res_str + res_str_len), p1); + res_str_len = len; + } + *p = SPECIAL_VAR_SYMBOL; + inp = ++p; + done = 1; + } + if (done) { + res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp))); + strcpy((res_str + res_str_len), inp); + while ((p = strchr(res_str, '\n'))) { + *p = ' '; + } + } + return (res_str == NULL) ? inp : res_str; +} + +static char **make_list_in(char **inp, char *name) +{ + int len, i; + int name_len = strlen(name); + int n = 0; + char **list; + char *p1, *p2, *p3; + + /* create list of variable values */ + list = xmalloc(sizeof(*list)); + for (i = 0; inp[i]; i++) { + p3 = insert_var_value(inp[i]); + p1 = p3; + while (*p1) { + if ((*p1 == ' ')) { + p1++; + continue; + } + if ((p2 = strchr(p1, ' '))) { + len = p2 - p1; + } else { + len = strlen(p1); + p2 = p1 + len; + } + /* we use n + 2 in realloc for list,because we add + * new element and then we will add NULL element */ + list = xrealloc(list, sizeof(*list) * (n + 2)); + list[n] = xmalloc(2 + name_len + len); + strcpy(list[n], name); + strcat(list[n], "="); + strncat(list[n], p1, len); + list[n++][name_len + len + 1] = '\0'; + p1 = p2; + } + if (p3 != inp[i]) free(p3); + } + list[n] = NULL; + return list; +} + +/* Make new string for parser */ +static char * make_string(char ** inp) +{ + char *p; + char *str = NULL; + int n; + int len = 2; + + for (n = 0; inp[n]; n++) { + p = insert_var_value(inp[n]); + str = xrealloc(str, (len + strlen(p))); + if (n) { + strcat(str, " "); + } else { + *str = '\0'; + } + strcat(str, p); + len = strlen(str) + 3; + if (p != inp[n]) free(p); + } + len = strlen(str); + *(str + len) = '\n'; + *(str + len + 1) = '\0'; + return str; +} diff --git a/id.c b/id.c new file mode 100644 index 000000000..85b288c0c --- /dev/null +++ b/id.c @@ -0,0 +1,97 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini id implementation for busybox + * + * Copyright (C) 2000 by Randolph Chung + * + * 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 "busybox.h" +#include +#include +#include +#include +#include + +extern int id_main(int argc, char **argv) +{ + int no_user = 0, no_group = 0, print_real = 0; + int name_not_number = 0; + char user[9], group[9]; + long gid; + long pwnam, grnam; + int opt; + + gid = 0; + + while ((opt = getopt(argc, argv, "ugrn")) > 0) { + switch (opt) { + case 'u': + no_group++; + break; + case 'g': + no_user++; + break; + case 'r': + print_real++; + break; + case 'n': + name_not_number++; + break; + default: + show_usage(); + } + } + + if (no_user && no_group) show_usage(); + + if (argv[optind] == NULL) { + if (print_real) { + my_getpwuid(user, getuid()); + my_getgrgid(group, getgid()); + } else { + my_getpwuid(user, geteuid()); + my_getgrgid(group, getegid()); + } + } else { + strncpy(user, argv[optind], 8); + user[8] = '\0'; + gid = my_getpwnamegid(user); + my_getgrgid(group, gid); + } + + pwnam=my_getpwnam(user); + grnam=my_getgrnam(group); + + if (no_group) { + if(name_not_number && user) + puts(user); + else + printf("%ld\n", pwnam); + } else if (no_user) { + if(name_not_number && group) + puts(group); + else + printf("%ld\n", grnam); + } else { + printf("uid=%ld(%s) gid=%ld(%s)\n", pwnam, user, grnam, group); + } + return(0); +} + + +/* END CODE */ diff --git a/ifconfig.c b/ifconfig.c new file mode 100644 index 000000000..1986adaa7 --- /dev/null +++ b/ifconfig.c @@ -0,0 +1,493 @@ +/* ifconfig + * + * Similar to the standard Unix ifconfig, but with only the necessary + * parts for AF_INET, and without any printing of if info (for now). + * + * Bjorn Wesen, Axis Communications AB + * + * + * Authors of the original ifconfig was: + * Fred N. van Kempen, + * + * 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. + * + * $Id: ifconfig.c,v 1.16 2003/11/14 03:04:56 andersen Exp $ + * + */ + +/* + * Heavily modified by Manuel Novoa III Mar 6, 2001 + * + * From initial port to busybox, removed most of the redundancy by + * converting to a table-driven approach. Added several (optional) + * args missing from initial port. + * + * Still missing: media, tunnel. + */ + +#include +#include +#include // strcmp and friends +#include // isdigit and friends +#include /* offsetof */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +#ifdef BB_FEATURE_IFCONFIG_SLIP +#include +#endif + +/* I don't know if this is needed for busybox or not. Anyone? */ +#define QUESTIONABLE_ALIAS_CASE + + +/* Defines for glibc2.0 users. */ +#ifndef SIOCSIFTXQLEN +#define SIOCSIFTXQLEN 0x8943 +#define SIOCGIFTXQLEN 0x8942 +#endif + +/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */ +#ifndef ifr_qlen +#define ifr_qlen ifr_ifru.ifru_mtu +#endif + +#ifndef IFF_DYNAMIC +#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */ +#endif + +/* + * Here are the bit masks for the "flags" member of struct options below. + * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'. + * CLR clears the flag; SET sets the flag; ARG signifies (optional) arg. + */ +#define N_CLR 0x01 +#define M_CLR 0x02 +#define N_SET 0x04 +#define M_SET 0x08 +#define N_ARG 0x10 +#define M_ARG 0x20 + +#define M_MASK (M_CLR | M_SET | M_ARG) +#define N_MASK (N_CLR | N_SET | N_ARG) +#define SET_MASK (N_SET | M_SET) +#define CLR_MASK (N_CLR | M_CLR) +#define SET_CLR_MASK (SET_MASK | CLR_MASK) +#define ARG_MASK (M_ARG | N_ARG) + +/* + * Here are the bit masks for the "arg_flags" member of struct options below. + */ + +/* + * cast type: + * 00 int + * 01 char * + * 02 HOST_COPY in_ether + * 03 HOST_COPY INET_resolve + */ +#define A_CAST_TYPE 0x03 +/* + * map type: + * 00 not a map type (mem_start, io_addr, irq) + * 04 memstart (unsigned long) + * 08 io_addr (unsigned short) + * 0C irq (unsigned char) + */ +#define A_MAP_TYPE 0x0C +#define A_ARG_REQ 0x10 /* Set if an arg is required. */ +#define A_NETMASK 0x20 /* Set if netmask (check for multiple sets). */ +#define A_SET_AFTER 0x40 /* Set a flag at the end. */ +#define A_COLON_CHK 0x80 /* Is this needed? See below. */ + +/* + * These defines are for dealing with the A_CAST_TYPE field. + */ +#define A_CAST_CHAR_PTR 0x01 +#define A_CAST_RESOLVE 0x01 +#define A_CAST_HOST_COPY 0x02 +#define A_CAST_HOST_COPY_IN_ETHER A_CAST_HOST_COPY +#define A_CAST_HOST_COPY_RESOLVE (A_CAST_HOST_COPY | A_CAST_RESOLVE) + +/* + * These defines are for dealing with the A_MAP_TYPE field. + */ +#define A_MAP_ULONG 0x04 /* memstart */ +#define A_MAP_USHORT 0x08 /* io_addr */ +#define A_MAP_UCHAR 0x0C /* irq */ + +/* + * Define the bit masks signifying which operations to perform for each arg. + */ + +#define ARG_METRIC (A_ARG_REQ /*| A_CAST_INT*/) +#define ARG_MTU (A_ARG_REQ /*| A_CAST_INT*/) +#define ARG_TXQUEUELEN (A_ARG_REQ /*| A_CAST_INT*/) +#define ARG_MEM_START (A_ARG_REQ | A_MAP_ULONG) +#define ARG_IO_ADDR (A_ARG_REQ | A_MAP_ULONG) +#define ARG_IRQ (A_ARG_REQ | A_MAP_UCHAR) +#define ARG_DSTADDR (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE) +#define ARG_NETMASK (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_NETMASK) +#define ARG_BROADCAST (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER) +#define ARG_HW (A_ARG_REQ | A_CAST_HOST_COPY_IN_ETHER) +#define ARG_POINTOPOINT (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER) +#define ARG_KEEPALIVE (A_ARG_REQ | A_CAST_CHAR_PTR) +#define ARG_OUTFILL (A_ARG_REQ | A_CAST_CHAR_PTR) +#define ARG_HOSTNAME (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK) + + +/* + * Set up the tables. Warning! They must have corresponding order! + */ + +struct arg1opt { + const char *name; + unsigned short selector; + unsigned short ifr_offset; +}; + +struct options { + const char *name; + const unsigned char flags; + const unsigned char arg_flags; + const unsigned short selector; +}; + +#define ifreq_offsetof(x) offsetof(struct ifreq, x) + +static const struct arg1opt Arg1Opt[] = { + {"SIOCSIFMETRIC", SIOCSIFMETRIC, ifreq_offsetof(ifr_metric)}, + {"SIOCSIFMTU", SIOCSIFMTU, ifreq_offsetof(ifr_mtu)}, + {"SIOCSIFTXQLEN", SIOCSIFTXQLEN, ifreq_offsetof(ifr_qlen)}, + {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)}, + {"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)}, + {"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)}, +#ifdef BB_FEATURE_IFCONFIG_HW + {"SIOCSIFHWADDR", SIOCSIFHWADDR, ifreq_offsetof(ifr_hwaddr)}, +#endif + {"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)}, +#ifdef SIOCSKEEPALIVE + {"SIOCSKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data)}, +#endif +#ifdef SIOCSOUTFILL + {"SIOCSOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data)}, +#endif +#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ + {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.mem_start)}, + {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.base_addr)}, + {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq)}, +#endif + /* Last entry if for unmatched (possibly hostname) arg. */ + {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)}, +}; + +static const struct options OptArray[] = { + {"metric", N_ARG, ARG_METRIC, 0}, + {"mtu", N_ARG, ARG_MTU, 0}, + {"txqueuelen", N_ARG, ARG_TXQUEUELEN, 0}, + {"dstaddr", N_ARG, ARG_DSTADDR, 0}, + {"netmask", N_ARG, ARG_NETMASK, 0}, + {"broadcast", N_ARG | M_CLR, ARG_BROADCAST, IFF_BROADCAST}, +#ifdef BB_FEATURE_IFCONFIG_HW + {"hw", N_ARG, ARG_HW, 0}, +#endif + {"pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT}, +#ifdef SIOCSKEEPALIVE + {"keepalive", N_ARG, ARG_KEEPALIVE, 0}, +#endif +#ifdef SIOCSOUTFILL + {"outfill", N_ARG, ARG_OUTFILL, 0}, +#endif +#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ + {"mem_start", N_ARG, ARG_MEM_START, 0}, + {"io_addr", N_ARG, ARG_IO_ADDR, 0}, + {"irq", N_ARG, ARG_IRQ, 0}, +#endif + {"arp", N_CLR | M_SET, 0, IFF_NOARP}, + {"trailers", N_CLR | M_SET, 0, IFF_NOTRAILERS}, + {"promisc", N_SET | M_CLR, 0, IFF_PROMISC}, + {"multicast", N_SET | M_CLR, 0, IFF_MULTICAST}, + {"allmulti", N_SET | M_CLR, 0, IFF_ALLMULTI}, + {"dynamic", N_SET | M_CLR, 0, IFF_DYNAMIC}, + {"up", N_SET , 0, (IFF_UP | IFF_RUNNING)}, + {"down", N_CLR , 0, IFF_UP}, + { NULL, 0, ARG_HOSTNAME, (IFF_UP | IFF_RUNNING)} +}; + +/* + * A couple of prototypes. + */ + +#ifdef BB_FEATURE_IFCONFIG_HW +static int in_ether(char *bufp, struct sockaddr *sap); +#endif + +#ifdef BB_FEATURE_IFCONFIG_STATUS +extern int interface_opt_a; +extern int display_interfaces(char *ifname); +#endif + +/* + * Our main function. + */ + +int ifconfig_main(int argc, char **argv) +{ + struct ifreq ifr; + struct sockaddr_in sai; +#ifdef BB_FEATURE_IFCONFIG_HW + struct sockaddr sa; +#endif + const struct arg1opt *a1op; + const struct options *op; + int sockfd; /* socket fd we use to manipulate stuff with */ + int goterr; + int selector; + char *p; + char host[128]; + unsigned char mask; + unsigned char did_flags; + + goterr = 0; + did_flags = 0; + + /* skip argv[0] */ + ++argv; + --argc; + +#ifdef BB_FEATURE_IFCONFIG_STATUS + if ((argc > 0) && (strcmp(*argv,"-a") == 0)) { + interface_opt_a = 1; + --argc; + ++argv; + } +#endif + + if(argc <= 1) { +#ifdef BB_FEATURE_IFCONFIG_STATUS + return display_interfaces(argc ? *argv : NULL); +#else + error_msg_and_die( "ifconfig was not compiled with interface status display support."); +#endif + } + + /* Create a channel to the NET kernel. */ + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror_msg_and_die("socket"); + } + + /* get interface name */ + safe_strncpy(ifr.ifr_name, *argv, IFNAMSIZ); + + /* Process the remaining arguments. */ + while (*++argv != (char *) NULL) { + p = *argv; + mask = N_MASK; + if (*p == '-') { /* If the arg starts with '-'... */ + ++p; /* advance past it and */ + mask = M_MASK; /* set the appropriate mask. */ + } + for (op = OptArray ; op->name ; op++) { /* Find table entry. */ + if (strcmp(p,op->name) == 0) { /* If name matches... */ + if ((mask &= op->flags)) { /* set the mask and go. */ + goto FOUND_ARG;; + } + /* If we get here, there was a valid arg with an */ + /* invalid '-' prefix. */ + ++goterr; + goto LOOP; + } + } + + /* We fell through, so treat as possible hostname. */ + a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1; + mask = op->arg_flags; + goto HOSTNAME; + + FOUND_ARG: + if (mask & ARG_MASK) { + mask = op->arg_flags; + a1op = Arg1Opt + (op - OptArray); + if (mask & A_NETMASK & did_flags) { + show_usage(); + } + if (*++argv == NULL) { + if (mask & A_ARG_REQ) { + show_usage(); + } else { + --argv; + mask &= A_SET_AFTER; /* just for broadcast */ + } + } else { /* got an arg so process it */ + HOSTNAME: + did_flags |= (mask & A_NETMASK); + if (mask & A_CAST_HOST_COPY) { +#ifdef BB_FEATURE_IFCONFIG_HW + if (mask & A_CAST_RESOLVE) { +#endif + safe_strncpy(host, *argv, (sizeof host)); + sai.sin_family = AF_INET; + sai.sin_port = 0; + if (!strcmp(host, "default")) { + /* Default is special, meaning 0.0.0.0. */ + sai.sin_addr.s_addr = INADDR_ANY; + } else if (inet_aton(host, &sai.sin_addr) == 0) { + /* It's not a dotted quad. */ + ++goterr; + continue; + } + p = (char *) &sai; +#ifdef BB_FEATURE_IFCONFIG_HW + } else { /* A_CAST_HOST_COPY_IN_ETHER */ + /* This is the "hw" arg case. */ + if (strcmp("ether", *argv) || (*++argv == NULL)) { + show_usage(); + } + safe_strncpy(host, *argv, (sizeof host)); + if (in_ether(host, &sa)) { + fprintf(stderr, "invalid hw-addr %s\n", host); + ++goterr; + continue; + } + p = (char *) &sa; + } +#endif + memcpy((((char *)(&ifr)) + a1op->ifr_offset), + p, sizeof(struct sockaddr)); + } else { + unsigned int i = strtoul(*argv,NULL,0); + p = ((char *)(&ifr)) + a1op->ifr_offset; +#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ + if (mask & A_MAP_TYPE) { + if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) { + ++goterr; + continue; + } + if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) { + *((unsigned char *) p) = i; + } else if (mask & A_MAP_USHORT) { + *((unsigned short *) p) = i; + } else { + *((unsigned long *) p) = i; + } + } else +#endif + if (mask & A_CAST_CHAR_PTR) { + *((caddr_t *) p) = (caddr_t) i; + } else { /* A_CAST_INT */ + *((int *) p) = i; + } + } + + if (ioctl(sockfd, a1op->selector, &ifr) < 0) { + perror(a1op->name); + ++goterr; + continue; + } + +#ifdef QUESTIONABLE_ALIAS_CASE + if (mask & A_COLON_CHK) { + /* + * Don't do the set_flag() if the address is an alias with + * a - at the end, since it's deleted already! - Roman + * + * Should really use regex.h here, not sure though how well + * it'll go with the cross-platform support etc. + */ + char *ptr; + short int found_colon = 0; + for (ptr = ifr.ifr_name; *ptr; ptr++ ) { + if (*ptr == ':') { + found_colon++; + } + } + + if (found_colon && *(ptr - 1) == '-') { + continue; + } + } +#endif + } + if (!(mask & A_SET_AFTER)) { + continue; + } + mask = N_SET; + } + + if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { + perror("SIOCGIFFLAGS"); + ++goterr; + } else { + selector = op->selector; + if (mask & SET_MASK) { + ifr.ifr_flags |= selector; + } else { + ifr.ifr_flags &= ~selector; + } + if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { + perror("SIOCSIFFLAGS"); + ++goterr; + } + } + LOOP: + continue; + } /* end of while-loop */ + + return goterr; +} + +#ifdef BB_FEATURE_IFCONFIG_HW +/* Input an Ethernet address and convert to binary. */ +static int +in_ether(char *bufp, struct sockaddr *sap) +{ + unsigned char *ptr; + int i, j; + unsigned char val; + unsigned char c; + + sap->sa_family = ARPHRD_ETHER; + ptr = sap->sa_data; + + for (i = 0 ; i < ETH_ALEN ; i++) { + val = 0; + + /* We might get a semicolon here - not required. */ + if (i && (*bufp == ':')) { + bufp++; + } + + for (j=0 ; j<2 ; j++) { + c = *bufp; + if (c >= '0' && c <= '9') { + c -= '0'; + } else if (c >= 'a' && c <= 'f') { + c -= ('a' - 10); + } else if (c >= 'A' && c <= 'F') { + c -= ('A' - 10); + } else if (j && (c == ':' || c == 0)) { + break; + } else { + return -1; + } + ++bufp; + val <<= 4; + val += c; + } + *ptr++ = val; + } + + return (int) (*bufp); /* Error if we don't end at end of string. */ +} +#endif diff --git a/init.c b/init.c new file mode 100644 index 000000000..7e4145a11 --- /dev/null +++ b/init.c @@ -0,0 +1,1206 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini init implementation for busybox + * + * + * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 1999-2002 Erik Andersen + * Adjusted by so many folks, it's impossible to keep track. + * + * 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 + * + */ + +/* Turn this on to disable all the dangerous + rebooting stuff when debugging. +#define DEBUG_INIT +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" +#ifdef BB_SYSLOGD +# include +#endif +#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__) +#include +#endif + + +#define INIT_BUFFS_SIZE 256 + +/* From */ +struct vt_stat { + unsigned short v_active; /* active vt */ + unsigned short v_signal; /* signal to send */ + unsigned short v_state; /* vt bitmask */ +}; +static const int VT_GETSTATE = 0x5603; /* get global vt state info */ + +/* From */ +struct serial_struct { + int type; + int line; + unsigned int port; + int irq; + int flags; + int xmit_fifo_size; + int custom_divisor; + int baud_base; + unsigned short close_delay; + char io_type; + char reserved_char[1]; + int hub6; + unsigned short closing_wait; /* time to wait before closing */ + unsigned short closing_wait2; /* no longer used... */ + unsigned char *iomem_base; + unsigned short iomem_reg_shift; + unsigned int port_high; + unsigned long iomap_base; /* cookie passed into ioremap */ + int reserved[1]; +}; + + +#ifndef _PATH_STDPATH +#define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin" +#endif + +#if defined BB_FEATURE_INIT_COREDUMPS +/* + * When a file named CORE_ENABLE_FLAG_FILE exists, setrlimit is called + * before processes are spawned to set core file size as unlimited. + * This is for debugging only. Don't use this is production, unless + * you want core dumps lying about.... + */ +#define CORE_ENABLE_FLAG_FILE "/.init_enable_core" +#include +#include +#endif + +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) + +#if __GNU_LIBRARY__ > 5 + #include +#else + extern int bdflush (int func, long int data); +#endif + +#define SHELL "/bin/sh" /* Default shell */ +#define LOGIN_SHELL "-" SHELL /* Default login shell */ +#define INITTAB "/etc/inittab" /* inittab file location */ +#ifndef INIT_SCRIPT +#define INIT_SCRIPT "/etc/init.d/rcS" /* Default sysinit script. */ +#endif + +#define MAXENV 16 /* Number of env. vars */ + +/* Allowed init action types */ +#define SYSINIT 0x001 +#define RESPAWN 0x002 +#define ASKFIRST 0x004 +#define WAIT 0x008 +#define ONCE 0x010 +#define CTRLALTDEL 0x020 +#define SHUTDOWN 0x040 +#define RESTART 0x080 + +/* A mapping between "inittab" action name strings and action type codes. */ +struct init_action_type { + const char *name; + int action; +}; + +static const struct init_action_type actions[] = { + {"sysinit", SYSINIT}, + {"respawn", RESPAWN}, + {"askfirst", ASKFIRST}, + {"wait", WAIT}, + {"once", ONCE}, + {"ctrlaltdel", CTRLALTDEL}, + {"shutdown", SHUTDOWN}, + {"restart", RESTART}, + {0, 0} +}; + +/* Set up a linked list of init_actions, to be read from inittab */ +struct init_action { + pid_t pid; + char command[INIT_BUFFS_SIZE]; + char terminal[INIT_BUFFS_SIZE]; + struct init_action *next; + int action; +}; + +/* Static variables */ +static struct init_action *init_action_list = NULL; +static int kernelVersion = 0; +static char termType[32] = "TERM=linux"; +static char console[32] = _PATH_CONSOLE; +#ifndef BB_SYSLOGD +static char *log = VC_5; +#endif +static sig_atomic_t got_cont = 0; +static const int LOG = 0x1; +static const int CONSOLE = 0x2; +#if defined BB_FEATURE_EXTRA_QUIET +static const int MAYBE_CONSOLE = 0x0; +#else +#define MAYBE_CONSOLE CONSOLE +#endif +#ifndef RB_HALT_SYSTEM +static const int RB_HALT_SYSTEM = 0xcdef0123; +static const int RB_ENABLE_CAD = 0x89abcdef; +static const int RB_DISABLE_CAD = 0; +#define RB_POWER_OFF 0x4321fedc +static const int RB_AUTOBOOT = 0x01234567; +#endif + +/* Function prototypes */ +static void delete_init_action(struct init_action *a); +static int waitfor(struct init_action *a); +static void halt_signal(int sig); + + +static void loop_forever(void) +{ + while (1) + sleep (1); +} + +/* Print a message to the specified device. + * Device may be bitwise-or'd from LOG | CONSOLE */ +#ifdef DEBUG_INIT +static inline messageND(int device, char *fmt, ...) { } +#else +#define messageND message +#endif +static void message(int device, char *fmt, ...) __attribute__ ((format (printf, 2, 3))); +static void message(int device, char *fmt, ...) +{ + va_list arguments; + int fd; + +#ifdef BB_SYSLOGD + + /* Log the message to syslogd */ + if (device & LOG) { + char msg[1024]; + + va_start(arguments, fmt); + vsnprintf(msg, sizeof(msg), fmt, arguments); + va_end(arguments); + syslog_msg(LOG_USER, LOG_INFO, msg); + } +#else + static int log_fd = -1; + + /* Take full control of the log tty, and never close it. + * It's mine, all mine! Muhahahaha! */ + if (log_fd < 0) { + if ((log_fd = device_open(log, O_RDWR|O_NDELAY)) < 0) { + log_fd = -2; + fprintf(stderr, "Bummer, can't write to log on %s!\n", log); + device = CONSOLE; + } else { + fcntl(log_fd, F_SETFD, FD_CLOEXEC); + } + } + if ((device & LOG) && (log_fd >= 0)) { + va_start(arguments, fmt); + vdprintf(log_fd, fmt, arguments); + va_end(arguments); + } +#endif + + if (device & CONSOLE) { + /* Always send console messages to /dev/console so people will see them. */ + if ( + (fd = + device_open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) { + va_start(arguments, fmt); + vdprintf(fd, fmt, arguments); + va_end(arguments); + close(fd); + } else { + fprintf(stderr, "Bummer, can't print: "); + va_start(arguments, fmt); + vfprintf(stderr, fmt, arguments); + va_end(arguments); + } + } +} + +/* Set terminal settings to reasonable defaults */ +static void set_term(int fd) +{ + struct termios tty; + + tcgetattr(fd, &tty); + + /* set control chars */ + tty.c_cc[VINTR] = 3; /* C-c */ + tty.c_cc[VQUIT] = 28; /* C-\ */ + tty.c_cc[VERASE] = 127; /* C-? */ + tty.c_cc[VKILL] = 21; /* C-u */ + tty.c_cc[VEOF] = 4; /* C-d */ + tty.c_cc[VSTART] = 17; /* C-q */ + tty.c_cc[VSTOP] = 19; /* C-s */ + tty.c_cc[VSUSP] = 26; /* C-z */ + + /* use line dicipline 0 */ + tty.c_line = 0; + + /* Make it be sane */ + tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD; + tty.c_cflag |= CREAD|HUPCL|CLOCAL; + + + /* input modes */ + tty.c_iflag = ICRNL | IXON | IXOFF; + + /* output modes */ + tty.c_oflag = OPOST | ONLCR; + + /* local modes */ + tty.c_lflag = + ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; + + tcsetattr(fd, TCSANOW, &tty); +} + +/* How much memory does this machine have? + Units are kBytes to avoid overflow on 4GB machines */ +static int check_free_memory(void) +{ + struct sysinfo info; + unsigned int result, u, s=10; + + if (sysinfo(&info) != 0) { + perror_msg("Error checking free memory"); + return -1; + } + + /* Kernels 2.0.x and 2.2.x return info.mem_unit==0 with values in bytes. + * Kernels 2.4.0 return info.mem_unit in bytes. */ + u = info.mem_unit; + if (u==0) u=1; + while ( (u&1) == 0 && s > 0 ) { u>>=1; s--; } + result = (info.totalram>>s) + (info.totalswap>>s); + result = result*u; + if (result < 0) result = INT_MAX; + return result; +} + +static void console_init(void) +{ + int fd; + int tried_devcons = 0; + int tried_vtprimary = 0; + struct vt_stat vt; + struct serial_struct sr; + char *s; + + if ((s = getenv("TERM")) != NULL) { + snprintf(termType, sizeof(termType) - 1, "TERM=%s", s); + } + + if ((s = getenv("CONSOLE")) != NULL) { + safe_strncpy(console, s, sizeof(console)); + } +#if #cpu(sparc) + /* sparc kernel supports console=tty[ab] parameter which is also + * passed to init, so catch it here */ + else if ((s = getenv("console")) != NULL) { + /* remap tty[ab] to /dev/ttyS[01] */ + if (strcmp(s, "ttya") == 0) + safe_strncpy(console, SC_0, sizeof(console)); + else if (strcmp(s, "ttyb") == 0) + safe_strncpy(console, SC_1, sizeof(console)); + } +#endif + else { + /* 2.2 kernels: identify the real console backend and try to use it */ + if (ioctl(0, TIOCGSERIAL, &sr) == 0) { + /* this is a serial console */ + snprintf(console, sizeof(console) - 1, SC_FORMAT, sr.line); + } else if (ioctl(0, VT_GETSTATE, &vt) == 0) { + /* this is linux virtual tty */ + snprintf(console, sizeof(console) - 1, VC_FORMAT, vt.v_active); + } else { + safe_strncpy(console, _PATH_CONSOLE, sizeof(console)); + tried_devcons++; + } + } + + while ((fd = open(console, O_RDONLY | O_NONBLOCK)) < 0) { + /* Can't open selected console -- try /dev/console */ + if (!tried_devcons) { + tried_devcons++; + safe_strncpy(console, _PATH_CONSOLE, sizeof(console)); + continue; + } + /* Can't open selected console -- try vt1 */ + if (!tried_vtprimary) { + tried_vtprimary++; + safe_strncpy(console, VC_1, sizeof(console)); + continue; + } + break; + } + if (fd < 0) { + /* Perhaps we should panic here? */ + safe_strncpy(console, "/dev/null", sizeof(console)); + } else { + /* check for serial console */ + if (ioctl(0, TIOCGSERIAL, &sr) == 0) { + /* Force the TERM setting to vt102 for serial console -- + * if TERM is set to linux (the default) */ + if (strcmp( termType, "TERM=linux" ) == 0) + safe_strncpy(termType, "TERM=vt102", sizeof(termType)); + } + close(fd); + } + message(LOG, "console=%s\n", console); +} + +static void fixup_argv(int argc, char **argv, char *new_argv0) +{ + int len; + /* Fix up argv[0] to be certain we claim to be init */ + len = strlen(argv[0]); + memset(argv[0], 0, len); + safe_strncpy(argv[0], new_argv0, len + 1); + + /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */ + len = 1; + while (argc > len) { + memset(argv[len], 0, strlen(argv[len])); + len++; + } +} + +/* Make sure there is enough memory to do something useful. * + * Calls "swapon -a" if needed so be sure /etc/fstab is present... */ +static void check_memory(void) +{ +#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__) + struct stat statBuf; +#endif + + if (check_free_memory() > 1000) + return; + +#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__) + if (stat("/etc/fstab", &statBuf) == 0) { + /* swapon -a requires /proc typically */ + system("/bin/mount -t proc proc /proc"); + /* Try to turn on swap */ + system("/sbin/swapon -a"); + if (check_free_memory() < 1000) + goto goodnight; + } else + goto goodnight; + return; + goodnight: +#endif + message(CONSOLE, + "\rSorry, your computer does not have enough memory.\n"); + loop_forever(); +} + +static pid_t run(struct init_action *a) +{ + struct stat sb; + int i, j, junk; + pid_t pid, pgrp, tmp_pid; + char *s, *tmpCmd, *cmd[INIT_BUFFS_SIZE], *cmdpath; + char buf[INIT_BUFFS_SIZE+6]; /* INIT_BUFFS_SIZE+strlen("exec ")+1 */ + sigset_t nmask, omask; + char *environment[MAXENV+1] = { + termType, + "HOME=/", + "PATH=" _PATH_STDPATH, + "SHELL=" SHELL, + "USER=root", + NULL + }; + static const char press_enter[] = +#ifdef CUSTOMIZED_BANNER +#include CUSTOMIZED_BANNER +#endif + "\nPlease press Enter to activate this console. "; +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &tmp_pid; +#endif + + /* inherit environment to the child, merging our values -andy */ + for (i=0; environ[i]; i++) { + for (j=0; environment[j]; j++) { + s = strchr(environment[j], '='); + if (!strncmp(environ[i], environment[j], s - environment[j])) + break; + } + if (!environment[j]) { + environment[j++] = environ[i]; + environment[j] = NULL; + } + } + + /* Block sigchild while forking. */ + sigemptyset(&nmask); + sigaddset(&nmask, SIGCHLD); + sigprocmask(SIG_BLOCK, &nmask, &omask); + + if ((pid = fork()) == 0) + { + /* Clean up */ + close(0); + close(1); + close(2); + sigprocmask(SIG_SETMASK, &omask, NULL); + + /* Reset signal handlers that were set by the parent process */ + signal(SIGUSR1, SIG_DFL); + signal(SIGUSR2, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGCONT, SIG_DFL); + signal(SIGSTOP, SIG_DFL); + signal(SIGTSTP, SIG_DFL); + + /* Create a new session and make ourself the process + * group leader */ + setsid(); + + /* Open the new terminal device */ + if ((device_open(a->terminal, O_RDWR)) < 0) { + if (stat(a->terminal, &sb) != 0) { + message(LOG | CONSOLE, "\rdevice '%s' does not exist.\n", + a->terminal); + _exit(1); + } + message(LOG | CONSOLE, "\rBummer, can't open %s\n", a->terminal); + _exit(1); + } + + /* Make sure the terminal will act fairly normal for us */ + set_term(0); + /* Setup stdout, stderr for the new process so + * they point to the supplied terminal */ + dup(0); + dup(0); + + /* If the init Action requires us to wait, then force the + * supplied terminal to be the controlling tty. */ + if (a->action & (SYSINIT|WAIT|CTRLALTDEL|SHUTDOWN|RESTART)) { + + /* Now fork off another process to just hang around */ + if ((pid = fork()) < 0) { + message(LOG | CONSOLE, "Can't fork!\n"); + _exit(1); + } + + if (pid > 0) { + + /* We are the parent -- wait till the child is done */ + signal(SIGINT, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGCHLD, SIG_DFL); + + /* Wait for child to exit */ + while ((tmp_pid = waitpid(pid, &junk, 0)) != pid) + ; + + /* See if stealing the controlling tty back is necessary */ + pgrp = tcgetpgrp(0); + if (pgrp != getpid()) + _exit(0); + + /* Use a temporary process to steal the controlling tty. */ + if ((pid = fork()) < 0) { + message(LOG | CONSOLE, "\rCan't fork!\n"); + _exit(1); + } + if (pid == 0) { + setsid(); + ioctl(0, TIOCSCTTY, 1); + _exit(0); + } + while((tmp_pid = waitpid(pid, &junk, 0)) != pid) { + if (tmp_pid < 0 && errno == ECHILD) + break; + } + _exit(0); + } + + /* Now fall though to actually execute things */ + } + + /* See if any special /bin/sh requiring characters are present */ + if (strpbrk(a->command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { + cmd[0] = SHELL; + cmd[1] = "-c"; + strcat(strcpy(buf, "exec "), a->command); + cmd[2] = buf; + cmd[3] = NULL; + } else { + /* Convert command (char*) into cmd (char**, one word per string) */ + strcpy(buf, a->command); + s = buf; + for (tmpCmd = buf, i = 0; + (tmpCmd = strsep(&s, " \t")) != NULL;) { + if (*tmpCmd != '\0') { + cmd[i] = tmpCmd; + i++; + } + } + cmd[i] = NULL; + } + + cmdpath = cmd[0]; + + /* + Interactive shells want to see a dash in argv[0]. This + typically is handled by login, argv will be setup this + way if a dash appears at the front of the command path + (like "-/bin/sh"). + */ + + if (*cmdpath == '-') { + + /* skip over the dash */ + ++cmdpath; + + /* find the last component in the command pathname */ + s = get_last_path_component(cmdpath); + + /* make a new argv[0] */ + if ((cmd[0] = malloc(strlen(s)+2)) == NULL) { + message(LOG | CONSOLE, "malloc failed"); + cmd[0] = cmdpath; + } else { + cmd[0][0] = '-'; + strcpy(cmd[0]+1, s); + } + } + + if (a->action & ASKFIRST) { + /* + * Save memory by not exec-ing anything large (like a shell) + * before the user wants it. This is critical if swap is not + * enabled and the system has low memory. Generally this will + * be run on the second virtual console, and the first will + * be allowed to start a shell or whatever an init script + * specifies. + */ + messageND(LOG, "Waiting for enter to start '%s' (pid %d, terminal %s)\n", + cmdpath, getpid(), a->terminal); + fflush(stdout); + write(fileno(stdout), press_enter, sizeof(press_enter) - 1); + getc(stdin); + } + + /* Log the process name and args */ + messageND(LOG, "Starting pid %d, console %s: '%s'\n", + getpid(), a->terminal, cmdpath); + +#if defined BB_FEATURE_INIT_COREDUMPS + if (stat (CORE_ENABLE_FLAG_FILE, &sb) == 0) { + struct rlimit limit; + limit.rlim_cur = RLIM_INFINITY; + limit.rlim_max = RLIM_INFINITY; + setrlimit(RLIMIT_CORE, &limit); + } +#endif + + /* Now run it. The new program will take over this PID, + * so nothing further in init.c should be run. */ + execve(cmdpath, cmd, environment); + + /* We're still here? Some error happened. */ + message(LOG | CONSOLE, "\rBummer, could not run '%s': %s\n", cmdpath, + strerror(errno)); + _exit(-1); + } + sigprocmask(SIG_SETMASK, &omask, NULL); + return pid; +} + +static int waitfor(struct init_action *a) +{ + int pid; + int status, wpid; + + pid = run(a); + while (1) { + wpid = wait(&status); + if (wpid > 0 && wpid != pid) { + continue; + } + if (wpid == pid) + break; + } + return wpid; +} + +/* Run all commands of a particular type */ +static void run_actions(int action) +{ + struct init_action *a, *tmp; + + for (a = init_action_list; a; a = tmp) { + tmp = a->next; + if (a->action == action) { + if (a->action & (SYSINIT|WAIT|CTRLALTDEL|SHUTDOWN|RESTART)) { + waitfor(a); + delete_init_action(a); + } else if (a->action & ONCE) { + run(a); + delete_init_action(a); + } else if (a->action & (RESPAWN|ASKFIRST)) { + /* Only run stuff with pid==0. If they have + * a pid, that means it is still running */ + if (a->pid == 0) { + a->pid = run(a); + } + } + } + } +} + + +#ifndef DEBUG_INIT +static void init_reboot(unsigned long magic) +{ + pid_t pid; + /* We have to fork here, since the kernel calls do_exit(0) in + * linux/kernel/sys.c, which can cause the machine to panic when + * the init process is killed.... */ + if ((pid = fork()) == 0) { +#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__) + reboot(magic); +#else + reboot(0xfee1dead, 672274793, magic); +#endif + _exit(0); + } + waitpid (pid, NULL, 0); +} + +static void shutdown_system(void) +{ + sigset_t block_signals; + + /* run everything to be run at "shutdown". This is done _prior_ + * to killing everything, in case people wish to use scripts to + * shut things down gracefully... */ + run_actions(SHUTDOWN); + + /* first disable all our signals */ + sigemptyset(&block_signals); + sigaddset(&block_signals, SIGHUP); + sigaddset(&block_signals, SIGCHLD); + sigaddset(&block_signals, SIGUSR1); + sigaddset(&block_signals, SIGUSR2); + sigaddset(&block_signals, SIGINT); + sigaddset(&block_signals, SIGTERM); + sigaddset(&block_signals, SIGCONT); + sigaddset(&block_signals, SIGSTOP); + sigaddset(&block_signals, SIGTSTP); + sigprocmask(SIG_BLOCK, &block_signals, NULL); + + /* Allow Ctrl-Alt-Del to reboot system. */ + init_reboot(RB_ENABLE_CAD); + + message(CONSOLE|LOG, "\n\rThe system is going down NOW !!\n"); + sync(); + + /* Send signals to every process _except_ pid 1 */ + message(CONSOLE|LOG, "\rSending SIGTERM to all processes.\n"); + kill(-1, SIGTERM); + sleep(1); + sync(); + + message(CONSOLE|LOG, "\rSending SIGKILL to all processes.\n"); + kill(-1, SIGKILL); + sleep(1); + + sync(); +#if 0 + if (kernelVersion > 0 && kernelVersion <= KERNEL_VERSION(2,2,11)) { + /* bdflush, kupdate not needed for kernels >2.2.11 */ + bdflush(1, 0); + sync(); + } +#endif +} + +static void exec_signal(int sig) +{ + struct init_action *a, *tmp; + sigset_t unblock_signals; + + for (a = init_action_list; a; a = tmp) { + tmp = a->next; + if (a->action & RESTART) { + struct stat sb; + + shutdown_system(); + + /* unblock all signals, blocked in shutdown_system() */ + sigemptyset(&unblock_signals); + sigaddset(&unblock_signals, SIGHUP); + sigaddset(&unblock_signals, SIGCHLD); + sigaddset(&unblock_signals, SIGUSR1); + sigaddset(&unblock_signals, SIGUSR2); + sigaddset(&unblock_signals, SIGINT); + sigaddset(&unblock_signals, SIGTERM); + sigaddset(&unblock_signals, SIGCONT); + sigaddset(&unblock_signals, SIGSTOP); + sigaddset(&unblock_signals, SIGTSTP); + sigprocmask(SIG_UNBLOCK, &unblock_signals, NULL); + + /* Open the new terminal device */ + if ((device_open(a->terminal, O_RDWR)) < 0) { + if (stat(a->terminal, &sb) != 0) { + message(LOG | CONSOLE, "device '%s' does not exist.", a->terminal); + } else { + message(LOG | CONSOLE, "Bummer, can't open %s", a->terminal); + } + halt_signal(SIGUSR1); + } + + /* Make sure the terminal will act fairly normal for us */ + set_term(0); + /* Setup stdout, stderr on the supplied terminal */ + dup(0); + dup(0); + + message(CONSOLE|LOG, "\rTrying to re-exec %s\n", a->command); + execl(a->command, a->command, NULL); + + message(CONSOLE|LOG, "\rexec of '%s' failed: %s\n", + a->command, strerror(errno)); + sync(); + sleep(2); + init_reboot(RB_HALT_SYSTEM); + loop_forever(); + } + } +} + +static void halt_signal(int sig) +{ + shutdown_system(); + message(CONSOLE|LOG, +#if #cpu(s390) + /* Seems the s390 console is Wierd(tm). */ + "\rThe system is halted. You may reboot now.\n" +#else + "\rThe system is halted. Press Reset or turn off power\n" +#endif + ); + sync(); + + /* allow time for last message to reach serial console */ + sleep(2); + + if (sig == SIGUSR2 && kernelVersion >= KERNEL_VERSION(2,2,0)) + init_reboot(RB_POWER_OFF); + else + init_reboot(RB_HALT_SYSTEM); + + loop_forever(); +} + +static void reboot_signal(int sig) +{ + shutdown_system(); + message(CONSOLE|LOG, "\rPlease stand by while rebooting the system.\n"); + sync(); + + /* allow time for last message to reach serial console */ + sleep(2); + + init_reboot(RB_AUTOBOOT); + + loop_forever(); +} + +static void ctrlaltdel_signal(int sig) +{ + run_actions(CTRLALTDEL); +} + +/* The SIGSTOP & SIGTSTP handler */ +static void stop_handler(int sig) +{ + int saved_errno = errno; + + got_cont = 0; + while(!got_cont) pause(); + got_cont = 0; + errno = saved_errno; +} + +/* The SIGCONT handler */ +static void cont_handler(int sig) +{ + got_cont = 1; +} + +/* Reap any zombie processes that are reparented to init */ +static void child_handler(int sig) +{ + int status; + while ( wait3(&status, WNOHANG, NULL) > 0 ); +} + +#endif /* ! DEBUG_INIT */ + +static void new_init_action(int action, char *command, char *cons) +{ + struct init_action *new_action, *a; + + if (*cons == '\0') + cons = console; + + /* do not run entries if console device is not available */ + if (access(cons, R_OK|W_OK)) + return; + if (strcmp(cons, "/dev/null") == 0 && (action & ASKFIRST)) + return; + + new_action = calloc((size_t) (1), sizeof(struct init_action)); + if (!new_action) { + message(LOG | CONSOLE, "\rMemory allocation failure\n"); + loop_forever(); + } + + /* Append to the end of the list */ + for (a = init_action_list; a && a->next; a = a->next) ; + if (a) { + a->next = new_action; + } else { + init_action_list = new_action; + } + strcpy(new_action->command, command); + new_action->action = action; + strcpy(new_action->terminal, cons); + new_action->pid = 0; +// message(LOG|CONSOLE, "command='%s' action='%d' terminal='%s'\n", +// new_action->command, new_action->action, new_action->terminal); +} + +static void delete_init_action(struct init_action * action) +{ + struct init_action *a, *b = NULL; + + for (a = init_action_list; a; b = a, a = a->next) { + if (a == action) { + if (b == NULL) { + init_action_list = a->next; + } else { + b->next = a->next; + } + free(a); + break; + } + } +} + +/* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined, + * then parse_inittab() simply adds in some default + * actions(i.e., runs INIT_SCRIPT and then starts a pair + * of "askfirst" shells). If BB_FEATURE_USE_INITTAB + * _is_ defined, but /etc/inittab is missing, this + * results in the same set of default behaviors. + * */ +static void parse_inittab(void) +{ +#ifdef BB_FEATURE_USE_INITTAB + FILE *file; + char buf[INIT_BUFFS_SIZE], lineAsRead[INIT_BUFFS_SIZE], tmpConsole[INIT_BUFFS_SIZE]; + char *id, *runlev, *action, *command, *eol; + const struct init_action_type *a = actions; + int foundIt; + + + file = fopen(INITTAB, "r"); + if (file == NULL) { + /* No inittab file -- set up some default behavior */ +#endif + /* Reboot on Ctrl-Alt-Del */ + new_init_action(CTRLALTDEL, "/sbin/reboot", console); + /* Umount all filesystems on halt/reboot */ + new_init_action(SHUTDOWN, "/bin/umount -a -r", console); +#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__) + /* Swapoff on halt/reboot */ + new_init_action(SHUTDOWN, "/sbin/swapoff -a", console); +#endif + /* Prepare to restart init when a HUP is received */ + new_init_action(RESTART, "/sbin/init", console); + /* Askfirst shell on tty1-4 */ + new_init_action(ASKFIRST, LOGIN_SHELL, console); + new_init_action(ASKFIRST, LOGIN_SHELL, VC_2); + new_init_action(ASKFIRST, LOGIN_SHELL, VC_3); + new_init_action(ASKFIRST, LOGIN_SHELL, VC_4); + /* sysinit */ + new_init_action(SYSINIT, INIT_SCRIPT, console); + + return; +#ifdef BB_FEATURE_USE_INITTAB + } + + while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) { + foundIt = FALSE; + /* Skip leading spaces */ + for (id = buf; *id == ' ' || *id == '\t'; id++); + + /* Skip the line if it's a comment */ + if (*id == '#' || *id == '\n') + continue; + + /* Trim the trailing \n */ + eol = strrchr(id, '\n'); + if (eol != NULL) + *eol = '\0'; + + /* Keep a copy around for posterity's sake (and error msgs) */ + strcpy(lineAsRead, buf); + + /* Separate the ID field from the runlevels */ + runlev = strchr(id, ':'); + if (runlev == NULL || *(runlev + 1) == '\0') { + message(LOG | CONSOLE, "\rBad inittab entry: %s\n", lineAsRead); + continue; + } else { + *runlev = '\0'; + ++runlev; + } + + /* Separate the runlevels from the action */ + action = strchr(runlev, ':'); + if (action == NULL || *(action + 1) == '\0') { + message(LOG | CONSOLE, "\rBad inittab entry: %s\n", lineAsRead); + continue; + } else { + *action = '\0'; + ++action; + } + + /* Separate the action from the command */ + command = strchr(action, ':'); + if (command == NULL || *(command + 1) == '\0') { + message(LOG | CONSOLE, "\rBad inittab entry: %s\n", lineAsRead); + continue; + } else { + *command = '\0'; + ++command; + } + + /* Ok, now process it */ + a = actions; + while (a->name != 0) { + if (strcmp(a->name, action) == 0) { + if (*id != '\0') { + strcpy(tmpConsole, "/dev/"); + strncat(tmpConsole, id, INIT_BUFFS_SIZE-6); + id = tmpConsole; + } + new_init_action(a->action, command, id); + foundIt = TRUE; + } + a++; + } + if (foundIt == TRUE) + continue; + else { + /* Choke on an unknown action */ + message(LOG | CONSOLE, "\rBad inittab entry: %s\n", lineAsRead); + } + } + fclose(file); + return; +#endif /* BB_FEATURE_USE_INITTAB */ +} + + + +extern int init_main(int argc, char **argv) +{ + struct init_action *a; + pid_t wpid; + int status; + + if (argc > 1 && !strcmp(argv[1], "-q")) { + /* don't assume init's pid == 1 */ + long *pid = find_pid_by_name("init"); + if (!pid || *pid<=0) { + pid = find_pid_by_name("linuxrc"); + if (!pid || *pid<=0) + error_msg_and_die("no process killed"); + } + kill(*pid, SIGHUP); + exit(0); + } + +#ifndef DEBUG_INIT + /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ + if (getpid() != 1 +#ifdef BB_FEATURE_LINUXRC + && strstr(applet_name, "linuxrc") == NULL +#endif + ) + { + show_usage(); + } + /* Set up sig handlers -- be sure to + * clear all of these in run() */ + signal(SIGHUP, exec_signal); + signal(SIGUSR1, halt_signal); + signal(SIGUSR2, halt_signal); + signal(SIGINT, ctrlaltdel_signal); + signal(SIGTERM, reboot_signal); + signal(SIGCONT, cont_handler); + signal(SIGSTOP, stop_handler); + signal(SIGTSTP, stop_handler); + signal(SIGCHLD, child_handler); + + /* Turn off rebooting via CTL-ALT-DEL -- we get a + * SIGINT on CAD so we can shut things down gracefully... */ + init_reboot(RB_DISABLE_CAD); +#endif + + /* Figure out what kernel this is running */ + kernelVersion = get_kernel_revision(); + + /* Figure out where the default console should be */ + console_init(); + + /* Close whatever files are open, and reset the console. */ + close(0); + close(1); + close(2); + + if(device_open(console, O_RDWR|O_NOCTTY)==0) { + set_term(0); + close(0); + } + + chdir("/"); + setsid(); + + /* Make sure PATH is set to something sane */ + putenv("PATH="_PATH_STDPATH); + + /* Hello world */ + message(MAYBE_CONSOLE|LOG, "\rinit started: %s\n", full_version); + + /* Make sure there is enough memory to do something useful. */ + check_memory(); + + /* Check if we are supposed to be in single user mode */ + if (argc > 1 && (!strcmp(argv[1], "single") || + !strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) { + /* Ask first then start a shell on tty2-4 */ + new_init_action(ASKFIRST, LOGIN_SHELL, VC_2); + new_init_action(ASKFIRST, LOGIN_SHELL, VC_3); + new_init_action(ASKFIRST, LOGIN_SHELL, VC_4); + /* Start a shell on tty1 */ + new_init_action(RESPAWN, LOGIN_SHELL, console); + } else { + /* Not in single user mode -- see what inittab says */ + + /* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined, + * then parse_inittab() simply adds in some default + * actions(i.e., runs INIT_SCRIPT and then starts a pair + * of "askfirst" shells */ + parse_inittab(); + } + + /* Make the command line just say "init" -- thats all, nothing else */ + fixup_argv(argc, argv, "init"); + + /* Now run everything that needs to be run */ + + /* First run the sysinit command */ + run_actions(SYSINIT); + + /* Next run anything that wants to block */ + run_actions(WAIT); + + /* Next run anything to be run only once */ + run_actions(ONCE); + + /* If there is nothing else to do, stop */ + if (init_action_list == NULL) { + message(LOG | CONSOLE, "\rNo more tasks for init -- sleeping forever.\n"); + loop_forever(); + } + + /* Now run the looping stuff for the rest of forever */ + while (1) { + /* run the respawn stuff */ + run_actions(RESPAWN); + + /* run the askfirst stuff */ + run_actions(ASKFIRST); + + /* Don't consume all CPU time -- sleep a bit */ + sleep(1); + + /* Wait for a child process to exit */ + wpid = wait(&status); + while (wpid > 0) { + /* Find out who died and clean up their corpse */ + for (a = init_action_list; a; a = a->next) { + if (a->pid == wpid) { + /* Set the pid to 0 so that the process gets + * restarted by run_actions() */ + a->pid = 0; + message(LOG, "Process '%s' (pid %d) exited. " + "Scheduling it for restart.\n", a->command, wpid); + } + } + /* see if anyone else is waiting to be reaped */ + wpid = waitpid (-1, &status, WNOHANG); + } + } +} + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/insmod.c b/insmod.c new file mode 100644 index 000000000..c612e686a --- /dev/null +++ b/insmod.c @@ -0,0 +1,3727 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini insmod implementation for busybox + * + * This version of insmod supports x86, ARM, SH3/4, powerpc, m68k, + * and MIPS. + * + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999-2002 Erik Andersen + * Written by Erik Andersen and Ron Alder + * + * Modified by Bryan Rittmeyer to support SH4 + * and (theoretically) SH3. I have only tested SH4 in little endian mode. + * + * Modified by Alcove, Julien Gaulmin and + * Nicolas Ferre to support ARM7TDMI. Only + * very minor changes required to also work with StrongArm and presumably + * all ARM based systems. + * + * Magnus Damm 22-May-2002. + * The plt and got code are now using the same structs. + * Added generic linked list code to fully support PowerPC. + * Replaced the mess in arch_apply_relocation() with architecture blocks. + * The arch_create_got() function got cleaned up with architecture blocks. + * These blocks should be easy maintain and sync with obj_xxx.c in modutils. + * + * Magnus Damm added PowerPC support 20-Feb-2001. + * PowerPC specific code stolen from modutils-2.3.16, + * written by Paul Mackerras, Copyright 1996, 1997 Linux International. + * I've only tested the code on mpc8xx platforms in big-endian mode. + * Did some cleanup and added BB_USE_xxx_ENTRIES... + * + * Quinn Jensen added MIPS support 23-Feb-2001. + * based on modutils-2.4.2 + * MIPS specific support for Elf loading and relocation. + * Copyright 1996, 1997 Linux International. + * Contributed by Ralf Baechle + * + * Based almost entirely on the Linux modutils-2.3.11 implementation. + * Copyright 1996, 1997 Linux International. + * New implementation contributed by Richard Henderson + * Based on original work by Bjorn Ekwall + * Restructured (and partly rewritten) by: + * Björn Ekwall February 1999 + * + * 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 +#include +#include +#include "busybox.h" + +#ifdef BB_FEATURE_NEW_MODULE_INTERFACE +# undef BB_FEATURE_OLD_MODULE_INTERFACE +# define new_sys_init_module init_module +#else +# define old_sys_init_module init_module +#endif + +#ifdef BB_FEATURE_INSMOD_LOADINKMEM +#define LOADBITS 0 +#else +#define LOADBITS 1 +#endif + +#if defined(__arm__) +#define BB_USE_PLT_ENTRIES +#define BB_PLT_ENTRY_SIZE 8 +#define BB_USE_GOT_ENTRIES +#define BB_GOT_ENTRY_SIZE 8 +#define BB_USE_SINGLE + +#define MATCH_MACHINE(x) (x == EM_ARM) +#define SHT_RELM SHT_REL +#define Elf32_RelM Elf32_Rel +#define ELFCLASSM ELFCLASS32 +#endif + +#if defined(__i386__) +#define BB_USE_GOT_ENTRIES +#define BB_GOT_ENTRY_SIZE 4 +#define BB_USE_SINGLE + +#ifndef EM_486 +#define MATCH_MACHINE(x) (x == EM_386) +#else +#define MATCH_MACHINE(x) (x == EM_386 || x == EM_486) +#endif + +#define SHT_RELM SHT_REL +#define Elf32_RelM Elf32_Rel +#define ELFCLASSM ELFCLASS32 +#endif + +#if defined(__mc68000__) +#define BB_USE_GOT_ENTRIES +#define BB_GOT_ENTRY_SIZE 4 +#define BB_USE_SINGLE + +#define MATCH_MACHINE(x) (x == EM_68K) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#endif + +#if defined(__mips__) +/* Account for ELF spec changes. */ +#ifndef EM_MIPS_RS3_LE +#ifdef EM_MIPS_RS4_BE +#define EM_MIPS_RS3_LE EM_MIPS_RS4_BE +#else +#define EM_MIPS_RS3_LE 10 +#endif +#endif /* !EM_MIPS_RS3_LE */ + +#define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE) +#define SHT_RELM SHT_REL +#define Elf32_RelM Elf32_Rel +#define ELFCLASSM ELFCLASS32 +#define ARCHDATAM "__dbe_table" +#endif + +#if defined(__powerpc__) +#define BB_USE_PLT_ENTRIES +#define BB_PLT_ENTRY_SIZE 16 +#define BB_USE_PLT_LIST +#define BB_LIST_ARCHTYPE ElfW(Addr) +#define BB_USE_LIST + +#define MATCH_MACHINE(x) (x == EM_PPC) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#define ARCHDATAM "__ftr_fixup" +#endif + +#if defined(__sh__) +#define BB_USE_GOT_ENTRIES +#define BB_GOT_ENTRY_SIZE 4 +#define BB_USE_SINGLE + +#define MATCH_MACHINE(x) (x == EM_SH) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 + +/* the SH changes have only been tested on the SH4 in =little endian= mode */ +/* I'm not sure about big endian, so let's warn: */ + +#if (defined(__SH4__) || defined(__SH3__)) && defined(__BIG_ENDIAN__) +#error insmod.c may require changes for use on big endian SH4/SH3 +#endif + +/* it may or may not work on the SH1/SH2... So let's error on those + also */ +#if (defined(__sh__) && (!(defined(__SH3__) || defined(__SH4__)))) +#error insmod.c may require changes for non-SH3/SH4 use +#endif +#endif + +#ifndef SHT_RELM +#error Sorry, but insmod.c does not yet support this architecture... +#endif + +//---------------------------------------------------------------------------- +//--------modutils module.h, lines 45-242 +//---------------------------------------------------------------------------- + +/* Definitions for the Linux module syscall interface. + Copyright 1996, 1997 Linux International. + + Contributed by Richard Henderson + + This file is part of the Linux modutils. + + 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. */ + + +#ifndef MODUTILS_MODULE_H +#define MODUTILS_MODULE_H + +/* This file contains the structures used by the 2.0 and 2.1 kernels. + We do not use the kernel headers directly because we do not wish + to be dependant on a particular kernel version to compile insmod. */ + + +/*======================================================================*/ +/* The structures used by Linux 2.0. */ + +/* The symbol format used by get_kernel_syms(2). */ +struct old_kernel_sym +{ + unsigned long value; + char name[60]; +}; + +struct old_module_ref +{ + unsigned long module; /* kernel addresses */ + unsigned long next; +}; + +struct old_module_symbol +{ + unsigned long addr; + unsigned long name; +}; + +struct old_symbol_table +{ + int size; /* total, including string table!!! */ + int n_symbols; + int n_refs; + struct old_module_symbol symbol[0]; /* actual size defined by n_symbols */ + struct old_module_ref ref[0]; /* actual size defined by n_refs */ +}; + +struct old_mod_routines +{ + unsigned long init; + unsigned long cleanup; +}; + +struct old_module +{ + unsigned long next; + unsigned long ref; /* the list of modules that refer to me */ + unsigned long symtab; + unsigned long name; + int size; /* size of module in pages */ + unsigned long addr; /* address of module */ + int state; + unsigned long cleanup; /* cleanup routine */ +}; + +/* Sent to init_module(2) or'ed into the code size parameter. */ +static const int OLD_MOD_AUTOCLEAN = 0x40000000; /* big enough, but no sign problems... */ + +int get_kernel_syms(struct old_kernel_sym *); +int old_sys_init_module(const char *name, char *code, unsigned codesize, + struct old_mod_routines *, struct old_symbol_table *); + +/*======================================================================*/ +/* For sizeof() which are related to the module platform and not to the + environment isnmod is running in, use sizeof_xx instead of sizeof(xx). */ + +#define tgt_sizeof_char sizeof(char) +#define tgt_sizeof_short sizeof(short) +#define tgt_sizeof_int sizeof(int) +#define tgt_sizeof_long sizeof(long) +#define tgt_sizeof_char_p sizeof(char *) +#define tgt_sizeof_void_p sizeof(void *) +#define tgt_long long + +#if defined(__sparc__) && !defined(__sparc_v9__) && defined(ARCH_sparc64) +#undef tgt_sizeof_long +#undef tgt_sizeof_char_p +#undef tgt_sizeof_void_p +#undef tgt_long +static const int tgt_sizeof_long = 8; +static const int tgt_sizeof_char_p = 8; +static const int tgt_sizeof_void_p = 8; +#define tgt_long long long +#endif + +/*======================================================================*/ +/* The structures used in Linux 2.1. */ + +/* Note: new_module_symbol does not use tgt_long intentionally */ +struct new_module_symbol +{ + unsigned long value; + unsigned long name; +}; + +struct new_module_persist; + +struct new_module_ref +{ + unsigned tgt_long dep; /* kernel addresses */ + unsigned tgt_long ref; + unsigned tgt_long next_ref; +}; + +struct new_module +{ + unsigned tgt_long size_of_struct; /* == sizeof(module) */ + unsigned tgt_long next; + unsigned tgt_long name; + unsigned tgt_long size; + + tgt_long usecount; + unsigned tgt_long flags; /* AUTOCLEAN et al */ + + unsigned nsyms; + unsigned ndeps; + + unsigned tgt_long syms; + unsigned tgt_long deps; + unsigned tgt_long refs; + unsigned tgt_long init; + unsigned tgt_long cleanup; + unsigned tgt_long ex_table_start; + unsigned tgt_long ex_table_end; +#ifdef __alpha__ + unsigned tgt_long gp; +#endif + /* Everything after here is extension. */ + unsigned tgt_long persist_start; + unsigned tgt_long persist_end; + unsigned tgt_long can_unload; + unsigned tgt_long runsize; +#ifdef BB_FEATURE_NEW_MODULE_INTERFACE + const char *kallsyms_start; /* All symbols for kernel debugging */ + const char *kallsyms_end; + const char *archdata_start; /* arch specific data for module */ + const char *archdata_end; + const char *kernel_data; /* Reserved for kernel internal use */ +#endif +}; + +#ifdef ARCHDATAM +#define ARCHDATA_SEC_NAME ARCHDATAM +#else +#define ARCHDATA_SEC_NAME "__archdata" +#endif +#define KALLSYMS_SEC_NAME "__kallsyms" + + +struct new_module_info +{ + unsigned long addr; + unsigned long size; + unsigned long flags; + long usecount; +}; + +/* Bits of module.flags. */ +static const int NEW_MOD_RUNNING = 1; +static const int NEW_MOD_DELETED = 2; +static const int NEW_MOD_AUTOCLEAN = 4; +static const int NEW_MOD_VISITED = 8; +static const int NEW_MOD_USED_ONCE = 16; + +int new_sys_init_module(const char *name, const struct new_module *); +int query_module(const char *name, int which, void *buf, size_t bufsize, + size_t *ret); + +/* Values for query_module's which. */ + +static const int QM_MODULES = 1; +static const int QM_DEPS = 2; +static const int QM_REFS = 3; +static const int QM_SYMBOLS = 4; +static const int QM_INFO = 5; + +/*======================================================================*/ +/* The system calls unchanged between 2.0 and 2.1. */ + +unsigned long create_module(const char *, size_t); +int delete_module(const char *); + + +#endif /* module.h */ + +//---------------------------------------------------------------------------- +//--------end of modutils module.h +//---------------------------------------------------------------------------- + + + +//---------------------------------------------------------------------------- +//--------modutils obj.h, lines 253-462 +//---------------------------------------------------------------------------- + +/* Elf object file loading and relocation routines. + Copyright 1996, 1997 Linux International. + + Contributed by Richard Henderson + + This file is part of the Linux modutils. + + 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. */ + + +#ifndef MODUTILS_OBJ_H +static const int MODUTILS_OBJ_H = 1; + +/* The relocatable object is manipulated using elfin types. */ + +#include +#include +#include + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define ELFDATAM ELFDATA2LSB +#elif __BYTE_ORDER == __BIG_ENDIAN +#define ELFDATAM ELFDATA2MSB +#endif + +#ifndef ElfW +# if ELFCLASSM == ELFCLASS32 +# define ElfW(x) Elf32_ ## x +# define ELFW(x) ELF32_ ## x +# else +# define ElfW(x) Elf64_ ## x +# define ELFW(x) ELF64_ ## x +# endif +#endif + +/* For some reason this is missing from libc5. */ +#ifndef ELF32_ST_INFO +# define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) +#endif + +#ifndef ELF64_ST_INFO +# define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) +#endif + +struct obj_string_patch; +struct obj_symbol_patch; + +struct obj_section +{ + ElfW(Shdr) header; + const char *name; + char *contents; + struct obj_section *load_next; + int idx; +}; + +struct obj_symbol +{ + struct obj_symbol *next; /* hash table link */ + const char *name; + unsigned long value; + unsigned long size; + int secidx; /* the defining section index/module */ + int info; + int ksymidx; /* for export to the kernel symtab */ + int referenced; /* actually used in the link */ +}; + +/* Hardcode the hash table size. We shouldn't be needing so many + symbols that we begin to degrade performance, and we get a big win + by giving the compiler a constant divisor. */ + +#define HASH_BUCKETS 521 + +struct obj_file +{ + ElfW(Ehdr) header; + ElfW(Addr) baseaddr; + struct obj_section **sections; + struct obj_section *load_order; + struct obj_section **load_order_search_start; + struct obj_string_patch *string_patches; + struct obj_symbol_patch *symbol_patches; + int (*symbol_cmp)(const char *, const char *); + unsigned long (*symbol_hash)(const char *); + unsigned long local_symtab_size; + struct obj_symbol **local_symtab; + struct obj_symbol *symtab[HASH_BUCKETS]; +}; + +enum obj_reloc +{ + obj_reloc_ok, + obj_reloc_overflow, + obj_reloc_dangerous, + obj_reloc_unhandled +}; + +struct obj_string_patch +{ + struct obj_string_patch *next; + int reloc_secidx; + ElfW(Addr) reloc_offset; + ElfW(Addr) string_offset; +}; + +struct obj_symbol_patch +{ + struct obj_symbol_patch *next; + int reloc_secidx; + ElfW(Addr) reloc_offset; + struct obj_symbol *sym; +}; + + +/* Generic object manipulation routines. */ + +static unsigned long obj_elf_hash(const char *); + +static unsigned long obj_elf_hash_n(const char *, unsigned long len); + +static struct obj_symbol *obj_find_symbol (struct obj_file *f, + const char *name); + +static ElfW(Addr) obj_symbol_final_value(struct obj_file *f, + struct obj_symbol *sym); + +#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING +static void obj_set_symbol_compare(struct obj_file *f, + int (*cmp)(const char *, const char *), + unsigned long (*hash)(const char *)); +#endif + +static struct obj_section *obj_find_section (struct obj_file *f, + const char *name); + +static void obj_insert_section_load_order (struct obj_file *f, + struct obj_section *sec); + +static struct obj_section *obj_create_alloced_section (struct obj_file *f, + const char *name, + unsigned long align, + unsigned long size); + +static struct obj_section *obj_create_alloced_section_first (struct obj_file *f, + const char *name, + unsigned long align, + unsigned long size); + +static void *obj_extend_section (struct obj_section *sec, unsigned long more); + +static int obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, + const char *string); + +#ifdef BB_FEATURE_NEW_MODULE_INTERFACE +static int obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, + struct obj_symbol *sym); +#endif + +static int obj_check_undefineds(struct obj_file *f); + +static void obj_allocate_commons(struct obj_file *f); + +static unsigned long obj_load_size (struct obj_file *f); + +static int obj_relocate (struct obj_file *f, ElfW(Addr) base); + +static struct obj_file *obj_load(FILE *f, int loadprogbits); + +static int obj_create_image (struct obj_file *f, char *image); + +/* Architecture specific manipulation routines. */ + +static struct obj_file *arch_new_file (void); + +static struct obj_section *arch_new_section (void); + +static struct obj_symbol *arch_new_symbol (void); + +static enum obj_reloc arch_apply_relocation (struct obj_file *f, + struct obj_section *targsec, + struct obj_section *symsec, + struct obj_symbol *sym, + ElfW(RelM) *rel, ElfW(Addr) value); + +static void arch_create_got (struct obj_file *f); + +#ifdef BB_FEATURE_NEW_MODULE_INTERFACE +static int arch_init_module (struct obj_file *f, struct new_module *); +#endif + +#endif /* obj.h */ +//---------------------------------------------------------------------------- +//--------end of modutils obj.h +//---------------------------------------------------------------------------- + + + + + +#define _PATH_MODULES "/lib/modules" +static const int STRVERSIONLEN = 32; + +/*======================================================================*/ + +static int flag_force_load = 0; +static int flag_autoclean = 0; +static int flag_verbose = 0; +static int flag_quiet = 0; +static int flag_export = 1; + + +/*======================================================================*/ + +#if defined(BB_USE_LIST) + +struct arch_list_entry +{ + struct arch_list_entry *next; + BB_LIST_ARCHTYPE addend; + int offset; + int inited : 1; +}; + +#endif + +#if defined(BB_USE_SINGLE) + +struct arch_single_entry +{ + int offset; + int inited : 1; + int allocated : 1; +}; + +#endif + +#if defined(__mips__) +struct mips_hi16 +{ + struct mips_hi16 *next; + Elf32_Addr *addr; + Elf32_Addr value; +}; +#endif + +struct arch_file { + struct obj_file root; +#if defined(BB_USE_PLT_ENTRIES) + struct obj_section *plt; +#endif +#if defined(BB_USE_GOT_ENTRIES) + struct obj_section *got; +#endif +#if defined(__mips__) + struct mips_hi16 *mips_hi16_list; +#endif +}; + +struct arch_symbol { + struct obj_symbol root; +#if defined(BB_USE_PLT_ENTRIES) +#if defined(BB_USE_PLT_LIST) + struct arch_list_entry *pltent; +#else + struct arch_single_entry pltent; +#endif +#endif +#if defined(BB_USE_GOT_ENTRIES) + struct arch_single_entry gotent; +#endif +}; + + +struct external_module { + const char *name; + ElfW(Addr) addr; + int used; + size_t nsyms; + struct new_module_symbol *syms; +}; + +static struct new_module_symbol *ksyms; +static size_t nksyms; + +static struct external_module *ext_modules; +static int n_ext_modules; +static int n_ext_modules_used; +extern int delete_module(const char *); + +static char m_filename[FILENAME_MAX]; +static char m_fullName[FILENAME_MAX]; + + + +/*======================================================================*/ + + +static int check_module_name_match(const char *filename, struct stat *statbuf, + void *userdata) +{ + char *fullname = (char *) userdata; + + if (fullname[0] == '\0') + return (FALSE); + else { + char *tmp, *tmp1 = strdup(filename); + tmp = get_last_path_component(tmp1); + if (strcmp(tmp, fullname) == 0) { + free(tmp1); + /* Stop searching if we find a match */ + safe_strncpy(m_filename, filename, sizeof(m_filename)); + return (TRUE); + } + free(tmp1); + } + return (FALSE); +} + + +/*======================================================================*/ + +static struct obj_file *arch_new_file(void) +{ + struct arch_file *f; + f = xmalloc(sizeof(*f)); + + memset(f, 0, sizeof(*f)); + + return &f->root; +} + +static struct obj_section *arch_new_section(void) +{ + return xmalloc(sizeof(struct obj_section)); +} + +static struct obj_symbol *arch_new_symbol(void) +{ + struct arch_symbol *sym; + sym = xmalloc(sizeof(*sym)); + + memset(sym, 0, sizeof(*sym)); + + return &sym->root; +} + +static enum obj_reloc +arch_apply_relocation(struct obj_file *f, + struct obj_section *targsec, + struct obj_section *symsec, + struct obj_symbol *sym, + ElfW(RelM) *rel, ElfW(Addr) v) +{ + struct arch_file *ifile = (struct arch_file *) f; + enum obj_reloc ret = obj_reloc_ok; + ElfW(Addr) *loc = (ElfW(Addr) *) (targsec->contents + rel->r_offset); + ElfW(Addr) dot = targsec->header.sh_addr + rel->r_offset; +#if defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES) + struct arch_symbol *isym = (struct arch_symbol *) sym; +#endif +#if defined(BB_USE_GOT_ENTRIES) + ElfW(Addr) got = ifile->got ? ifile->got->header.sh_addr : 0; +#endif +#if defined(BB_USE_PLT_ENTRIES) + ElfW(Addr) plt = ifile->plt ? ifile->plt->header.sh_addr : 0; + unsigned long *ip; +#if defined(BB_USE_PLT_LIST) + struct arch_list_entry *pe; +#else + struct arch_single_entry *pe; +#endif +#endif + + switch (ELF32_R_TYPE(rel->r_info)) { + +#if defined(__arm__) + case R_ARM_NONE: + break; + + case R_ARM_ABS32: + *loc += v; + break; + + case R_ARM_GOT32: + goto bb_use_got; + + case R_ARM_GOTPC: + /* relative reloc, always to _GLOBAL_OFFSET_TABLE_ + * (which is .got) similar to branch, + * but is full 32 bits relative */ + + assert(got); + *loc += got - dot; + break; + + case R_ARM_PC24: + case R_ARM_PLT32: + goto bb_use_plt; + + case R_ARM_GOTOFF: /* address relative to the got */ + assert(got); + *loc += v - got; + break; + +#elif defined(__i386__) + + case R_386_NONE: + break; + + case R_386_32: + *loc += v; + break; + + case R_386_PLT32: + case R_386_PC32: + *loc += v - dot; + break; + + case R_386_GLOB_DAT: + case R_386_JMP_SLOT: + *loc = v; + break; + + case R_386_RELATIVE: + *loc += f->baseaddr; + break; + + case R_386_GOTPC: + assert(got != 0); + *loc += got - dot; + break; + + case R_386_GOT32: + goto bb_use_got; + + case R_386_GOTOFF: + assert(got != 0); + *loc += v - got; + break; + +#elif defined(__mc68000__) + + case R_68K_NONE: + break; + + case R_68K_32: + *loc += v; + break; + + case R_68K_8: + if (v > 0xff) { + ret = obj_reloc_overflow; + } + *(char *)loc = v; + break; + + case R_68K_16: + if (v > 0xffff) { + ret = obj_reloc_overflow; + } + *(short *)loc = v; + break; + + case R_68K_PC8: + v -= dot; + if ((Elf32_Sword)v > 0x7f || + (Elf32_Sword)v < -(Elf32_Sword)0x80) { + ret = obj_reloc_overflow; + } + *(char *)loc = v; + break; + + case R_68K_PC16: + v -= dot; + if ((Elf32_Sword)v > 0x7fff || + (Elf32_Sword)v < -(Elf32_Sword)0x8000) { + ret = obj_reloc_overflow; + } + *(short *)loc = v; + break; + + case R_68K_PC32: + *(int *)loc = v - dot; + break; + + case R_68K_GLOB_DAT: + case R_68K_JMP_SLOT: + *loc = v; + break; + + case R_68K_RELATIVE: + *(int *)loc += f->baseaddr; + break; + + case R_68K_GOT32: + goto bb_use_got; + + case R_68K_GOTOFF: + assert(got != 0); + *loc += v - got; + break; + +#elif defined(__mips__) + + case R_MIPS_NONE: + break; + + case R_MIPS_32: + *loc += v; + break; + + case R_MIPS_26: + if (v % 4) + ret = obj_reloc_dangerous; + if ((v & 0xf0000000) != ((dot + 4) & 0xf0000000)) + ret = obj_reloc_overflow; + *loc = + (*loc & ~0x03ffffff) | ((*loc + (v >> 2)) & + 0x03ffffff); + break; + + case R_MIPS_HI16: + { + struct mips_hi16 *n; + + /* We cannot relocate this one now because we don't know the value + of the carry we need to add. Save the information, and let LO16 + do the actual relocation. */ + n = (struct mips_hi16 *) xmalloc(sizeof *n); + n->addr = loc; + n->value = v; + n->next = ifile->mips_hi16_list; + ifile->mips_hi16_list = n; + break; + } + + case R_MIPS_LO16: + { + unsigned long insnlo = *loc; + Elf32_Addr val, vallo; + + /* Sign extend the addend we extract from the lo insn. */ + vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000; + + if (ifile->mips_hi16_list != NULL) { + struct mips_hi16 *l; + + l = ifile->mips_hi16_list; + while (l != NULL) { + struct mips_hi16 *next; + unsigned long insn; + + /* The value for the HI16 had best be the same. */ + assert(v == l->value); + + /* Do the HI16 relocation. Note that we actually don't + need to know anything about the LO16 itself, except where + to find the low 16 bits of the addend needed by the LO16. */ + insn = *l->addr; + val = + ((insn & 0xffff) << 16) + + vallo; + val += v; + + /* Account for the sign extension that will happen in the + low bits. */ + val = + ((val >> 16) + + ((val & 0x8000) != + 0)) & 0xffff; + + insn = (insn & ~0xffff) | val; + *l->addr = insn; + + next = l->next; + free(l); + l = next; + } + + ifile->mips_hi16_list = NULL; + } + + /* Ok, we're done with the HI16 relocs. Now deal with the LO16. */ + val = v + vallo; + insnlo = (insnlo & ~0xffff) | (val & 0xffff); + *loc = insnlo; + break; + } + +#elif defined(__powerpc__) + + case R_PPC_ADDR16_HA: + *(unsigned short *)loc = (v + 0x8000) >> 16; + break; + + case R_PPC_ADDR16_HI: + *(unsigned short *)loc = v >> 16; + break; + + case R_PPC_ADDR16_LO: + *(unsigned short *)loc = v; + break; + + case R_PPC_REL24: + goto bb_use_plt; + + case R_PPC_REL32: + *loc = v - dot; + break; + + case R_PPC_ADDR32: + *loc = v; + break; + +#elif defined(__sh__) + + case R_SH_NONE: + break; + + case R_SH_DIR32: + *loc += v; + break; + + case R_SH_REL32: + *loc += v - dot; + break; + + case R_SH_PLT32: + *loc = v - dot; + break; + + case R_SH_GLOB_DAT: + case R_SH_JMP_SLOT: + *loc = v; + break; + + case R_SH_RELATIVE: + *loc = f->baseaddr + rel->r_addend; + break; + + case R_SH_GOTPC: + assert(got != 0); + *loc = got - dot + rel->r_addend; + break; + + case R_SH_GOT32: + goto bb_use_got; + + case R_SH_GOTOFF: + assert(got != 0); + *loc = v - got; + break; + +#endif + + default: + printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info)); + ret = obj_reloc_unhandled; + break; + +#if defined(BB_USE_PLT_ENTRIES) + + bb_use_plt: + + /* find the plt entry and initialize it if necessary */ + assert(isym != NULL); + +#if defined(BB_USE_PLT_LIST) + for (pe = isym->pltent; pe != NULL && pe->addend != rel->r_addend;) + pe = pe->next; + assert(pe != NULL); +#else + pe = &isym->pltent; +#endif + + if (! pe->inited) { + ip = (unsigned long *) (ifile->plt->contents + pe->offset); + + /* generate some machine code */ + +#if defined(__arm__) + ip[0] = 0xe51ff004; /* ldr pc,[pc,#-4] */ + ip[1] = v; /* sym@ */ +#endif +#if defined(__powerpc__) + ip[0] = 0x3d600000 + ((v + 0x8000) >> 16); /* lis r11,sym@ha */ + ip[1] = 0x396b0000 + (v & 0xffff); /* addi r11,r11,sym@l */ + ip[2] = 0x7d6903a6; /* mtctr r11 */ + ip[3] = 0x4e800420; /* bctr */ +#endif + pe->inited = 1; + } + + /* relative distance to target */ + v -= dot; + /* if the target is too far away.... */ + if ((int)v < -0x02000000 || (int)v >= 0x02000000) { + /* go via the plt */ + v = plt + pe->offset - dot; + } + if (v & 3) + ret = obj_reloc_dangerous; + + /* merge the offset into the instruction. */ +#if defined(__arm__) + /* Convert to words. */ + v >>= 2; + + *loc = (*loc & ~0x00ffffff) | ((v + *loc) & 0x00ffffff); +#endif +#if defined(__powerpc__) + *loc = (*loc & ~0x03fffffc) | (v & 0x03fffffc); +#endif + break; +#endif /* BB_USE_PLT_ENTRIES */ + +#if defined(BB_USE_GOT_ENTRIES) + bb_use_got: + + assert(isym != NULL); + /* needs an entry in the .got: set it, once */ + if (!isym->gotent.inited) { + isym->gotent.inited = 1; + *(ElfW(Addr) *) (ifile->got->contents + isym->gotent.offset) = v; + } + /* make the reloc with_respect_to_.got */ +#if defined(__sh__) + *loc += isym->gotent.offset + rel->r_addend; +#elif defined(__i386__) || defined(__arm__) || defined(__mc68000__) + *loc += isym->gotent.offset; +#endif + break; + +#endif /* BB_USE_GOT_ENTRIES */ + } + + return ret; +} + +#if defined(BB_USE_LIST) + +static int arch_list_add(ElfW(RelM) *rel, struct arch_list_entry **list, + int offset, int size) +{ + struct arch_list_entry *pe; + + for (pe = *list; pe != NULL; pe = pe->next) { + if (pe->addend == rel->r_addend) { + break; + } + } + + if (pe == NULL) { + pe = xmalloc(sizeof(struct arch_list_entry)); + pe->next = *list; + pe->addend = rel->r_addend; + pe->offset = offset; + pe->inited = 0; + *list = pe; + return size; + } + return 0; +} + +#endif + +#if defined(BB_USE_SINGLE) + +static int arch_single_init(ElfW(RelM) *rel, struct arch_single_entry *single, + int offset, int size) +{ + if (single->allocated == 0) { + single->allocated = 1; + single->offset = offset; + single->inited = 0; + return size; + } + return 0; +} + +#endif + +#if defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES) + +static struct obj_section *arch_xsect_init(struct obj_file *f, char *name, + int offset, int size) +{ + struct obj_section *myrelsec = obj_find_section(f, name); + + if (offset == 0) { + offset += size; + } + + if (myrelsec) { + obj_extend_section(myrelsec, offset); + } else { + myrelsec = obj_create_alloced_section(f, name, + size, offset); + assert(myrelsec); + } + + return myrelsec; +} + +#endif + +static void arch_create_got(struct obj_file *f) +{ +#if defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES) + struct arch_file *ifile = (struct arch_file *) f; + int i; +#if defined(BB_USE_GOT_ENTRIES) + int got_offset = 0, got_needed = 0, got_allocate; +#endif +#if defined(BB_USE_PLT_ENTRIES) + int plt_offset = 0, plt_needed = 0, plt_allocate; +#endif + struct obj_section *relsec, *symsec, *strsec; + ElfW(RelM) *rel, *relend; + ElfW(Sym) *symtab, *extsym; + const char *strtab, *name; + struct arch_symbol *intsym; + + for (i = 0; i < f->header.e_shnum; ++i) { + relsec = f->sections[i]; + + if (relsec->header.sh_type != SHT_RELM) + continue; + + symsec = f->sections[relsec->header.sh_link]; + strsec = f->sections[symsec->header.sh_link]; + + rel = (ElfW(RelM) *) relsec->contents; + relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM))); + symtab = (ElfW(Sym) *) symsec->contents; + strtab = (const char *) strsec->contents; + + for (; rel < relend; ++rel) { + extsym = &symtab[ELF32_R_SYM(rel->r_info)]; + +#if defined(BB_USE_GOT_ENTRIES) + got_allocate = 0; +#endif +#if defined(BB_USE_PLT_ENTRIES) + plt_allocate = 0; +#endif + + switch (ELF32_R_TYPE(rel->r_info)) { + +#if defined(__arm__) + + case R_ARM_PC24: + case R_ARM_PLT32: + plt_allocate = 1; + break; + + case R_ARM_GOTOFF: + case R_ARM_GOTPC: + got_needed = 1; + continue; + + case R_ARM_GOT32: + got_allocate = 1; + break; + +#elif defined(__i386__) + + case R_386_GOTPC: + case R_386_GOTOFF: + got_needed = 1; + continue; + + case R_386_GOT32: + got_allocate = 1; + break; + +#elif defined(__powerpc__) + + case R_PPC_REL24: + plt_allocate = 1; + break; + +#elif defined(__mc68000__) + + case R_68K_GOT32: + got_allocate = 1; + break; + + case R_68K_GOTOFF: + got_needed = 1; + continue; + +#elif defined(__sh__) + + case R_SH_GOT32: + got_allocate = 1; + break; + + case R_SH_GOTPC: + case R_SH_GOTOFF: + got_needed = 1; + continue; + +#endif + default: + continue; + } + + if (extsym->st_name != 0) { + name = strtab + extsym->st_name; + } else { + name = f->sections[extsym->st_shndx]->name; + } + intsym = (struct arch_symbol *) obj_find_symbol(f, name); +#if defined(BB_USE_GOT_ENTRIES) + if (got_allocate) { + got_offset += arch_single_init( + rel, &intsym->gotent, + got_offset, BB_GOT_ENTRY_SIZE); + + got_needed = 1; + } +#endif +#if defined(BB_USE_PLT_ENTRIES) + if (plt_allocate) { +#if defined(BB_USE_PLT_LIST) + plt_offset += arch_list_add( + rel, &intsym->pltent, + plt_offset, BB_PLT_ENTRY_SIZE); +#else + plt_offset += arch_single_init( + rel, &intsym->pltent, + plt_offset, BB_PLT_ENTRY_SIZE); +#endif + plt_needed = 1; + } +#endif + } + } + +#if defined(BB_USE_GOT_ENTRIES) + if (got_needed) { + ifile->got = arch_xsect_init(f, ".got", got_offset, + BB_GOT_ENTRY_SIZE); + } +#endif + +#if defined(BB_USE_PLT_ENTRIES) + if (plt_needed) { + ifile->plt = arch_xsect_init(f, ".plt", plt_offset, + BB_PLT_ENTRY_SIZE); + } +#endif + +#endif /* defined(BB_USE_GOT_ENTRIES) || defined(BB_USE_PLT_ENTRIES) */ +} + +#ifdef BB_FEATURE_NEW_MODULE_INTERFACE +static int arch_init_module(struct obj_file *f, struct new_module *mod) +{ + return 1; +} +#endif + + +/*======================================================================*/ + +/* Standard ELF hash function. */ +static inline unsigned long obj_elf_hash_n(const char *name, unsigned long n) +{ + unsigned long h = 0; + unsigned long g; + unsigned char ch; + + while (n > 0) { + ch = *name++; + h = (h << 4) + ch; + if ((g = (h & 0xf0000000)) != 0) { + h ^= g >> 24; + h &= ~g; + } + n--; + } + return h; +} + +static unsigned long obj_elf_hash(const char *name) +{ + return obj_elf_hash_n(name, strlen(name)); +} + +#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING +/* String comparison for non-co-versioned kernel and module. */ + +static int ncv_strcmp(const char *a, const char *b) +{ + size_t alen = strlen(a), blen = strlen(b); + + if (blen == alen + 10 && b[alen] == '_' && b[alen + 1] == 'R') + return strncmp(a, b, alen); + else if (alen == blen + 10 && a[blen] == '_' && a[blen + 1] == 'R') + return strncmp(a, b, blen); + else + return strcmp(a, b); +} + +/* String hashing for non-co-versioned kernel and module. Here + we are simply forced to drop the crc from the hash. */ + +static unsigned long ncv_symbol_hash(const char *str) +{ + size_t len = strlen(str); + if (len > 10 && str[len - 10] == '_' && str[len - 9] == 'R') + len -= 10; + return obj_elf_hash_n(str, len); +} + +static void +obj_set_symbol_compare(struct obj_file *f, + int (*cmp) (const char *, const char *), + unsigned long (*hash) (const char *)) +{ + if (cmp) + f->symbol_cmp = cmp; + if (hash) { + struct obj_symbol *tmptab[HASH_BUCKETS], *sym, *next; + int i; + + f->symbol_hash = hash; + + memcpy(tmptab, f->symtab, sizeof(tmptab)); + memset(f->symtab, 0, sizeof(f->symtab)); + + for (i = 0; i < HASH_BUCKETS; ++i) + for (sym = tmptab[i]; sym; sym = next) { + unsigned long h = hash(sym->name) % HASH_BUCKETS; + next = sym->next; + sym->next = f->symtab[h]; + f->symtab[h] = sym; + } + } +} + +#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ + +static struct obj_symbol * +obj_add_symbol(struct obj_file *f, const char *name, + unsigned long symidx, int info, + int secidx, ElfW(Addr) value, + unsigned long size) +{ + struct obj_symbol *sym; + unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; + int n_type = ELFW(ST_TYPE) (info); + int n_binding = ELFW(ST_BIND) (info); + + for (sym = f->symtab[hash]; sym; sym = sym->next) + if (f->symbol_cmp(sym->name, name) == 0) { + int o_secidx = sym->secidx; + int o_info = sym->info; + int o_type = ELFW(ST_TYPE) (o_info); + int o_binding = ELFW(ST_BIND) (o_info); + + /* A redefinition! Is it legal? */ + + if (secidx == SHN_UNDEF) + return sym; + else if (o_secidx == SHN_UNDEF) + goto found; + else if (n_binding == STB_GLOBAL && o_binding == STB_LOCAL) { + /* Cope with local and global symbols of the same name + in the same object file, as might have been created + by ld -r. The only reason locals are now seen at this + level at all is so that we can do semi-sensible things + with parameters. */ + + struct obj_symbol *nsym, **p; + + nsym = arch_new_symbol(); + nsym->next = sym->next; + nsym->ksymidx = -1; + + /* Excise the old (local) symbol from the hash chain. */ + for (p = &f->symtab[hash]; *p != sym; p = &(*p)->next) + continue; + *p = sym = nsym; + goto found; + } else if (n_binding == STB_LOCAL) { + /* Another symbol of the same name has already been defined. + Just add this to the local table. */ + sym = arch_new_symbol(); + sym->next = NULL; + sym->ksymidx = -1; + f->local_symtab[symidx] = sym; + goto found; + } else if (n_binding == STB_WEAK) + return sym; + else if (o_binding == STB_WEAK) + goto found; + /* Don't unify COMMON symbols with object types the programmer + doesn't expect. */ + else if (secidx == SHN_COMMON + && (o_type == STT_NOTYPE || o_type == STT_OBJECT)) + return sym; + else if (o_secidx == SHN_COMMON + && (n_type == STT_NOTYPE || n_type == STT_OBJECT)) + goto found; + else { + /* Don't report an error if the symbol is coming from + the kernel or some external module. */ + if (secidx <= SHN_HIRESERVE) + error_msg("%s multiply defined", name); + return sym; + } + } + + /* Completely new symbol. */ + sym = arch_new_symbol(); + sym->next = f->symtab[hash]; + f->symtab[hash] = sym; + sym->ksymidx = -1; + + if (ELFW(ST_BIND)(info) == STB_LOCAL && symidx != -1) { + if (symidx >= f->local_symtab_size) + error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld", + name, (long) symidx, (long) f->local_symtab_size); + else + f->local_symtab[symidx] = sym; + } + + found: + sym->name = name; + sym->value = value; + sym->size = size; + sym->secidx = secidx; + sym->info = info; + + return sym; +} + +static struct obj_symbol * +obj_find_symbol(struct obj_file *f, const char *name) +{ + struct obj_symbol *sym; + unsigned long hash = f->symbol_hash(name) % HASH_BUCKETS; + + for (sym = f->symtab[hash]; sym; sym = sym->next) + if (f->symbol_cmp(sym->name, name) == 0) + return sym; + + return NULL; +} + +static ElfW(Addr) + obj_symbol_final_value(struct obj_file * f, struct obj_symbol * sym) +{ + if (sym) { + if (sym->secidx >= SHN_LORESERVE) + return sym->value; + + return sym->value + f->sections[sym->secidx]->header.sh_addr; + } else { + /* As a special case, a NULL sym has value zero. */ + return 0; + } +} + +static struct obj_section *obj_find_section(struct obj_file *f, const char *name) +{ + int i, n = f->header.e_shnum; + + for (i = 0; i < n; ++i) + if (strcmp(f->sections[i]->name, name) == 0) + return f->sections[i]; + + return NULL; +} + +static int obj_load_order_prio(struct obj_section *a) +{ + unsigned long af, ac; + + af = a->header.sh_flags; + + ac = 0; + if (a->name[0] != '.' || strlen(a->name) != 10 || + strcmp(a->name + 5, ".init")) + ac |= 32; + if (af & SHF_ALLOC) + ac |= 16; + if (!(af & SHF_WRITE)) + ac |= 8; + if (af & SHF_EXECINSTR) + ac |= 4; + if (a->header.sh_type != SHT_NOBITS) + ac |= 2; + + return ac; +} + +static void +obj_insert_section_load_order(struct obj_file *f, struct obj_section *sec) +{ + struct obj_section **p; + int prio = obj_load_order_prio(sec); + for (p = f->load_order_search_start; *p; p = &(*p)->load_next) + if (obj_load_order_prio(*p) < prio) + break; + sec->load_next = *p; + *p = sec; +} + +static struct obj_section *obj_create_alloced_section(struct obj_file *f, + const char *name, + unsigned long align, + unsigned long size) +{ + int newidx = f->header.e_shnum++; + struct obj_section *sec; + + f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec)); + f->sections[newidx] = sec = arch_new_section(); + + memset(sec, 0, sizeof(*sec)); + sec->header.sh_type = SHT_PROGBITS; + sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; + sec->header.sh_size = size; + sec->header.sh_addralign = align; + sec->name = name; + sec->idx = newidx; + if (size) + sec->contents = xmalloc(size); + + obj_insert_section_load_order(f, sec); + + return sec; +} + +static struct obj_section *obj_create_alloced_section_first(struct obj_file *f, + const char *name, + unsigned long align, + unsigned long size) +{ + int newidx = f->header.e_shnum++; + struct obj_section *sec; + + f->sections = xrealloc(f->sections, (newidx + 1) * sizeof(sec)); + f->sections[newidx] = sec = arch_new_section(); + + memset(sec, 0, sizeof(*sec)); + sec->header.sh_type = SHT_PROGBITS; + sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; + sec->header.sh_size = size; + sec->header.sh_addralign = align; + sec->name = name; + sec->idx = newidx; + if (size) + sec->contents = xmalloc(size); + + sec->load_next = f->load_order; + f->load_order = sec; + if (f->load_order_search_start == &f->load_order) + f->load_order_search_start = &sec->load_next; + + return sec; +} + +static void *obj_extend_section(struct obj_section *sec, unsigned long more) +{ + unsigned long oldsize = sec->header.sh_size; + if (more) { + sec->contents = xrealloc(sec->contents, sec->header.sh_size += more); + } + return sec->contents + oldsize; +} + + +/* Conditionally add the symbols from the given symbol set to the + new module. */ + +static int +add_symbols_from( + struct obj_file *f, + int idx, struct new_module_symbol *syms, size_t nsyms) +{ + struct new_module_symbol *s; + size_t i; + int used = 0; + + for (i = 0, s = syms; i < nsyms; ++i, ++s) { + + /* Only add symbols that are already marked external. If we + override locals we may cause problems for argument initialization. + We will also create a false dependency on the module. */ + struct obj_symbol *sym; + + sym = obj_find_symbol(f, (char *) s->name); + if (sym && !ELFW(ST_BIND) (sym->info) == STB_LOCAL) { + sym = obj_add_symbol(f, (char *) s->name, -1, + ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), + idx, s->value, 0); + /* Did our symbol just get installed? If so, mark the + module as "used". */ + if (sym->secidx == idx) + used = 1; + } + } + + return used; +} + +static void add_kernel_symbols(struct obj_file *f) +{ + struct external_module *m; + int i, nused = 0; + + /* Add module symbols first. */ + + for (i = 0, m = ext_modules; i < n_ext_modules; ++i, ++m) + if (m->nsyms + && add_symbols_from(f, SHN_HIRESERVE + 2 + i, m->syms, + m->nsyms)) m->used = 1, ++nused; + + n_ext_modules_used = nused; + + /* And finally the symbols from the kernel proper. */ + + if (nksyms) + add_symbols_from(f, SHN_HIRESERVE + 1, ksyms, nksyms); +} + +static char *get_modinfo_value(struct obj_file *f, const char *key) +{ + struct obj_section *sec; + char *p, *v, *n, *ep; + size_t klen = strlen(key); + + sec = obj_find_section(f, ".modinfo"); + if (sec == NULL) + return NULL; + p = sec->contents; + ep = p + sec->header.sh_size; + while (p < ep) { + v = strchr(p, '='); + n = strchr(p, '\0'); + if (v) { + if (p + klen == v && strncmp(p, key, klen) == 0) + return v + 1; + } else { + if (p + klen == n && strcmp(p, key) == 0) + return n; + } + p = n + 1; + } + + return NULL; +} + + +/*======================================================================*/ +/* Functions relating to module loading in pre 2.1 kernels. */ + +static int +old_process_module_arguments(struct obj_file *f, int argc, char **argv) +{ + while (argc > 0) { + char *p, *q; + struct obj_symbol *sym; + int *loc; + + p = *argv; + if ((q = strchr(p, '=')) == NULL) { + argc--; + continue; + } + *q++ = '\0'; + + sym = obj_find_symbol(f, p); + + /* Also check that the parameter was not resolved from the kernel. */ + if (sym == NULL || sym->secidx > SHN_HIRESERVE) { + error_msg("symbol for parameter %s not found", p); + return 0; + } + + loc = (int *) (f->sections[sym->secidx]->contents + sym->value); + + /* Do C quoting if we begin with a ". */ + if (*q == '"') { + char *r, *str; + + str = alloca(strlen(q)); + for (r = str, q++; *q != '"'; ++q, ++r) { + if (*q == '\0') { + error_msg("improperly terminated string argument for %s", p); + return 0; + } else if (*q == '\\') + switch (*++q) { + case 'a': + *r = '\a'; + break; + case 'b': + *r = '\b'; + break; + case 'e': + *r = '\033'; + break; + case 'f': + *r = '\f'; + break; + case 'n': + *r = '\n'; + break; + case 'r': + *r = '\r'; + break; + case 't': + *r = '\t'; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + int c = *q - '0'; + if (q[1] >= '0' && q[1] <= '7') { + c = (c * 8) + *++q - '0'; + if (q[1] >= '0' && q[1] <= '7') + c = (c * 8) + *++q - '0'; + } + *r = c; + } + break; + + default: + *r = *q; + break; + } else + *r = *q; + } + *r = '\0'; + obj_string_patch(f, sym->secidx, sym->value, str); + } else if (*q >= '0' && *q <= '9') { + do + *loc++ = strtoul(q, &q, 0); + while (*q++ == ','); + } else { + char *contents = f->sections[sym->secidx]->contents; + char *myloc = contents + sym->value; + char *r; /* To search for commas */ + + /* Break the string with comas */ + while ((r = strchr(q, ',')) != (char *) NULL) { + *r++ = '\0'; + obj_string_patch(f, sym->secidx, myloc - contents, q); + myloc += sizeof(char *); + q = r; + } + + /* last part */ + obj_string_patch(f, sym->secidx, myloc - contents, q); + } + + argc--, argv++; + } + + return 1; +} + +#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING +static int old_is_module_checksummed(struct obj_file *f) +{ + return obj_find_symbol(f, "Using_Versions") != NULL; +} +/* Get the module's kernel version in the canonical integer form. */ + +static int +old_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) +{ + struct obj_symbol *sym; + char *p, *q; + int a, b, c; + + sym = obj_find_symbol(f, "kernel_version"); + if (sym == NULL) + return -1; + + p = f->sections[sym->secidx]->contents + sym->value; + safe_strncpy(str, p, STRVERSIONLEN); + + a = strtoul(p, &p, 10); + if (*p != '.') + return -1; + b = strtoul(p + 1, &p, 10); + if (*p != '.') + return -1; + c = strtoul(p + 1, &q, 10); + if (p + 1 == q) + return -1; + + return a << 16 | b << 8 | c; +} + +#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ + +#ifdef BB_FEATURE_OLD_MODULE_INTERFACE + +/* Fetch all the symbols and divvy them up as appropriate for the modules. */ + +static int old_get_kernel_symbols(const char *m_name) +{ + struct old_kernel_sym *ks, *k; + struct new_module_symbol *s; + struct external_module *mod; + int nks, nms, nmod, i; + + nks = get_kernel_syms(NULL); + if (nks <= 0) { + if (nks) + perror_msg("get_kernel_syms: %s", m_name); + else + error_msg("No kernel symbols"); + return 0; + } + + ks = k = xmalloc(nks * sizeof(*ks)); + + if (get_kernel_syms(ks) != nks) { + perror("inconsistency with get_kernel_syms -- is someone else " + "playing with modules?"); + free(ks); + return 0; + } + + /* Collect the module information. */ + + mod = NULL; + nmod = -1; + + while (k->name[0] == '#' && k->name[1]) { + struct old_kernel_sym *k2; + + /* Find out how many symbols this module has. */ + for (k2 = k + 1; k2->name[0] != '#'; ++k2) + continue; + nms = k2 - k - 1; + + mod = xrealloc(mod, (++nmod + 1) * sizeof(*mod)); + mod[nmod].name = k->name + 1; + mod[nmod].addr = k->value; + mod[nmod].used = 0; + mod[nmod].nsyms = nms; + mod[nmod].syms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL); + + for (i = 0, ++k; i < nms; ++i, ++s, ++k) { + s->name = (unsigned long) k->name; + s->value = k->value; + } + + k = k2; + } + + ext_modules = mod; + n_ext_modules = nmod + 1; + + /* Now collect the symbols for the kernel proper. */ + + if (k->name[0] == '#') + ++k; + + nksyms = nms = nks - (k - ks); + ksyms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL); + + for (i = 0; i < nms; ++i, ++s, ++k) { + s->name = (unsigned long) k->name; + s->value = k->value; + } + + return 1; +} + +/* Return the kernel symbol checksum version, or zero if not used. */ + +static int old_is_kernel_checksummed(void) +{ + /* Using_Versions is the first symbol. */ + if (nksyms > 0 + && strcmp((char *) ksyms[0].name, + "Using_Versions") == 0) return ksyms[0].value; + else + return 0; +} + + +static int old_create_mod_use_count(struct obj_file *f) +{ + struct obj_section *sec; + + sec = obj_create_alloced_section_first(f, ".moduse", sizeof(long), + sizeof(long)); + + obj_add_symbol(f, "mod_use_count_", -1, + ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0, + sizeof(long)); + + return 1; +} + +static int +old_init_module(const char *m_name, struct obj_file *f, + unsigned long m_size) +{ + char *image; + struct old_mod_routines routines; + struct old_symbol_table *symtab; + int ret; + + /* Create the symbol table */ + { + int nsyms = 0, strsize = 0, total; + + /* Size things first... */ + if (flag_export) { + int i; + for (i = 0; i < HASH_BUCKETS; ++i) { + struct obj_symbol *sym; + for (sym = f->symtab[i]; sym; sym = sym->next) + if (ELFW(ST_BIND) (sym->info) != STB_LOCAL + && sym->secidx <= SHN_HIRESERVE) + { + sym->ksymidx = nsyms++; + strsize += strlen(sym->name) + 1; + } + } + } + + total = (sizeof(struct old_symbol_table) + + nsyms * sizeof(struct old_module_symbol) + + n_ext_modules_used * sizeof(struct old_module_ref) + + strsize); + symtab = xmalloc(total); + symtab->size = total; + symtab->n_symbols = nsyms; + symtab->n_refs = n_ext_modules_used; + + if (flag_export && nsyms) { + struct old_module_symbol *ksym; + char *str; + int i; + + ksym = symtab->symbol; + str = ((char *) ksym + nsyms * sizeof(struct old_module_symbol) + + n_ext_modules_used * sizeof(struct old_module_ref)); + + for (i = 0; i < HASH_BUCKETS; ++i) { + struct obj_symbol *sym; + for (sym = f->symtab[i]; sym; sym = sym->next) + if (sym->ksymidx >= 0) { + ksym->addr = obj_symbol_final_value(f, sym); + ksym->name = + (unsigned long) str - (unsigned long) symtab; + + strcpy(str, sym->name); + str += strlen(sym->name) + 1; + ksym++; + } + } + } + + if (n_ext_modules_used) { + struct old_module_ref *ref; + int i; + + ref = (struct old_module_ref *) + ((char *) symtab->symbol + nsyms * sizeof(struct old_module_symbol)); + + for (i = 0; i < n_ext_modules; ++i) + if (ext_modules[i].used) + ref++->module = ext_modules[i].addr; + } + } + + /* Fill in routines. */ + + routines.init = + obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); + routines.cleanup = + obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module")); + + /* Whew! All of the initialization is complete. Collect the final + module image and give it to the kernel. */ + + image = xmalloc(m_size); + obj_create_image(f, image); + + /* image holds the complete relocated module, accounting correctly for + mod_use_count. However the old module kernel support assume that + it is receiving something which does not contain mod_use_count. */ + ret = old_sys_init_module(m_name, image + sizeof(long), + m_size | (flag_autoclean ? OLD_MOD_AUTOCLEAN + : 0), &routines, symtab); + if (ret) + perror_msg("init_module: %s", m_name); + + free(image); + free(symtab); + + return ret == 0; +} + +#else + +#define old_create_mod_use_count(x) TRUE +#define old_init_module(x, y, z) TRUE + +#endif /* BB_FEATURE_OLD_MODULE_INTERFACE */ + + + +/*======================================================================*/ +/* Functions relating to module loading after 2.1.18. */ + +static int +new_process_module_arguments(struct obj_file *f, int argc, char **argv) +{ + while (argc > 0) { + char *p, *q, *key; + struct obj_symbol *sym; + char *contents, *loc; + int min, max, n; + + p = *argv; + if ((q = strchr(p, '=')) == NULL) { + argc--; + continue; + } + + key = alloca(q - p + 6); + memcpy(key, "parm_", 5); + memcpy(key + 5, p, q - p); + key[q - p + 5] = 0; + + p = get_modinfo_value(f, key); + key += 5; + if (p == NULL) { + error_msg("invalid parameter %s", key); + return 0; + } + + sym = obj_find_symbol(f, key); + + /* Also check that the parameter was not resolved from the kernel. */ + if (sym == NULL || sym->secidx > SHN_HIRESERVE) { + error_msg("symbol for parameter %s not found", key); + return 0; + } + + if (isdigit(*p)) { + min = strtoul(p, &p, 10); + if (*p == '-') + max = strtoul(p + 1, &p, 10); + else + max = min; + } else + min = max = 1; + + contents = f->sections[sym->secidx]->contents; + loc = contents + sym->value; + n = (*++q != '\0'); + + while (1) { + if ((*p == 's') || (*p == 'c')) { + char *str; + + /* Do C quoting if we begin with a ", else slurp the lot. */ + if (*q == '"') { + char *r; + + str = alloca(strlen(q)); + for (r = str, q++; *q != '"'; ++q, ++r) { + if (*q == '\0') { + error_msg("improperly terminated string argument for %s", + key); + return 0; + } else if (*q == '\\') + switch (*++q) { + case 'a': + *r = '\a'; + break; + case 'b': + *r = '\b'; + break; + case 'e': + *r = '\033'; + break; + case 'f': + *r = '\f'; + break; + case 'n': + *r = '\n'; + break; + case 'r': + *r = '\r'; + break; + case 't': + *r = '\t'; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + int c = *q - '0'; + if (q[1] >= '0' && q[1] <= '7') { + c = (c * 8) + *++q - '0'; + if (q[1] >= '0' && q[1] <= '7') + c = (c * 8) + *++q - '0'; + } + *r = c; + } + break; + + default: + *r = *q; + break; + } else + *r = *q; + } + *r = '\0'; + ++q; + } else { + char *r; + + /* In this case, the string is not quoted. We will break + it using the coma (like for ints). If the user wants to + include comas in a string, he just has to quote it */ + + /* Search the next coma */ + r = strchr(q, ','); + + /* Found ? */ + if (r != (char *) NULL) { + /* Recopy the current field */ + str = alloca(r - q + 1); + memcpy(str, q, r - q); + + /* I don't know if it is usefull, as the previous case + doesn't null terminate the string ??? */ + str[r - q] = '\0'; + + /* Keep next fields */ + q = r; + } else { + /* last string */ + str = q; + q = ""; + } + } + + if (*p == 's') { + /* Normal string */ + obj_string_patch(f, sym->secidx, loc - contents, str); + loc += tgt_sizeof_char_p; + } else { + /* Array of chars (in fact, matrix !) */ + unsigned long charssize; /* size of each member */ + + /* Get the size of each member */ + /* Probably we should do that outside the loop ? */ + if (!isdigit(*(p + 1))) { + error_msg("parameter type 'c' for %s must be followed by" + " the maximum size", key); + return 0; + } + charssize = strtoul(p + 1, (char **) NULL, 10); + + /* Check length */ + if (strlen(str) >= charssize) { + error_msg("string too long for %s (max %ld)", key, + charssize - 1); + return 0; + } + + /* Copy to location */ + strcpy((char *) loc, str); + loc += charssize; + } + } else { + long v = strtoul(q, &q, 0); + switch (*p) { + case 'b': + *loc++ = v; + break; + case 'h': + *(short *) loc = v; + loc += tgt_sizeof_short; + break; + case 'i': + *(int *) loc = v; + loc += tgt_sizeof_int; + break; + case 'l': + *(long *) loc = v; + loc += tgt_sizeof_long; + break; + + default: + error_msg("unknown parameter type '%c' for %s", *p, key); + return 0; + } + } + + retry_end_of_value: + switch (*q) { + case '\0': + goto end_of_arg; + + case ' ': + case '\t': + case '\n': + case '\r': + ++q; + goto retry_end_of_value; + + case ',': + if (++n > max) { + error_msg("too many values for %s (max %d)", key, max); + return 0; + } + ++q; + break; + + default: + error_msg("invalid argument syntax for %s", key); + return 0; + } + } + + end_of_arg: + if (n < min) { + error_msg("too few values for %s (min %d)", key, min); + return 0; + } + + argc--, argv++; + } + + return 1; +} + +#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING +static int new_is_module_checksummed(struct obj_file *f) +{ + const char *p = get_modinfo_value(f, "using_checksums"); + if (p) + return atoi(p); + else + return 0; +} + +/* Get the module's kernel version in the canonical integer form. */ + +static int +new_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]) +{ + char *p, *q; + int a, b, c; + + p = get_modinfo_value(f, "kernel_version"); + if (p == NULL) + return -1; + safe_strncpy(str, p, STRVERSIONLEN); + + a = strtoul(p, &p, 10); + if (*p != '.') + return -1; + b = strtoul(p + 1, &p, 10); + if (*p != '.') + return -1; + c = strtoul(p + 1, &q, 10); + if (p + 1 == q) + return -1; + + return a << 16 | b << 8 | c; +} + +#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ + + +#ifdef BB_FEATURE_NEW_MODULE_INTERFACE + +/* Fetch the loaded modules, and all currently exported symbols. */ + +static int new_get_kernel_symbols(void) +{ + char *module_names, *mn; + struct external_module *modules, *m; + struct new_module_symbol *syms, *s; + size_t ret, bufsize, nmod, nsyms, i, j; + + /* Collect the loaded modules. */ + + module_names = xmalloc(bufsize = 256); + retry_modules_load: + if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) { + if (errno == ENOSPC && bufsize < ret) { + module_names = xrealloc(module_names, bufsize = ret); + goto retry_modules_load; + } + perror_msg("QM_MODULES"); + return 0; + } + + n_ext_modules = nmod = ret; + + /* Collect the modules' symbols. */ + + if (nmod){ + ext_modules = modules = xmalloc(nmod * sizeof(*modules)); + memset(modules, 0, nmod * sizeof(*modules)); + for (i = 0, mn = module_names, m = modules; + i < nmod; ++i, ++m, mn += strlen(mn) + 1) { + struct new_module_info info; + + if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) { + if (errno == ENOENT) { + /* The module was removed out from underneath us. */ + continue; + } + perror_msg("query_module: QM_INFO: %s", mn); + return 0; + } + + syms = xmalloc(bufsize = 1024); + retry_mod_sym_load: + if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) { + switch (errno) { + case ENOSPC: + syms = xrealloc(syms, bufsize = ret); + goto retry_mod_sym_load; + case ENOENT: + /* The module was removed out from underneath us. */ + continue; + default: + perror_msg("query_module: QM_SYMBOLS: %s", mn); + return 0; + } + } + nsyms = ret; + + m->name = mn; + m->addr = info.addr; + m->nsyms = nsyms; + m->syms = syms; + + for (j = 0, s = syms; j < nsyms; ++j, ++s) { + s->name += (unsigned long) syms; + } + } + } + + /* Collect the kernel's symbols. */ + + syms = xmalloc(bufsize = 16 * 1024); + retry_kern_sym_load: + if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) { + if (errno == ENOSPC && bufsize < ret) { + syms = xrealloc(syms, bufsize = ret); + goto retry_kern_sym_load; + } + perror_msg("kernel: QM_SYMBOLS"); + return 0; + } + nksyms = nsyms = ret; + ksyms = syms; + + for (j = 0, s = syms; j < nsyms; ++j, ++s) { + s->name += (unsigned long) syms; + } + return 1; +} + + +/* Return the kernel symbol checksum version, or zero if not used. */ + +static int new_is_kernel_checksummed(void) +{ + struct new_module_symbol *s; + size_t i; + + /* Using_Versions is not the first symbol, but it should be in there. */ + + for (i = 0, s = ksyms; i < nksyms; ++i, ++s) + if (strcmp((char *) s->name, "Using_Versions") == 0) + return s->value; + + return 0; +} + + +static int new_create_this_module(struct obj_file *f, const char *m_name) +{ + struct obj_section *sec; + + sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long, + sizeof(struct new_module)); + memset(sec->contents, 0, sizeof(struct new_module)); + + obj_add_symbol(f, "__this_module", -1, + ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0, + sizeof(struct new_module)); + + obj_string_patch(f, sec->idx, offsetof(struct new_module, name), + m_name); + + return 1; +} + + +static int new_create_module_ksymtab(struct obj_file *f) +{ + struct obj_section *sec; + int i; + + /* We must always add the module references. */ + + if (n_ext_modules_used) { + struct new_module_ref *dep; + struct obj_symbol *tm; + + sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p, + (sizeof(struct new_module_ref) + * n_ext_modules_used)); + if (!sec) + return 0; + + tm = obj_find_symbol(f, "__this_module"); + dep = (struct new_module_ref *) sec->contents; + for (i = 0; i < n_ext_modules; ++i) + if (ext_modules[i].used) { + dep->dep = ext_modules[i].addr; + obj_symbol_patch(f, sec->idx, + (char *) &dep->ref - sec->contents, tm); + dep->next_ref = 0; + ++dep; + } + } + + if (flag_export && !obj_find_section(f, "__ksymtab")) { + size_t nsyms; + int *loaded; + + sec = + obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, + 0); + + /* We don't want to export symbols residing in sections that + aren't loaded. There are a number of these created so that + we make sure certain module options don't appear twice. */ + + loaded = alloca(sizeof(int) * (i = f->header.e_shnum)); + while (--i >= 0) + loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0; + + for (nsyms = i = 0; i < HASH_BUCKETS; ++i) { + struct obj_symbol *sym; + for (sym = f->symtab[i]; sym; sym = sym->next) + if (ELFW(ST_BIND) (sym->info) != STB_LOCAL + && sym->secidx <= SHN_HIRESERVE + && (sym->secidx >= SHN_LORESERVE + || loaded[sym->secidx])) { + ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p; + + obj_symbol_patch(f, sec->idx, ofs, sym); + obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, + sym->name); + + nsyms++; + } + } + + obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p); + } + + return 1; +} + + +static int +new_init_module(const char *m_name, struct obj_file *f, + unsigned long m_size) +{ + struct new_module *module; + struct obj_section *sec; + void *image; + int ret; + tgt_long m_addr; + + sec = obj_find_section(f, ".this"); + if (!sec || !sec->contents) { + perror_msg_and_die("corrupt module %s?",m_name); + } + module = (struct new_module *) sec->contents; + m_addr = sec->header.sh_addr; + + module->size_of_struct = sizeof(*module); + module->size = m_size; + module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0; + + sec = obj_find_section(f, "__ksymtab"); + if (sec && sec->header.sh_size) { + module->syms = sec->header.sh_addr; + module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p); + } + + if (n_ext_modules_used) { + sec = obj_find_section(f, ".kmodtab"); + module->deps = sec->header.sh_addr; + module->ndeps = n_ext_modules_used; + } + + module->init = + obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); + module->cleanup = + obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module")); + + sec = obj_find_section(f, "__ex_table"); + if (sec) { + module->ex_table_start = sec->header.sh_addr; + module->ex_table_end = sec->header.sh_addr + sec->header.sh_size; + } + + sec = obj_find_section(f, ".text.init"); + if (sec) { + module->runsize = sec->header.sh_addr - m_addr; + } + sec = obj_find_section(f, ".data.init"); + if (sec) { + if (!module->runsize || + module->runsize > sec->header.sh_addr - m_addr) + module->runsize = sec->header.sh_addr - m_addr; + } + sec = obj_find_section(f, ARCHDATA_SEC_NAME); + if (sec && sec->header.sh_size) { + module->archdata_start = (void*)sec->header.sh_addr; + module->archdata_end = module->archdata_start + sec->header.sh_size; + } + sec = obj_find_section(f, KALLSYMS_SEC_NAME); + if (sec && sec->header.sh_size) { + module->kallsyms_start = (void*)sec->header.sh_addr; + module->kallsyms_end = module->kallsyms_start + sec->header.sh_size; + } + + if (!arch_init_module(f, module)) + return 0; + + /* Whew! All of the initialization is complete. Collect the final + module image and give it to the kernel. */ + + image = xmalloc(m_size); + obj_create_image(f, image); + + ret = new_sys_init_module(m_name, (struct new_module *) image); + if (ret) + perror_msg("init_module: %s", m_name); + + free(image); + + return ret == 0; +} + +#else + +#define new_init_module(x, y, z) TRUE +#define new_create_this_module(x, y) 0 +#define new_create_module_ksymtab(x) +#define query_module(v, w, x, y, z) -1 + +#endif /* BB_FEATURE_NEW_MODULE_INTERFACE */ + + +/*======================================================================*/ + +static int +obj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, + const char *string) +{ + struct obj_string_patch *p; + struct obj_section *strsec; + size_t len = strlen(string) + 1; + char *loc; + + p = xmalloc(sizeof(*p)); + p->next = f->string_patches; + p->reloc_secidx = secidx; + p->reloc_offset = offset; + f->string_patches = p; + + strsec = obj_find_section(f, ".kstrtab"); + if (strsec == NULL) { + strsec = obj_create_alloced_section(f, ".kstrtab", 1, len); + p->string_offset = 0; + loc = strsec->contents; + } else { + p->string_offset = strsec->header.sh_size; + loc = obj_extend_section(strsec, len); + } + memcpy(loc, string, len); + + return 1; +} + +#ifdef BB_FEATURE_NEW_MODULE_INTERFACE +static int +obj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, + struct obj_symbol *sym) +{ + struct obj_symbol_patch *p; + + p = xmalloc(sizeof(*p)); + p->next = f->symbol_patches; + p->reloc_secidx = secidx; + p->reloc_offset = offset; + p->sym = sym; + f->symbol_patches = p; + + return 1; +} +#endif + +static int obj_check_undefineds(struct obj_file *f) +{ + unsigned long i; + int ret = 1; + + for (i = 0; i < HASH_BUCKETS; ++i) { + struct obj_symbol *sym; + for (sym = f->symtab[i]; sym; sym = sym->next) + if (sym->secidx == SHN_UNDEF) { + if (ELFW(ST_BIND) (sym->info) == STB_WEAK) { + sym->secidx = SHN_ABS; + sym->value = 0; + } else { + if (!flag_quiet) { + error_msg("unresolved symbol %s", sym->name); + } + ret = 0; + } + } + } + + return ret; +} + +static void obj_allocate_commons(struct obj_file *f) +{ + struct common_entry { + struct common_entry *next; + struct obj_symbol *sym; + } *common_head = NULL; + + unsigned long i; + + for (i = 0; i < HASH_BUCKETS; ++i) { + struct obj_symbol *sym; + for (sym = f->symtab[i]; sym; sym = sym->next) + if (sym->secidx == SHN_COMMON) { + /* Collect all COMMON symbols and sort them by size so as to + minimize space wasted by alignment requirements. */ + { + struct common_entry **p, *n; + for (p = &common_head; *p; p = &(*p)->next) + if (sym->size <= (*p)->sym->size) + break; + + n = alloca(sizeof(*n)); + n->next = *p; + n->sym = sym; + *p = n; + } + } + } + + for (i = 1; i < f->local_symtab_size; ++i) { + struct obj_symbol *sym = f->local_symtab[i]; + if (sym && sym->secidx == SHN_COMMON) { + struct common_entry **p, *n; + for (p = &common_head; *p; p = &(*p)->next) + if (sym == (*p)->sym) + break; + else if (sym->size < (*p)->sym->size) { + n = alloca(sizeof(*n)); + n->next = *p; + n->sym = sym; + *p = n; + break; + } + } + } + + if (common_head) { + /* Find the bss section. */ + for (i = 0; i < f->header.e_shnum; ++i) + if (f->sections[i]->header.sh_type == SHT_NOBITS) + break; + + /* If for some reason there hadn't been one, create one. */ + if (i == f->header.e_shnum) { + struct obj_section *sec; + + f->sections = xrealloc(f->sections, (i + 1) * sizeof(sec)); + f->sections[i] = sec = arch_new_section(); + f->header.e_shnum = i + 1; + + memset(sec, 0, sizeof(*sec)); + sec->header.sh_type = SHT_PROGBITS; + sec->header.sh_flags = SHF_WRITE | SHF_ALLOC; + sec->name = ".bss"; + sec->idx = i; + } + + /* Allocate the COMMONS. */ + { + ElfW(Addr) bss_size = f->sections[i]->header.sh_size; + ElfW(Addr) max_align = f->sections[i]->header.sh_addralign; + struct common_entry *c; + + for (c = common_head; c; c = c->next) { + ElfW(Addr) align = c->sym->value; + + if (align > max_align) + max_align = align; + if (bss_size & (align - 1)) + bss_size = (bss_size | (align - 1)) + 1; + + c->sym->secidx = i; + c->sym->value = bss_size; + + bss_size += c->sym->size; + } + + f->sections[i]->header.sh_size = bss_size; + f->sections[i]->header.sh_addralign = max_align; + } + } + + /* For the sake of patch relocation and parameter initialization, + allocate zeroed data for NOBITS sections now. Note that after + this we cannot assume NOBITS are really empty. */ + for (i = 0; i < f->header.e_shnum; ++i) { + struct obj_section *s = f->sections[i]; + if (s->header.sh_type == SHT_NOBITS) { + if (s->header.sh_size != 0) + s->contents = memset(xmalloc(s->header.sh_size), + 0, s->header.sh_size); + else + s->contents = NULL; + + s->header.sh_type = SHT_PROGBITS; + } + } +} + +static unsigned long obj_load_size(struct obj_file *f) +{ + unsigned long dot = 0; + struct obj_section *sec; + + /* Finalize the positions of the sections relative to one another. */ + + for (sec = f->load_order; sec; sec = sec->load_next) { + ElfW(Addr) align; + + align = sec->header.sh_addralign; + if (align && (dot & (align - 1))) + dot = (dot | (align - 1)) + 1; + + sec->header.sh_addr = dot; + dot += sec->header.sh_size; + } + + return dot; +} + +static int obj_relocate(struct obj_file *f, ElfW(Addr) base) +{ + int i, n = f->header.e_shnum; + int ret = 1; + + /* Finalize the addresses of the sections. */ + + f->baseaddr = base; + for (i = 0; i < n; ++i) + f->sections[i]->header.sh_addr += base; + + /* And iterate over all of the relocations. */ + + for (i = 0; i < n; ++i) { + struct obj_section *relsec, *symsec, *targsec, *strsec; + ElfW(RelM) * rel, *relend; + ElfW(Sym) * symtab; + const char *strtab; + + relsec = f->sections[i]; + if (relsec->header.sh_type != SHT_RELM) + continue; + + symsec = f->sections[relsec->header.sh_link]; + targsec = f->sections[relsec->header.sh_info]; + strsec = f->sections[symsec->header.sh_link]; + + rel = (ElfW(RelM) *) relsec->contents; + relend = rel + (relsec->header.sh_size / sizeof(ElfW(RelM))); + symtab = (ElfW(Sym) *) symsec->contents; + strtab = (const char *) strsec->contents; + + for (; rel < relend; ++rel) { + ElfW(Addr) value = 0; + struct obj_symbol *intsym = NULL; + unsigned long symndx; + ElfW(Sym) * extsym = 0; + const char *errmsg; + + /* Attempt to find a value to use for this relocation. */ + + symndx = ELFW(R_SYM) (rel->r_info); + if (symndx) { + /* Note we've already checked for undefined symbols. */ + + extsym = &symtab[symndx]; + if (ELFW(ST_BIND) (extsym->st_info) == STB_LOCAL) { + /* Local symbols we look up in the local table to be sure + we get the one that is really intended. */ + intsym = f->local_symtab[symndx]; + } else { + /* Others we look up in the hash table. */ + const char *name; + if (extsym->st_name) + name = strtab + extsym->st_name; + else + name = f->sections[extsym->st_shndx]->name; + intsym = obj_find_symbol(f, name); + } + + value = obj_symbol_final_value(f, intsym); + intsym->referenced = 1; + } +#if SHT_RELM == SHT_RELA +#if defined(__alpha__) && defined(AXP_BROKEN_GAS) + /* Work around a nasty GAS bug, that is fixed as of 2.7.0.9. */ + if (!extsym || !extsym->st_name || + ELFW(ST_BIND) (extsym->st_info) != STB_LOCAL) +#endif + value += rel->r_addend; +#endif + + /* Do it! */ + switch (arch_apply_relocation + (f, targsec, symsec, intsym, rel, value)) { + case obj_reloc_ok: + break; + + case obj_reloc_overflow: + errmsg = "Relocation overflow"; + goto bad_reloc; + case obj_reloc_dangerous: + errmsg = "Dangerous relocation"; + goto bad_reloc; + case obj_reloc_unhandled: + errmsg = "Unhandled relocation"; + bad_reloc: + if (extsym) { + error_msg("%s of type %ld for %s", errmsg, + (long) ELFW(R_TYPE) (rel->r_info), + strtab + extsym->st_name); + } else { + error_msg("%s of type %ld", errmsg, + (long) ELFW(R_TYPE) (rel->r_info)); + } + ret = 0; + break; + } + } + } + + /* Finally, take care of the patches. */ + + if (f->string_patches) { + struct obj_string_patch *p; + struct obj_section *strsec; + ElfW(Addr) strsec_base; + strsec = obj_find_section(f, ".kstrtab"); + strsec_base = strsec->header.sh_addr; + + for (p = f->string_patches; p; p = p->next) { + struct obj_section *targsec = f->sections[p->reloc_secidx]; + *(ElfW(Addr) *) (targsec->contents + p->reloc_offset) + = strsec_base + p->string_offset; + } + } + + if (f->symbol_patches) { + struct obj_symbol_patch *p; + + for (p = f->symbol_patches; p; p = p->next) { + struct obj_section *targsec = f->sections[p->reloc_secidx]; + *(ElfW(Addr) *) (targsec->contents + p->reloc_offset) + = obj_symbol_final_value(f, p->sym); + } + } + + return ret; +} + +static int obj_create_image(struct obj_file *f, char *image) +{ + struct obj_section *sec; + ElfW(Addr) base = f->baseaddr; + + for (sec = f->load_order; sec; sec = sec->load_next) { + char *secimg; + + if (sec->contents == 0 || sec->header.sh_size == 0) + continue; + + secimg = image + (sec->header.sh_addr - base); + + /* Note that we allocated data for NOBITS sections earlier. */ + memcpy(secimg, sec->contents, sec->header.sh_size); + } + + return 1; +} + +/*======================================================================*/ + +static struct obj_file *obj_load(FILE * fp, int loadprogbits) +{ + struct obj_file *f; + ElfW(Shdr) * section_headers; + int shnum, i; + char *shstrtab; + + /* Read the file header. */ + + f = arch_new_file(); + memset(f, 0, sizeof(*f)); + f->symbol_cmp = strcmp; + f->symbol_hash = obj_elf_hash; + f->load_order_search_start = &f->load_order; + + fseek(fp, 0, SEEK_SET); + if (fread(&f->header, sizeof(f->header), 1, fp) != 1) { + perror_msg("error reading ELF header"); + return NULL; + } + + if (f->header.e_ident[EI_MAG0] != ELFMAG0 + || f->header.e_ident[EI_MAG1] != ELFMAG1 + || f->header.e_ident[EI_MAG2] != ELFMAG2 + || f->header.e_ident[EI_MAG3] != ELFMAG3) { + error_msg("not an ELF file"); + return NULL; + } + if (f->header.e_ident[EI_CLASS] != ELFCLASSM + || f->header.e_ident[EI_DATA] != ELFDATAM + || f->header.e_ident[EI_VERSION] != EV_CURRENT + || !MATCH_MACHINE(f->header.e_machine)) { + error_msg("ELF file not for this architecture"); + return NULL; + } + if (f->header.e_type != ET_REL) { + error_msg("ELF file not a relocatable object"); + return NULL; + } + + /* Read the section headers. */ + + if (f->header.e_shentsize != sizeof(ElfW(Shdr))) { + error_msg("section header size mismatch: %lu != %lu", + (unsigned long) f->header.e_shentsize, + (unsigned long) sizeof(ElfW(Shdr))); + return NULL; + } + + shnum = f->header.e_shnum; + f->sections = xmalloc(sizeof(struct obj_section *) * shnum); + memset(f->sections, 0, sizeof(struct obj_section *) * shnum); + + section_headers = alloca(sizeof(ElfW(Shdr)) * shnum); + fseek(fp, f->header.e_shoff, SEEK_SET); + if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) { + perror_msg("error reading ELF section headers"); + return NULL; + } + + /* Read the section data. */ + + for (i = 0; i < shnum; ++i) { + struct obj_section *sec; + + f->sections[i] = sec = arch_new_section(); + memset(sec, 0, sizeof(*sec)); + + sec->header = section_headers[i]; + sec->idx = i; + + if(sec->header.sh_size) switch (sec->header.sh_type) { + case SHT_NULL: + case SHT_NOTE: + case SHT_NOBITS: + /* ignore */ + break; + + case SHT_PROGBITS: +#if LOADBITS + if (!loadprogbits) { + sec->contents = NULL; + break; + } +#endif + case SHT_SYMTAB: + case SHT_STRTAB: + case SHT_RELM: + if (sec->header.sh_size > 0) { + sec->contents = xmalloc(sec->header.sh_size); + fseek(fp, sec->header.sh_offset, SEEK_SET); + if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) { + perror_msg("error reading ELF section data"); + return NULL; + } + } else { + sec->contents = NULL; + } + break; + +#if SHT_RELM == SHT_REL + case SHT_RELA: + error_msg("RELA relocations not supported on this architecture"); + return NULL; +#else + case SHT_REL: + error_msg("REL relocations not supported on this architecture"); + return NULL; +#endif + + default: + if (sec->header.sh_type >= SHT_LOPROC) { + /* Assume processor specific section types are debug + info and can safely be ignored. If this is ever not + the case (Hello MIPS?), don't put ifdefs here but + create an arch_load_proc_section(). */ + break; + } + + error_msg("can't handle sections of type %ld", + (long) sec->header.sh_type); + return NULL; + } + } + + /* Do what sort of interpretation as needed by each section. */ + + shstrtab = f->sections[f->header.e_shstrndx]->contents; + + for (i = 0; i < shnum; ++i) { + struct obj_section *sec = f->sections[i]; + sec->name = shstrtab + sec->header.sh_name; + } + + for (i = 0; i < shnum; ++i) { + struct obj_section *sec = f->sections[i]; + + /* .modinfo should be contents only but gcc has no attribute for that. + * The kernel may have marked .modinfo as ALLOC, ignore this bit. + */ + if (strcmp(sec->name, ".modinfo") == 0) + sec->header.sh_flags &= ~SHF_ALLOC; + + if (sec->header.sh_flags & SHF_ALLOC) + obj_insert_section_load_order(f, sec); + + switch (sec->header.sh_type) { + case SHT_SYMTAB: + { + unsigned long nsym, j; + char *strtab; + ElfW(Sym) * sym; + + if (sec->header.sh_entsize != sizeof(ElfW(Sym))) { + error_msg("symbol size mismatch: %lu != %lu", + (unsigned long) sec->header.sh_entsize, + (unsigned long) sizeof(ElfW(Sym))); + return NULL; + } + + nsym = sec->header.sh_size / sizeof(ElfW(Sym)); + strtab = f->sections[sec->header.sh_link]->contents; + sym = (ElfW(Sym) *) sec->contents; + + /* Allocate space for a table of local symbols. */ + j = f->local_symtab_size = sec->header.sh_info; + f->local_symtab = xcalloc(j, sizeof(struct obj_symbol *)); + + /* Insert all symbols into the hash table. */ + for (j = 1, ++sym; j < nsym; ++j, ++sym) { + const char *name; + if (sym->st_name) + name = strtab + sym->st_name; + else + name = f->sections[sym->st_shndx]->name; + + obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx, + sym->st_value, sym->st_size); + } + } + break; + + case SHT_RELM: + if (sec->header.sh_entsize != sizeof(ElfW(RelM))) { + error_msg("relocation entry size mismatch: %lu != %lu", + (unsigned long) sec->header.sh_entsize, + (unsigned long) sizeof(ElfW(RelM))); + return NULL; + } + break; + /* XXX Relocation code from modutils-2.3.19 is not here. + * Why? That's about 20 lines of code from obj/obj_load.c, + * which gets done in a second pass through the sections. + * This BusyBox insmod does similar work in obj_relocate(). */ + } + } + + return f; +} + +#ifdef BB_FEATURE_INSMOD_LOADINKMEM +/* + * load the unloaded sections directly into the memory allocated by + * kernel for the module + */ + +static int obj_load_progbits(FILE * fp, struct obj_file* f, char* imagebase) +{ + ElfW(Addr) base = f->baseaddr; + struct obj_section* sec; + + for (sec = f->load_order; sec; sec = sec->load_next) { + + /* section already loaded? */ + if (sec->contents != NULL) + continue; + + if (sec->header.sh_size == 0) + continue; + + sec->contents = imagebase + (sec->header.sh_addr - base); + fseek(fp, sec->header.sh_offset, SEEK_SET); + if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) { + error_msg("error reading ELF section data: %s\n", strerror(errno)); + return 0; + } + + } + return 1; +} +#endif + +static void hide_special_symbols(struct obj_file *f) +{ + static const char *const specials[] = { + "cleanup_module", + "init_module", + "kernel_version", + NULL + }; + + struct obj_symbol *sym; + const char *const *p; + + for (p = specials; *p; ++p) + if ((sym = obj_find_symbol(f, *p)) != NULL) + sym->info = + ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info)); +} + +static int obj_gpl_license(struct obj_file *f, const char **license) +{ + struct obj_section *sec; + /* This list must match *exactly* the list of allowable licenses in + * linux/include/linux/module.h. Checking for leading "GPL" will not + * work, somebody will use "GPL sucks, this is proprietary". + */ + static const char *gpl_licenses[] = { + "GPL", + "GPL v2", + "GPL and additional rights", + "Dual BSD/GPL", + "Dual MPL/GPL", + }; + + if ((sec = obj_find_section(f, ".modinfo"))) { + const char *value, *ptr, *endptr; + ptr = sec->contents; + endptr = ptr + sec->header.sh_size; + while (ptr < endptr) { + if ((value = strchr(ptr, '=')) && strncmp(ptr, "license", value-ptr) == 0) { + int i; + if (license) + *license = value+1; + for (i = 0; i < sizeof(gpl_licenses)/sizeof(gpl_licenses[0]); ++i) { + if (strcmp(value+1, gpl_licenses[i]) == 0) + return(0); + } + return(2); + } + if (strchr(ptr, '\0')) + ptr = strchr(ptr, '\0') + 1; + else + ptr = endptr; + } + } + return(1); +} + +#define TAINT_FILENAME "/proc/sys/kernel/tainted" +#define TAINT_PROPRIETORY_MODULE (1<<0) +#define TAINT_FORCED_MODULE (1<<1) +#define TAINT_UNSAFE_SMP (1<<2) +#define TAINT_URL "http://www.tux.org/lkml/#export-tainted" + +static void set_tainted(struct obj_file *f, int fd, char *m_name, + int kernel_has_tainted, int taint, const char *text1, const char *text2) +{ + char buf[80]; + int oldval; + static int first = 1; + if (fd < 0 && !kernel_has_tainted) + return; /* New modutils on old kernel */ + printf("Warning: loading %s will taint the kernel: %s%s\n", + m_name, text1, text2); + if (first) { + printf(" See %s for information about tainted modules\n", TAINT_URL); + first = 0; + } + if (fd >= 0) { + read(fd, buf, sizeof(buf)-1); + buf[sizeof(buf)-1] = '\0'; + oldval = strtoul(buf, NULL, 10); + sprintf(buf, "%d\n", oldval | taint); + write(fd, buf, strlen(buf)); + } +} + +/* Check if loading this module will taint the kernel. */ +static void check_tainted_module(struct obj_file *f, char *m_name) +{ + static const char tainted_file[] = TAINT_FILENAME; + int fd, kernel_has_tainted; + const char *ptr; + + kernel_has_tainted = 1; + if ((fd = open(tainted_file, O_RDWR)) < 0) { + if (errno == ENOENT) + kernel_has_tainted = 0; + else if (errno == EACCES) + kernel_has_tainted = 1; + else { + perror(tainted_file); + kernel_has_tainted = 0; + } + } + + switch (obj_gpl_license(f, &ptr)) { + case 0: + break; + case 1: + set_tainted(f, fd, m_name, kernel_has_tainted, TAINT_PROPRIETORY_MODULE, "no license", ""); + break; + case 2: + /* The module has a non-GPL license so we pretend that the + * kernel always has a taint flag to get a warning even on + * kernels without the proc flag. + */ + set_tainted(f, fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "non-GPL license - ", ptr); + break; + default: + set_tainted(f, fd, m_name, 1, TAINT_PROPRIETORY_MODULE, "Unexpected return from obj_gpl_license", ""); + break; + } + + if (flag_force_load) + set_tainted(f, fd, m_name, 1, TAINT_FORCED_MODULE, "forced load", ""); + + if (fd >= 0) + close(fd); +} + +extern int insmod_main( int argc, char **argv) +{ + int opt; + int k_crcs; + int k_new_syscalls; + int len; + char *tmp, *tmp1; + unsigned long m_size; + ElfW(Addr) m_addr; + FILE *fp; + struct obj_file *f; + struct stat st; + char m_name[FILENAME_MAX] = "\0"; + int exit_status = EXIT_FAILURE; + int m_has_modinfo; +#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING + struct utsname uts_info; + char m_strversion[STRVERSIONLEN]; + int m_version; + int m_crcs; +#endif + + /* Parse any options */ + while ((opt = getopt(argc, argv, "fkqsvxLo:")) > 0) { + switch (opt) { + case 'f': /* force loading */ + flag_force_load = 1; + break; + case 'k': /* module loaded by kerneld, auto-cleanable */ + flag_autoclean = 1; + break; + case 's': /* log to syslog */ + /* log to syslog -- not supported */ + /* but kernel needs this for request_module(), */ + /* as this calls: modprobe -k -s -- */ + /* so silently ignore this flag */ + break; + case 'v': /* verbose output */ + flag_verbose = 1; + break; + case 'q': /* silent */ + flag_quiet = 1; + break; + case 'x': /* do not export externs */ + flag_export = 0; + break; + case 'o': /* name the output module */ + safe_strncpy(m_name, optarg, sizeof(m_name)); + break; + case 'L': /* Stub warning */ + /* This is needed for compatibility with modprobe. + * In theory, this does locking, but we don't do + * that. So be careful and plan your life around not + * loading the same module 50 times concurrently. */ + break; + default: + show_usage(); + } + } + + if (argv[optind] == NULL) { + show_usage(); + } + + /* Grab the module name */ + tmp1 = xstrdup(argv[optind]); + tmp = basename(tmp1); + len = strlen(tmp); + + if (len > 2 && tmp[len - 2] == '.' && tmp[len - 1] == 'o') { + len-=2; + tmp[len] = '\0'; + } + /* Make sure there is space for the terminal NULL */ + len += 1; + + if (len >= sizeof(m_fullName)) { + len = sizeof(m_fullName); + } + safe_strncpy(m_fullName, tmp, len); + if (tmp1) + free(tmp1); + if (*m_name == '\0') { + safe_strncpy(m_name, m_fullName, sizeof(m_name)); + } + len = strlen(m_fullName); + if (len > (sizeof(m_fullName)-3)) + error_msg_and_die("%s: no module by that name found", m_fullName); + strcat(m_fullName, ".o"); + + /* Get a filedesc for the module. Check we we have a complete path */ + if (stat(argv[optind], &st) < 0 || !S_ISREG(st.st_mode) || + (fp = fopen(argv[optind], "r")) == NULL) { + struct utsname myuname; + + /* Hmm. Could not open it. First search under /lib/modules/`uname -r`, + * but do not error out yet if we fail to find it... */ + if (uname(&myuname) == 0) { + char module_dir[FILENAME_MAX]; + char real_module_dir[FILENAME_MAX]; + snprintf (module_dir, sizeof(module_dir), "%s/%s", + _PATH_MODULES, myuname.release); + /* Jump through hoops in case /lib/modules/`uname -r` + * is a symlink. We do not want recursive_action to + * follow symlinks, but we do want to follow the + * /lib/modules/`uname -r` dir, So resolve it ourselves + * if it is a link... */ + if (realpath (module_dir, real_module_dir) == NULL) + strcpy(real_module_dir, module_dir); + recursive_action(real_module_dir, TRUE, FALSE, FALSE, + check_module_name_match, 0, m_fullName); + } + + /* Check if we have found anything yet */ + if (m_filename[0] == '\0' || ((fp = fopen(m_filename, "r")) == NULL)) + { + char module_dir[FILENAME_MAX]; + if (realpath (_PATH_MODULES, module_dir) == NULL) + strcpy(module_dir, _PATH_MODULES); + /* No module found under /lib/modules/`uname -r`, this + * time cast the net a bit wider. Search /lib/modules/ */ + if (recursive_action(module_dir, TRUE, FALSE, FALSE, + check_module_name_match, 0, m_fullName) == FALSE) + { + if (m_filename[0] == '\0' + || ((fp = fopen(m_filename, "r")) == NULL)) + { + error_msg("%s: no module by that name found", m_fullName); + return EXIT_FAILURE; + } + } else + error_msg_and_die("%s: no module by that name found", m_fullName); + } + } else + safe_strncpy(m_filename, argv[optind], sizeof(m_filename)); + + printf("Using %s\n", m_filename); + + if ((f = obj_load(fp, LOADBITS)) == NULL) + perror_msg_and_die("Could not load the module"); + + if (get_modinfo_value(f, "kernel_version") == NULL) + m_has_modinfo = 0; + else + m_has_modinfo = 1; + +#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING + /* Version correspondence? */ + if (!flag_quiet) { + if (uname(&uts_info) < 0) + uts_info.release[0] = '\0'; + if (m_has_modinfo) { + m_version = new_get_module_version(f, m_strversion); + } else { + m_version = old_get_module_version(f, m_strversion); + if (m_version == -1) { + error_msg("couldn't find the kernel version the module was " + "compiled for"); + goto out; + } + } + + if (strncmp(uts_info.release, m_strversion, STRVERSIONLEN) != 0) { + if (flag_force_load) { + error_msg("Warning: kernel-module version mismatch\n" + "\t%s was compiled for kernel version %s\n" + "\twhile this kernel is version %s", + m_filename, m_strversion, uts_info.release); + } else { + error_msg("kernel-module version mismatch\n" + "\t%s was compiled for kernel version %s\n" + "\twhile this kernel is version %s.", + m_filename, m_strversion, uts_info.release); + goto out; + } + } + } + k_crcs = 0; +#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ + + k_new_syscalls = !query_module(NULL, 0, NULL, 0, NULL); + + if (k_new_syscalls) { +#ifdef BB_FEATURE_NEW_MODULE_INTERFACE + if (!new_get_kernel_symbols()) + goto out; + k_crcs = new_is_kernel_checksummed(); +#else + error_msg("Not configured to support new kernels"); + goto out; +#endif + } else { +#ifdef BB_FEATURE_OLD_MODULE_INTERFACE + if (!old_get_kernel_symbols(m_name)) + goto out; + k_crcs = old_is_kernel_checksummed(); +#else + error_msg("Not configured to support old kernels"); + goto out; +#endif + } + +#ifdef BB_FEATURE_INSMOD_VERSION_CHECKING + if (m_has_modinfo) + m_crcs = new_is_module_checksummed(f); + else + m_crcs = old_is_module_checksummed(f); + + if (m_crcs != k_crcs) + obj_set_symbol_compare(f, ncv_strcmp, ncv_symbol_hash); +#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */ + + /* Let the module know about the kernel symbols. */ + add_kernel_symbols(f); + + /* Allocate common symbols, symbol tables, and string tables. */ + + if (k_new_syscalls + ? !new_create_this_module(f, m_name) + : !old_create_mod_use_count(f)) + { + goto out; + } + + if (!obj_check_undefineds(f)) { + goto out; + } + obj_allocate_commons(f); + check_tainted_module(f, m_name); + + /* done with the module name, on to the optional var=value arguments */ + ++optind; + + if (optind < argc) { + if (m_has_modinfo + ? !new_process_module_arguments(f, argc - optind, argv + optind) + : !old_process_module_arguments(f, argc - optind, argv + optind)) + { + goto out; + } + } + + arch_create_got(f); + hide_special_symbols(f); + + if (k_new_syscalls) + new_create_module_ksymtab(f); + + /* Find current size of the module */ + m_size = obj_load_size(f); + + + m_addr = create_module(m_name, m_size); + if (m_addr==-1) switch (errno) { + case EEXIST: + error_msg("A module named %s already exists", m_name); + goto out; + case ENOMEM: + error_msg("Can't allocate kernel memory for module; needed %lu bytes", + m_size); + goto out; + default: + perror_msg("create_module: %s", m_name); + goto out; + } + +#if !LOADBITS + /* + * the PROGBITS section was not loaded by the obj_load + * now we can load them directly into the kernel memory + */ + if (!obj_load_progbits(fp, f, (char*)m_addr)) { + delete_module(m_name); + goto out; + } +#endif + + if (!obj_relocate(f, m_addr)) { + delete_module(m_name); + goto out; + } + + if (k_new_syscalls + ? !new_init_module(m_name, f, m_size) + : !old_init_module(m_name, f, m_size)) + { + delete_module(m_name); + goto out; + } + + exit_status = EXIT_SUCCESS; + +out: + fclose(fp); + return(exit_status); +} diff --git a/install.sh b/install.sh new file mode 100755 index 000000000..d163a2ef8 --- /dev/null +++ b/install.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +export LC_ALL=POSIX +export LC_CTYPE=POSIX + +prefix=$1 +if [ "$prefix" = "" ]; then + echo "No installation directory, aborting." + exit 1; +fi +if [ "$2" = "--hardlinks" ]; then + linkopts="-f" +else + linkopts="-fs" +fi +h=`sort busybox.links | uniq` + + +rm -f $prefix/bin/busybox || exit 1 +mkdir -p $prefix/bin || exit 1 +install -m 755 busybox $prefix/bin/busybox || exit 1 + +for i in $h ; do + appdir=`dirname $i` + mkdir -p $prefix/$appdir || exit 1 + if [ "$2" = "--hardlinks" ]; then + bb_path="$prefix/bin/busybox" + else + case "$appdir" in + /) + bb_path="bin/busybox" + ;; + /bin) + bb_path="busybox" + ;; + /sbin) + bb_path="../bin/busybox" + ;; + /usr/bin|/usr/sbin) + bb_path="../../bin/busybox" + ;; + *) + echo "Unknown installation directory: $appdir" + exit 1 + ;; + esac + fi + echo " $prefix$i -> $bb_path" + ln $linkopts $bb_path $prefix$i || exit 1 +done + +exit 0 diff --git a/kernel-patches/Will_devps_GoIntoTheKernel b/kernel-patches/Will_devps_GoIntoTheKernel new file mode 100644 index 000000000..c541c0f8c --- /dev/null +++ b/kernel-patches/Will_devps_GoIntoTheKernel @@ -0,0 +1,104 @@ +I have been asked several times whether the devps patch will go into the +mainline Linux kernel. The following emails from Alan Cox and Linus Torvalds +make it clear that it is not going to happen. This does not mean this patch +had no value -- it does. It just means that those that like it get to apply it +themselves... + + -Erik + + +------------------------------- + +From alan@lxorguk.ukuu.org.uk Thu Apr 13 08:07:22 2000 +Return-Path: +Delivered-To: andersen@dillweed.dsl.xmission.com +Received: from localhost (dillweed.dsl.xmission.com [10.0.0.1]) + by dillweed.dsl.xmission.com (Postfix) with ESMTP id 1D57A11A4F5 + for ; Thu, 13 Apr 2000 08:07:22 -0600 (MDT) +Envelope-to: andersen@xmission.com +Received: from mail.xmission.com + by localhost with IMAP (fetchmail-5.3.3) + for andersen@dillweed.dsl.xmission.com (single-drop); Thu, 13 Apr 2000 08:07:22 -0600 (MDT) +Received: from [194.168.151.1] (helo=the-village.bc.nu) + by mail.xmission.com with esmtp (Exim 3.03 #3) + id 12fhQk-0002OZ-00 + for andersen@xmission.com; Thu, 13 Apr 2000 05:05:03 -0600 +Received: from alan by the-village.bc.nu with local (Exim 2.12 #1) + id 12fhQ9-0002nD-00 + for andersen@xmission.com; Thu, 13 Apr 2000 12:04:25 +0100 +Subject: Re: kernel ps drivers [Was: vm locking question] +To: andersen@xmission.com +Date: Thu, 13 Apr 2000 12:04:23 +0100 (BST) +In-Reply-To: <20000412224130.A2748@xmission.com> from "Erik Andersen" at Apr 12, 2000 10:41:30 PM +X-Mailer: ELM [version 2.5 PL1] +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: 7bit +Message-Id: +From: Alan Cox +Status: RO +X-Status: A +Content-Length: 242 +Lines: 6 + +> On the subject of ps, would you be willing to accept my /dev/ps +> patch into the kernel? If no, any suggestions on what should +> be done differently (if anything) to make it worthy of inclusion? + +For 2.2.x no, for 2.3.x ask Linus not me + + +From torvalds@transmeta.com Thu Apr 13 09:18:16 2000 +Return-Path: +Delivered-To: andersen@dillweed.dsl.xmission.com +Received: from localhost (dillweed.dsl.xmission.com [10.0.0.1]) + by dillweed.dsl.xmission.com (Postfix) with ESMTP id 3776411A3DF + for ; Thu, 13 Apr 2000 09:18:16 -0600 (MDT) +Envelope-to: andersen@xmission.com +Received: from mail.xmission.com + by localhost with IMAP (fetchmail-5.3.3) + for andersen@dillweed.dsl.xmission.com (single-drop); Thu, 13 Apr 2000 09:18:16 -0600 (MDT) +Received: from [209.10.217.66] (helo=neon-gw.transmeta.com) + by mail.xmission.com with esmtp (Exim 3.03 #3) + id 12flK2-0004dd-00 + for andersen@xmission.com; Thu, 13 Apr 2000 09:14:22 -0600 +Received: (from root@localhost) + by neon-gw.transmeta.com (8.9.3/8.9.3) id IAA18635; + Thu, 13 Apr 2000 08:10:51 -0700 +Received: from mailhost.transmeta.com(10.1.1.15) by neon-gw.transmeta.com via smap (V2.1) + id xma018629; Thu, 13 Apr 00 08:10:25 -0700 +Received: from penguin.transmeta.com (root@penguin.transmeta.com [10.1.2.202]) + by deepthought.transmeta.com (8.9.3/8.9.3) with ESMTP id IAA12264; + Thu, 13 Apr 2000 08:13:53 -0700 (PDT) +Received: from localhost (torvalds@localhost) by penguin.transmeta.com (8.9.3/8.7.3) with ESMTP id IAA02051; Thu, 13 Apr 2000 08:13:53 -0700 +X-Authentication-Warning: penguin.transmeta.com: torvalds owned process doing -bs +Date: Thu, 13 Apr 2000 08:13:53 -0700 (PDT) +From: Linus Torvalds +To: Erik Andersen +Cc: Alan Cox +Subject: Re: kernel ps drivers [Was: vm locking question] +In-Reply-To: <20000413083127.A976@xmission.com> +Message-ID: +MIME-Version: 1.0 +Content-Type: TEXT/PLAIN; charset=US-ASCII +Status: RO +Content-Length: 659 +Lines: 16 + + + +On Thu, 13 Apr 2000, Erik Andersen wrote: +> +> For 2.3.x would you be willing to accept my /dev/ps driver into the kernel? +> (Assuming I remove the /dev/modules driver (since it was pointed out that there +> is a perfectly good syscall providing that interface). If no, is there anything +> that could be done differently (if anything) to make it worthy of inclusion? + +I do dislike /dev/ps mightily. If the problem is that /proc is too large, +then the right solution is to just clean up /proc. Which is getting done. +And yes, /proc will be larger than /dev/ps, but I still find that +preferable to having two incompatible ways to do the same thing. + + Linus + + diff --git a/kernel-patches/devps.patch.9_25_2000 b/kernel-patches/devps.patch.9_25_2000 new file mode 100644 index 000000000..d74a26a99 --- /dev/null +++ b/kernel-patches/devps.patch.9_25_2000 @@ -0,0 +1,1478 @@ +diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/Config.in linux/drivers/char/Config.in +--- linux-2.2.18-9.virgin/drivers/char/Config.in Mon Sep 18 15:02:30 2000 ++++ linux/drivers/char/Config.in Mon Sep 25 16:33:16 2000 +@@ -56,6 +56,8 @@ + dep_tristate 'Microgate SyncLink card support' CONFIG_SYNCLINK m + dep_tristate 'HDLC line discipline support' CONFIG_N_HDLC m + fi ++tristate 'Devps support' CONFIG_DEVPS ++tristate 'Devmounts support' CONFIG_DEVMTAB + bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS + if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then + int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 +diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/Makefile linux/drivers/char/Makefile +--- linux-2.2.18-9.virgin/drivers/char/Makefile Mon Sep 18 15:02:30 2000 ++++ linux/drivers/char/Makefile Mon Sep 25 18:01:12 2000 +@@ -697,6 +697,22 @@ + M_OBJS += $(sort $(filter $(module-list), $(obj-m))) + + ++ifeq ($(CONFIG_DEVPS),y) ++O_OBJS += devps.o ++else ++ ifeq ($(CONFIG_DEVPS),m) ++ M_OBJS += devps.o ++ endif ++endif ++ ++ifeq ($(CONFIG_DEVMTAB),y) ++O_OBJS += devmtab.o ++else ++ ifeq ($(CONFIG_DEVMTAB),m) ++ M_OBJS += devmtab.o ++ endif ++endif ++ + include $(TOPDIR)/Rules.make + + fastdep: +diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/devmtab.c linux/drivers/char/devmtab.c +--- linux-2.2.18-9.virgin/drivers/char/devmtab.c Wed Dec 31 17:00:00 1969 ++++ linux/drivers/char/devmtab.c Mon Sep 25 17:00:57 2000 +@@ -0,0 +1,295 @@ ++/* vi: set sw=8 ts=8: */ ++/* ++ * linux/drivers/char/devmtab.c ++ * ++ * Copyright (C) 2000 Erik Andersen ++ * ++ * May be copied or modified under the terms of the GNU General Public License. ++ * See linux/COPYING for more information. ++ * ++ * This driver implements an interface whereby programs such as mount(8), ++ * umount(8), and df(1) may obtain all the process information they need to do ++ * their jobs without needing to use /proc. This driver another step in my ++ * evil plan to completely dismantle /proc. Muhahahaha! ++ * ++ * Suggestions are welcome. Patches that work are more welcome though. ;-) ++ * ++ * ++ * When using this driver, running: ++ * mknod /dev/mtab c 10 22 ++ * could be considered helpful. ++ * ++ * ---------------------------------- ++ * 1.00 Mar 07, 2000 -- Initial version. ++ * ++ *************************************************************************/ ++ ++#define DEVMTAB_VERSION "1.00" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++/* Some variables used by this device */ ++static struct wait_queue *devmtab_waitq = NULL; ++static int devmtab_already_opened = 0; ++static char *mtabfile = NULL; ++static int mtab_ptr; ++static int mtab_size; ++ ++ ++ ++/**************************************************************************** ++ * Handle opening and closing of the device ++ */ ++ ++static long long ++devmtab_lseek (struct file *file, long long offset, int orig) ++{ ++ return -ESPIPE; ++} ++ ++static ssize_t ++devmtab_read (struct file *file, char *buf, size_t count, loff_t * ppos) ++{ ++ int n = mtab_size - mtab_ptr; ++ ++ if (mtab_size == 0) { ++ /* Make some space */ ++ if (!(mtabfile = (char *) get_free_page (GFP_KERNEL))) ++ return -ENOMEM; ++ /* Grab the mtab */ ++ get_filesystem_info (mtabfile); ++ mtab_ptr = 0; ++ mtab_size = strlen (mtabfile); ++ n = mtab_size - mtab_ptr; ++ } ++ ++ if (n > count) ++ n = count; ++ if (n <= 0) ++ return 0; ++ ++ if (copy_to_user (buf, mtabfile, n)) ++ return -EFAULT; ++ mtab_ptr += n; ++ return n; ++} ++ ++static int devmtab_open (struct inode *ip, struct file *fp) ++{ ++ /* Only let one process use us at any time -- putting other ++ * processes to sleep. Those opening us O_NONBLOCK will ++ * get an EAGAIN error */ ++ if ((fp->f_flags & O_NONBLOCK) && devmtab_already_opened) ++ return -EAGAIN; ++ ++ MOD_INC_USE_COUNT; ++ ++ while (devmtab_already_opened) { ++ int i, got_signal=0; ++ ++ /* Go to sleep until we get woken up ++ * by devmtab_close or we receive a signal */ ++ module_interruptible_sleep_on(&devmtab_waitq); ++ ++ for(i=0; i<_NSIG_WORDS && !got_signal; i++) ++ got_signal = current->signal.sig[i] & ~current->blocked.sig[i]; ++ ++ /* If we got a signal, decrement the use count ++ * and return to user space */ ++ if (got_signal) { ++ MOD_DEC_USE_COUNT; ++ return -EINTR; ++ } ++ } ++ ++ /* Since we got here, then devmtab_already_opened must equal 0 */ ++ devmtab_already_opened=1; ++ mtab_ptr = 0; ++ mtab_size = 0; ++ ++ return 0; ++} ++ ++static int devmtab_release (struct inode *ip, struct file *fp) ++{ ++ /* Clean up */ ++ if (mtabfile != NULL) { ++ free_page ((unsigned long) mtabfile); ++ mtabfile = NULL; ++ } ++ ++ /* Zero out the reference counter */ ++ devmtab_already_opened=0; ++ ++ /* Wake up anybody that is waiting to access this device */ ++ module_wake_up(&devmtab_waitq); ++ ++ MOD_DEC_USE_COUNT; ++ ++ return 0; ++} ++ ++static int ++devmtab_ioctl (struct inode *ip, struct file *fp, ++ unsigned int cmd, unsigned long arg) ++{ ++ switch (cmd) { ++ case DEVMTAB_COUNT_FILESYSTEMS:{ ++ return(count_kfstypes()); ++ } ++ ++ case DEVMTAB_GET_FILESYSTEMS:{ ++ int stat, count; ++ struct k_fstype* fstypelist; ++ ++ /* How many are there? */ ++ count = count_kfstypes(); ++ ++ /* Make some space */ ++ fstypelist = (struct k_fstype *)kmalloc(sizeof(struct k_fstype) * count, GFP_KERNEL); ++ if (!fstypelist) ++ return -ENOMEM; ++ memset(fstypelist, 0, sizeof(struct k_fstype) * count); ++ ++ /* Grab the mtab entries */ ++ get_kfstype_list(count, fstypelist); ++ ++ /* Make sure there is enough room */ ++ stat = verify_area (VERIFY_WRITE, (struct k_fstype *) arg, ++ sizeof(struct k_fstype) * count); ++ if (stat) { ++ printk (KERN_INFO ++ "devmtab: Insufficient space was provided.\n"); ++ return stat; ++ } ++ ++ /* Send it to user space */ ++ copy_to_user_ret ((struct k_fstype *) arg, fstypelist, ++ sizeof(struct k_fstype) * count, ++ -EFAULT); ++ ++ /* Clean up */ ++ kfree( fstypelist); ++ return 0; ++ } ++ ++ case DEVMTAB_COUNT_MOUNTS:{ ++ return(count_mounted_filesystems()); ++ } ++ ++ case DEVMTAB_GET_MOUNTS:{ ++ int stat, count; ++ struct k_mntent* mntentlist; ++ ++ /* How many are there? */ ++ count = count_mounted_filesystems(); ++ ++ /* Make some space */ ++ mntentlist = (struct k_mntent *)kmalloc(sizeof(struct k_mntent) * count, GFP_KERNEL); ++ if (!mntentlist) ++ return -ENOMEM; ++ memset(mntentlist, 0, sizeof(struct k_mntent) * count); ++ ++ /* Grab the mtab entries */ ++ get_mtab_entries (count, mntentlist); ++ ++ /* Make sure there is enough room */ ++ stat = verify_area (VERIFY_WRITE, (void*) arg, ++ sizeof(struct k_mntent) * count); ++ if (stat) { ++ printk (KERN_INFO ++ "devmtab: Insufficient space was provided.\n"); ++ return stat; ++ } ++ ++ /* Send it to user space */ ++ copy_to_user_ret ((struct k_mntent *) arg, mntentlist, ++ sizeof(struct k_mntent) * count, ++ -EFAULT); ++ ++ /* Clean up */ ++ kfree( mntentlist); ++ return 0; ++ } ++ ++ default: ++ return -EINVAL; ++ ++ } ++ return 0; ++} ++ ++ ++ ++/**************************************************************************** ++ * Set up the file operations devmtab will support ++ */ ++static struct file_operations devmtab_fops = { ++ devmtab_lseek, ++ devmtab_read, ++ NULL, /* No write */ ++ NULL, /* No readdir */ ++ NULL, /* No poll */ ++ devmtab_ioctl, ++ NULL, /* No mmap */ ++ devmtab_open, ++ NULL, /* flush */ ++ devmtab_release, ++ NULL, /* fsync */ ++ NULL, /* fasync */ ++ NULL, /* check_media_change */ ++ NULL /* revalidate */ ++}; ++ ++static struct miscdevice devmtab_misc_dev = { ++ DEVMTAB_MINOR, ++ "devmtab", ++ &devmtab_fops ++}; ++ ++/* The real driver initialization function */ ++extern int devmtab_init (void) ++{ ++ printk (KERN_INFO "devmtab: driver %s loaded\n", DEVMTAB_VERSION); ++ ++ if (misc_register (&devmtab_misc_dev)) { ++ printk ("devmtab: can't register misc device %d\n", ++ DEVMTAB_MINOR); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++#ifdef MODULE ++ ++MODULE_AUTHOR ("Erik Andersen "); ++MODULE_DESCRIPTION ++ ("devmtab driver -- exports filesystem and mount information to user space"); ++ ++/* Stub driver initialization function */ ++int init_module (void) ++{ ++ return (devmtab_init ()); ++} ++ ++void cleanup_module (void) ++{ ++ printk (KERN_INFO "devmtab: driver unloaded\n"); ++ misc_deregister (&devmtab_misc_dev); ++} ++ ++#endif /* MODULE */ +diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/devps.c linux/drivers/char/devps.c +--- linux-2.2.18-9.virgin/drivers/char/devps.c Wed Dec 31 17:00:00 1969 ++++ linux/drivers/char/devps.c Mon Sep 25 17:00:57 2000 +@@ -0,0 +1,518 @@ ++/* vi: set sw=8 ts=8: */ ++/* ++ * linux/drivers/char/devps.c ++ * ++ * Copyright (C) 2000 Erik Andersen ++ * ++ * May be copied or modified under the terms of the GNU General Public License. ++ * See linux/COPYING for more information. ++ * ++ * This driver implements an interface whereby programs such as ps(1), top(1), ++ * killall(1) and the like may obtain all the process information they need to ++ * do their jobs. Now you may ask, "Why not use /proc? BSD uses /proc.". ++ * Thanks for asking. /proc is designed as a virtual filesystem. As such it ++ * presents all of its information in a nice, human readable format. But not ++ * human readable enough that mere mortals can actually look at the /proc ++ * information and know what is happening on their computer (which is why we ++ * have nice programs like ps(1) to help us out. Additionally, for ps (using ++ * /proc) to do its job, it has to do something like: ++ * ++ * dir = opendir("/proc"); ++ * while ((entry = readdir(dir)) != NULL) { ++ * if (!isdigit(*entry->d_name)) ++ * continue; ++ * open_lots_of files(); ++ * parse_lots_of_strings(); ++ * close_lots_of_files(); ++ * print_stuff(); ++ * } ++ * ++ * ++ * This is bad, because: ++ * ++ * 1) opening and closing lots of files is slow, ++ * ++ * 2) parsing lots of strings is slow, ++ * ++ * 3) every one of those strings had to be carefully printed out and formatted ++ * by the kernel, which is slow, ++ * ++ * 4) using a virtual filesystem is not the traditional UN*X solution to ++ * getting information from the kernel out to userspace (ioctls and syscalls ++ * are the established way to do this), and worst of all ++ * ++ * 5) having a virtual filesystem around has been so inviting that everyone has ++ * put their own weird little files into it, causing /proc to become a ++ * cluttered rubbish heap of 64 flavors of strange that takes a ridiculous ++ * amount of memory. ++ * ++ * This driver is the first step in my evil plan to completely ++ * dismantle /proc. Muhahahaha! ++ * ++ * Suggestions are welcome. Patches that work are more welcome though. ;-) ++ * ++ * When using this driver, running: ++ * mknod /dev/ps c 10 21 ++ * could be considered helpful. ++ * ++ * ---------------------------------- ++ * 1.00 Mar 07, 2000 -- Initial version. ++ * ++ * ++ * TODO ++ * ---------------------------------- ++ * ++ * * Right now none of the vm or fd info is being returned to user space. ++ * * There is probably other stuff that should be exported to user space. ++ * ++ * ++ *************************************************************************/ ++ ++#define DEVPS_VERSION "1.00" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Some variables used by this device */ ++static struct wait_queue *devps_waitq = NULL; ++static int devps_already_opened = 0; ++ ++/**************************************************************************** ++ * Handle opening and closing of the device ++ */ ++ ++static int devps_open (struct inode *ip, struct file *fp) ++{ ++ /* Only let one process use us at any time -- putting other ++ * processes to sleep. Those opening us O_NONBLOCK will ++ * get an EAGAIN error */ ++ if ((fp->f_flags & O_NONBLOCK) && devps_already_opened) ++ return -EAGAIN; ++ ++ MOD_INC_USE_COUNT; ++ ++ while (devps_already_opened) { ++ int i, got_signal=0; ++ ++ /* Go to sleep until we get woken up ++ * by devps_close or we receive a signal */ ++ module_interruptible_sleep_on(&devps_waitq); ++ ++ for(i=0; i<_NSIG_WORDS && !got_signal; i++) ++ got_signal = current->signal.sig[i] & ~current->blocked.sig[i]; ++ ++ /* If we got a signal, decrement the use count ++ * and return to user space */ ++ if (got_signal) { ++ MOD_DEC_USE_COUNT; ++ return -EINTR; ++ } ++ } ++ ++ /* Since we got here, then device_already_opened must equal 0 */ ++ devps_already_opened=1; ++ return 0; ++} ++ ++static int devps_release (struct inode *ip, struct file *fp) ++{ ++ /* Zero out the reference counter */ ++ devps_already_opened=0; ++ ++ /* Wake up anybody that is waiting to access this device */ ++ module_wake_up(&devps_waitq); ++ ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++ ++/* ++ * This pretty-prints the pathname of a dentry, ++ * clarifying sockets etc. ++ */ ++static int ++get_name_from_dentry (struct dentry *dentry, char *buffer, int buflen) ++{ ++ struct inode *inode; ++ char *tmp = (char *) __get_free_page (GFP_KERNEL), *path, *pattern; ++ int len; ++ ++ if (tmp == NULL) ++ return -ENOMEM; ++ ++ /* Check for special dentries.. */ ++ pattern = NULL; ++ inode = dentry->d_inode; ++ if (inode && dentry->d_parent == dentry) { ++ if (S_ISSOCK (inode->i_mode)) ++ pattern = "socket:[%lu]"; ++ if (S_ISFIFO (inode->i_mode)) ++ pattern = "pipe:[%lu]"; ++ } ++ ++ if (pattern) { ++ len = sprintf (tmp, pattern, inode->i_ino); ++ path = tmp; ++ } else { ++ path = d_path (dentry, tmp, PAGE_SIZE); ++ len = tmp + PAGE_SIZE - 1 - path; ++ } ++ ++ if (len < buflen) ++ buflen = len; ++ dput (dentry); ++ strncpy (buffer, path, buflen); ++ free_page ((unsigned long) tmp); ++ return buflen; ++} ++ ++static unsigned long get_phys_addr (struct task_struct *p, ++ unsigned long ptr) ++{ ++ pgd_t *page_dir; ++ pmd_t *page_middle; ++ pte_t pte; ++ ++ if (!p || !p->mm || ptr >= TASK_SIZE) ++ return 0; ++ /* Check for NULL pgd .. shouldn't happen! */ ++ if (!p->mm->pgd) { ++ printk ("get_phys_addr: pid %d has NULL pgd!\n", p->pid); ++ return 0; ++ } ++ ++ page_dir = pgd_offset (p->mm, ptr); ++ if (pgd_none (*page_dir)) ++ return 0; ++ if (pgd_bad (*page_dir)) { ++ printk ("bad page directory entry %08lx\n", ++ pgd_val (*page_dir)); ++ pgd_clear (page_dir); ++ return 0; ++ } ++ page_middle = pmd_offset (page_dir, ptr); ++ if (pmd_none (*page_middle)) ++ return 0; ++ if (pmd_bad (*page_middle)) { ++ printk ("bad page middle entry %08lx\n", ++ pmd_val (*page_middle)); ++ pmd_clear (page_middle); ++ return 0; ++ } ++ pte = *pte_offset (page_middle, ptr); ++ if (!pte_present (pte)) ++ return 0; ++ return pte_page (pte) + (ptr & ~PAGE_MASK); ++} ++ ++static int get_array (struct task_struct *p, unsigned long start, ++ unsigned long end, char *buffer) ++{ ++ unsigned long addr; ++ int size = 0, result = 0; ++ char c; ++ ++ if (start >= end) ++ return result; ++ for (;;) { ++ addr = get_phys_addr (p, start); ++ if (!addr) ++ return result; ++ do { ++ c = *(char *) addr; ++ if (!c) ++ result = size; ++ if (size < PAGE_SIZE) ++ buffer[size++] = c; ++ else ++ return result; ++ addr++; ++ start++; ++ if (!c && start >= end) ++ return result; ++ } while (addr & ~PAGE_MASK); ++ } ++ return result; ++} ++ ++static int ++devps_ioctl (struct inode *ip, struct file *fp, ++ unsigned int cmd, unsigned long arg) ++{ ++ switch (cmd) { ++ ++ /* Count up the total number of processes, ++ * and then return that total */ ++ case DEVPS_GET_NUM_PIDS:{ ++ struct task_struct *p; ++ pid_t num_pids = 0; ++ ++ read_lock (&tasklist_lock); ++ for_each_task (p) { ++ if (!p->pid) ++ continue; ++ num_pids++; ++ } ++ read_unlock (&tasklist_lock); ++ ++ copy_to_user_ret ((pid_t *) arg, &num_pids, ++ sizeof (num_pids), -EFAULT); ++ return 0; ++ } ++ ++ /* Returns an array containing all current pids, where ++ pidlist[0]=number of PIDs in the array. pidlist[0] also ++ specifies the size of the array for the kernel to ++ fill... */ ++ case DEVPS_GET_PID_LIST:{ ++ struct task_struct *p; ++ pid_t *pid_array = NULL; ++ pid_t num_pids; ++ int stat; ++ ++ /* Grab the first element to see how many * entries ++ they want us to fill */ ++ stat = verify_area (VERIFY_READ, (char *) arg, ++ sizeof (pid_t)); ++ if (stat) { ++ printk (KERN_INFO ++ "devps: can't tell how many " ++ "to pid's to write.\n"); ++ return stat; ++ } ++ ++ copy_from_user (&num_pids, (void *) arg, ++ sizeof (num_pids)); ++ ++ /* Now make sure we can write the specified amount ++ of stuff into the array. If we can't we might ++ as well quit now and save ourselves the bother. */ ++ stat = verify_area (VERIFY_WRITE, (char *) arg, ++ sizeof (pid_t) * num_pids); ++ if (stat) { ++ printk (KERN_INFO ++ "devps: Insufficient space was " ++ "provided to write %d pid's.\n", ++ num_pids); ++ return stat; ++ } ++ ++ /* Allocate some memory to hold this stuff in before ++ * we copy it out to user-space */ ++ pid_array = (pid_t *) kmalloc (num_pids * ++ sizeof (pid_t), ++ GFP_KERNEL); ++ if (pid_array == NULL) ++ return -ENOMEM; ++ ++ /* Now march through the PID list */ ++ pid_array[0] = 0; ++ read_lock (&tasklist_lock); ++ for_each_task (p) { ++ if (!p->pid) ++ continue; ++ (pid_array[0])++; ++ if (pid_array[0] >= (num_pids - 1)) ++ continue; ++ pid_array[pid_array[0]] = p->pid; ++ } ++ read_unlock (&tasklist_lock); ++ ++ /* Copy out to the user the number we actually filled ++ */ ++ copy_to_user_ret ((void *) arg, pid_array, ++ sizeof (pid_t) * pid_array[0], ++ -EFAULT); ++ kfree (pid_array); ++ ++ return 0; ++ } ++ ++ /* Find the details on a particular pid, and fill out a ++ struct with all the gory details. */ ++ case DEVPS_GET_PID_INFO:{ ++ struct task_struct *p; ++ struct pid_info mypidinfo; ++ unsigned int state; ++ /* 'R' running */ ++ /* 'S' sleeping */ ++ /* 'D' disk sleep */ ++ /* 'Z' zombie */ ++ /* 'T' stopped */ ++ /* 'W' paging */ ++ const char *state_string = "RSDZTW"; ++ ++ copy_from_user_ret (&mypidinfo, ++ (struct pid_info *) arg, ++ sizeof (mypidinfo), -EFAULT); ++ ++ read_lock (&tasklist_lock); ++ p = find_task_by_pid (mypidinfo.pid); ++ read_unlock (&tasklist_lock); ++ ++ /* Now copy all this crap so we can tell user space ++ all about it. ick. */ ++ memset (mypidinfo.name, 0, ++ sizeof (mypidinfo.name)); ++ strcpy (mypidinfo.name, p->comm); ++ mypidinfo.flags = p->flags; ++ mypidinfo.pgrp = p->pgrp; ++ mypidinfo.tms_cutime = p->times.tms_cutime; ++ mypidinfo.tms_cstime = p->times.tms_cstime; ++ mypidinfo.tms_utime = p->times.tms_utime; ++ mypidinfo.tms_stime = p->times.tms_stime; ++ mypidinfo.min_flt = p->min_flt; ++ mypidinfo.cmin_flt = p->cmin_flt; ++ mypidinfo.maj_flt = p->maj_flt; ++ mypidinfo.cmaj_flt = p->cmaj_flt; ++ mypidinfo.session = p->session; ++ mypidinfo.pid = p->pid; ++ mypidinfo.ppid = p->p_pptr->pid; ++ mypidinfo.tty = ++ p->tty ? kdev_t_to_nr (p->tty->device) : 0; ++ mypidinfo.start_time = p->start_time; ++ mypidinfo.uid = p->uid; ++ mypidinfo.euid = p->euid; ++ mypidinfo.suid = p->suid; ++ mypidinfo.fsuid = p->fsuid; ++ mypidinfo.gid = p->gid; ++ mypidinfo.egid = p->egid; ++ mypidinfo.sgid = p->sgid; ++ mypidinfo.fsgid = p->fsgid; ++ mypidinfo.priority = 20 - (p->counter * 10 + ++ DEF_PRIORITY / 2) / DEF_PRIORITY; ++ mypidinfo.nice = 20 - (mypidinfo.priority * 20 + ++ DEF_PRIORITY / 2) / DEF_PRIORITY; ++ state = p-> state & (TASK_RUNNING | TASK_INTERRUPTIBLE ++ | TASK_UNINTERRUPTIBLE | ++ TASK_ZOMBIE | TASK_STOPPED | ++ TASK_SWAPPING); ++ while (state) { ++ state_string++; ++ state >>= 1; ++ } ++ mypidinfo.state = *state_string; ++ mypidinfo.processor = p->processor; ++ mypidinfo.nswap = p->nswap; ++ mypidinfo.cnswap = p->cnswap; ++ if (p && p->mm) { ++ char *page = NULL; ++ ++ /* Look for some elbow room */ ++ if (!(page = (char*)get_free_page (GFP_KERNEL))) ++ return -ENOMEM; ++ /* Grab the command line */ ++ get_array (p, p->mm->arg_start, ++ p->mm->arg_end, page); ++ memcpy( mypidinfo.command_line, page, sizeof( mypidinfo.command_line)); ++ mypidinfo.command_line[sizeof( mypidinfo.command_line)-1]='\0'; ++ ++ /* Grab the environment */ ++ memset (page, 0, PAGE_SIZE); ++ get_array (p, p->mm->env_start, ++ p->mm->env_end, page); ++ memcpy( mypidinfo.environment, page, sizeof( mypidinfo.environment)); ++ mypidinfo.command_line[sizeof( mypidinfo.environment)-1]='\0'; ++ free_page ((unsigned long) page); ++ } ++ memset (mypidinfo.cwd, 0, sizeof (mypidinfo.cwd)); ++ get_name_from_dentry (dget (p->fs->pwd), mypidinfo.cwd, ++ sizeof (mypidinfo.cwd)); ++ memset (mypidinfo.root, 0, sizeof (mypidinfo.root)); ++ get_name_from_dentry (dget (p->fs->root), ++ mypidinfo.root, ++ sizeof (mypidinfo.root)); ++ ++ copy_to_user_ret ((struct pid_info *) arg, ++ &mypidinfo, sizeof (mypidinfo), ++ -EFAULT); ++ ++ return 0; ++ } ++ ++ /* Return the PID of the current process */ ++ case DEVPS_GET_CURRENT_PID:{ ++ return current->pid; ++ } ++ ++ default: ++ return -EINVAL; ++ ++ } ++ return 0; ++} ++ ++ ++ ++/**************************************************************************** ++ * Set up the file operations devps will support ++ */ ++static struct file_operations devps_fops = { ++ NULL, /* No lseek */ ++ NULL, /* No read */ ++ NULL, /* No write */ ++ NULL, /* No readdir */ ++ NULL, /* No poll */ ++ devps_ioctl, ++ NULL, /* No mmap */ ++ devps_open, ++ NULL, /* flush */ ++ devps_release, ++ NULL, /* fsync */ ++ NULL, /* fasync */ ++ NULL, /* check_media_change */ ++ NULL /* revalidate */ ++}; ++ ++static struct miscdevice devps_misc_dev = { ++ DEVPS_MINOR, ++ "devps", ++ &devps_fops ++}; ++ ++/* The real driver initialization function */ ++extern int devps_init (void) ++{ ++ printk (KERN_INFO "devps driver %s loaded\n", DEVPS_VERSION); ++ ++ if (misc_register (&devps_misc_dev)) { ++ printk ("devps: unable to get misc device %d\n", ++ DEVPS_MINOR); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++#ifdef MODULE ++ ++MODULE_AUTHOR ("Erik Andersen "); ++MODULE_DESCRIPTION ++ ("devps driver -- exports kernel process information to user space"); ++ ++ ++/* Stub driver initialization function */ ++int init_module (void) ++{ ++ return (devps_init ()); ++} ++ ++void cleanup_module (void) ++{ ++ printk (KERN_INFO "devps driver unloaded\n"); ++ misc_deregister (&devps_misc_dev); ++} ++ ++#endif /* endif MODULE */ +diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/makedevps.sh linux/drivers/char/makedevps.sh +--- linux-2.2.18-9.virgin/drivers/char/makedevps.sh Wed Dec 31 17:00:00 1969 ++++ linux/drivers/char/makedevps.sh Mon Sep 25 17:00:57 2000 +@@ -0,0 +1,5 @@ ++#!/bin/sh -x ++ ++gcc -Wall -g -I /usr/src/linux/include ps-devps.c -o ps-devps ++gcc -Wall -g -I /usr/src/linux/include mounts.c -o mounts ++ +diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/misc.c linux/drivers/char/misc.c +--- linux-2.2.18-9.virgin/drivers/char/misc.c Mon Sep 18 15:02:31 2000 ++++ linux/drivers/char/misc.c Mon Sep 25 17:00:57 2000 +@@ -85,6 +85,8 @@ + extern int pmu_device_init(void); + extern int tosh_init(void); + extern int rng_init(void); ++extern int devps_init(void); ++extern int devmtab_init(void); + + static int misc_read_proc(char *buf, char **start, off_t offset, + int len, int *eof, void *private) +@@ -268,6 +270,12 @@ + #endif + #ifdef CONFIG_PMAC_PBOOK + pmu_device_init(); ++#endif ++#ifdef CONFIG_DEVPS ++ devps_init(); ++#endif ++#ifdef CONFIG_DEVMTAB ++ devmtab_init(); + #endif + #ifdef CONFIG_SGI_NEWPORT_GFX + gfx_register (); +diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/mounts.c linux/drivers/char/mounts.c +--- linux-2.2.18-9.virgin/drivers/char/mounts.c Wed Dec 31 17:00:00 1969 ++++ linux/drivers/char/mounts.c Mon Sep 25 17:00:57 2000 +@@ -0,0 +1,116 @@ ++/* vi: set sw=4 ts=4: */ ++/* ++ * devmtab tester ++ * ++ * ++ * Copyright (C) 2000 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 ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++int main (int argc, char **argv) ++{ ++ char device[80] = "/dev/mtab"; ++ int fd; /* file descriptor for devmtab device */ ++ int i, numfilesystems; ++ struct k_fstype *fslist; ++ struct k_mntent *mntentlist; ++ ++ if (argc > 1 && **(argv + 1) == '-') { ++ fprintf(stderr, "Usage: mounts\n\nReport mounted stuff\n\nThis version of mounts accepts no options.\n\n"); ++ exit(1); ++ } ++ ++ /* open device */ ++ if ((fd = open(device, O_RDONLY)) < 0) { ++ fprintf (stderr, "open failed for `%s': %s\n", ++ device, strerror (errno)); ++ exit (1); ++ } ++ ++ /* How many filesystems? We need to know to allocate ++ * enough space for later... */ ++ numfilesystems = ioctl (fd, DEVMTAB_COUNT_FILESYSTEMS); ++ if (numfilesystems<0) { ++ fprintf (stderr, "\nDEVMTAB_COUNT_FILESYSTEMS: %s\n", ++ strerror (errno)); ++ exit (1); ++ } ++ fslist = (struct k_fstype *) calloc ( numfilesystems, sizeof(struct k_fstype)); ++ ++ /* Grab the list of available filesystems */ ++ if (ioctl (fd, DEVMTAB_GET_FILESYSTEMS, fslist)<0) { ++ fprintf (stderr, "\nDEVMTAB_GET_FILESYSTEMS: %s\n", ++ strerror (errno)); ++ exit (1); ++ } ++ fprintf( stdout, "\nEquivalent of /proc/filesystems:\n"); ++ for( i = 0 ; i < numfilesystems ; i++) { ++ fprintf( stdout, "%s%s\n", fslist[i].mnt_type, ++ (fslist[i].mnt_nodev)? " nodev" : ""); ++ } ++ ++ ++ /* How many mounted filesystems? We need to know to ++ * allocate enough space for later... */ ++ numfilesystems = ioctl (fd, DEVMTAB_COUNT_MOUNTS); ++ if (numfilesystems<0) { ++ fprintf (stderr, "\nDEVMTAB_COUNT_MOUNTS: %s\n", ++ strerror (errno)); ++ exit (1); ++ } ++ mntentlist = (struct k_mntent *) calloc ( numfilesystems, sizeof(struct k_mntent)); ++ ++ /* Grab the list of mounted filesystems */ ++ if (ioctl (fd, DEVMTAB_GET_MOUNTS, mntentlist)<0) { ++ fprintf (stderr, "\nDEVMTAB_GET_MOUNTS: %s\n", ++ strerror (errno)); ++ exit (1); ++ } ++ ++ fprintf( stdout, "\nEquivalent of /proc/mounts:\n"); ++ for( i = 0 ; i < numfilesystems ; i++) { ++ fprintf( stdout, "%s %s %s %s %d %d\n", mntentlist[i].mnt_fsname, ++ mntentlist[i].mnt_dir, mntentlist[i].mnt_type, ++ mntentlist[i].mnt_opts, mntentlist[i].mnt_freq, ++ mntentlist[i].mnt_passno); ++ } ++ ++ ++ /* clean up */ ++ free( fslist); ++ free( mntentlist); ++ if (close (fd) != 0) { ++ fprintf (stderr, "close failed for `%s': %s\n", ++ device, strerror (errno)); ++ exit (1); ++ } ++ ++ exit (0); ++} ++ +diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/drivers/char/ps-devps.c linux/drivers/char/ps-devps.c +--- linux-2.2.18-9.virgin/drivers/char/ps-devps.c Wed Dec 31 17:00:00 1969 ++++ linux/drivers/char/ps-devps.c Mon Sep 25 17:32:19 2000 +@@ -0,0 +1,148 @@ ++/* vi: set sw=4 ts=4: */ ++/* ++ * Mini ps implementation for use with the Linux devps driver ++ * ++ * ++ * Copyright (C) 2000 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 ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#define MAX_COLUMN 79 ++ ++int ++main (int argc, char **argv) ++{ ++ char device[80] = "/dev/ps"; ++ int i, j, len; ++ int fd; /* file descriptor for devps device */ ++ int status; /* return status for system calls */ ++ pid_t num_pids; ++ pid_t* pid_array = NULL; ++ struct pid_info info; ++ struct passwd *pwd; ++ struct group *grp; ++ char uidName[10] = ""; ++ char groupName[10] = ""; ++ ++ if (argc > 1 && **(argv + 1) == '-') { ++ fprintf(stderr, "Usage: ps-devps\n\nReport process status\n\nThis version of ps accepts no options.\n\n"); ++ exit(1); ++ } ++ ++ /* open device */ ++ //fd = open(device, O_RDWR); ++ fd = open(device, O_RDONLY); ++ if (fd < 0) { ++ fprintf (stderr, "open failed for `%s': %s\n", ++ device, strerror (errno)); ++ goto error; ++ } ++ ++ /* Find out how many processes there are */ ++ status = ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids); ++ if (status<0) { ++ fprintf (stderr, "\nDEVPS_GET_PID_LIST: %s\n", ++ strerror (errno)); ++ goto error; ++ } ++ ++ /* Allocate some memory -- grab a few extras just in case ++ * some new processes start up while we wait. The kernel will ++ * just ignore any extras if we give it too many, and will trunc. ++ * the list if we give it too few. */ ++ pid_array = (pid_t*) calloc( num_pids+10, sizeof(pid_t)); ++ pid_array[0] = num_pids+10; ++ ++ /* Now grab the pid list */ ++ status = ioctl (fd, DEVPS_GET_PID_LIST, pid_array); ++ if (status<0) { ++ fprintf (stderr, "\nDEVPS_GET_PID_LIST: %s\n", ++ strerror (errno)); ++ goto error; ++ } ++ ++ /* Print up a ps listing */ ++ fprintf(stdout, "%5s %-8s %-3s %5s %s\n", "PID", "Uid", "Gid", ++ "State", "Command"); ++ ++ for (i=1; ipw_name); ++ grp = getgrgid(info.egid); ++ if (grp == NULL) ++ sprintf(groupName, "%lu", info.egid); ++ else ++ sprintf(groupName, "%s", grp->gr_name); ++ ++ len = fprintf(stdout, "%5d %-8s %-8s %c ", info.pid, uidName, groupName, info.state); ++ ++ if (strlen(info.command_line) > 1) { ++ for( j=0; j<(sizeof(info.command_line)-1) && j < (MAX_COLUMN-len); j++) { ++ if (*(info.command_line+j) == '\0' && *(info.command_line+j+1) != '\0') { ++ *(info.command_line+j) = ' '; ++ } ++ } ++ *(info.command_line+j) = '\0'; ++ fprintf(stdout, "%s\n", info.command_line); ++ } else { ++ fprintf(stdout, "[%s]\n", info.name); ++ } ++ } ++ ++ /* Free memory */ ++ free( pid_array); ++ ++ /* close device */ ++ status = close (fd); ++ if (status != 0) { ++ fprintf (stderr, "close failed for `%s': %s\n", ++ device, strerror (errno)); ++ goto error; ++ } ++ ++ exit (0); ++error: ++ fflush(stdout); ++ fflush(stderr); ++ exit (1); ++} ++ +diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/fs/Makefile linux/fs/Makefile +--- linux-2.2.18-9.virgin/fs/Makefile Wed Aug 25 18:29:49 1999 ++++ linux/fs/Makefile Mon Sep 25 16:33:16 2000 +@@ -11,9 +11,10 @@ + L_OBJS = $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o)) + O_TARGET := fs.o + O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \ +- super.o block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ ++ block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ + ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \ + dcache.o inode.o attr.o bad_inode.o file.o $(BINFMTS) ++OX_OBJS = super.o + + MOD_LIST_NAME := FS_MODULES + ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \ +diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/fs/super.c linux/fs/super.c +--- linux-2.2.18-9.virgin/fs/super.c Mon Sep 18 15:02:34 2000 ++++ linux/fs/super.c Mon Sep 25 17:00:57 2000 +@@ -18,6 +18,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -25,6 +26,7 @@ + #include + #include + #include ++#include + + #include + +@@ -311,7 +313,57 @@ + { 0, NULL } + }; + +-int get_filesystem_info( char *buf ) ++ ++extern int count_mounted_filesystems() ++{ ++ struct vfsmount *tmp = vfsmntlist; ++ int count = 0; ++ ++ while (tmp) ++ { ++ tmp = tmp->mnt_next; ++ count++; ++ } ++ ++ return count; ++} ++EXPORT_SYMBOL(count_mounted_filesystems); ++ ++ ++extern void get_mtab_entries( int count, struct k_mntent* mntentlist) ++{ ++ struct vfsmount *tmp = vfsmntlist; ++ struct proc_fs_info *fs_infop; ++ int i = 0, len; ++ ++ while (tmp && i < count) ++ { ++ strncpy(mntentlist[i].mnt_fsname, tmp->mnt_devname, ++ sizeof(mntentlist[i].mnt_fsname)); ++ strncpy(mntentlist[i].mnt_dir, tmp->mnt_dirname, ++ sizeof(mntentlist[i].mnt_dir)); ++ strncpy(mntentlist[i].mnt_type, tmp->mnt_sb->s_type->name, ++ sizeof(mntentlist[i].mnt_type)); ++ len = 0; ++ len+=sprintf(mntentlist[i].mnt_opts, "%s", ++ tmp->mnt_flags & MS_RDONLY ? "ro" : "rw"); ++ for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { ++ if (tmp->mnt_flags & fs_infop->flag) { ++ strncpy(mntentlist[i].mnt_opts+len, fs_infop->str, ++ sizeof(mntentlist[i].mnt_opts)-len); ++ len += strlen(fs_infop->str); ++ } ++ } ++ ++ /* TODO -- add in NFS stuff */ ++ ++ tmp = tmp->mnt_next; ++ i++; ++ } ++} ++EXPORT_SYMBOL(get_mtab_entries); ++ ++extern int get_filesystem_info( char *buf ) + { + struct vfsmount *tmp = vfsmntlist; + struct proc_fs_info *fs_infop; +@@ -383,8 +435,37 @@ + + return len; + } ++EXPORT_SYMBOL(get_filesystem_info); ++ ++extern int count_kfstypes() ++{ ++ struct file_system_type * tmp = file_systems; ++ int count = 0; ++ ++ while (tmp) { ++ count++; ++ tmp = tmp->next; ++ } ++ ++ return count; ++} ++EXPORT_SYMBOL(count_kfstypes); ++ ++extern void get_kfstype_list(int count, struct k_fstype* fstypelist) ++{ ++ int i = 0; ++ struct file_system_type * tmp = file_systems; ++ ++ while (tmp && i < count) { ++ strncpy(fstypelist[i].mnt_type, tmp->name, sizeof(fstypelist[i].mnt_type)); ++ fstypelist[i].mnt_nodev = (tmp->fs_flags & FS_REQUIRES_DEV)? 0 : 1; ++ tmp = tmp->next; ++ i++; ++ } ++} ++EXPORT_SYMBOL(get_kfstype_list); + +-int get_filesystem_list(char * buf) ++extern int get_filesystem_list(char * buf) + { + int len = 0; + struct file_system_type * tmp; +@@ -398,6 +479,7 @@ + } + return len; + } ++EXPORT_SYMBOL(get_filesystem_list); + + struct file_system_type *get_fs_type(const char *name) + { +diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/devmtab.h linux/include/linux/devmtab.h +--- linux-2.2.18-9.virgin/include/linux/devmtab.h Wed Dec 31 17:00:00 1969 ++++ linux/include/linux/devmtab.h Mon Sep 25 17:00:57 2000 +@@ -0,0 +1,55 @@ ++/* vi: set sw=8 ts=8: */ ++/* ++ * -- ++ * ++ * Copyright (C) 2000 Erik Andersen ++ * ++ * May be copied or modified under the terms of the GNU General Public License. ++ * See linux/COPYING for more information. ++ * ++ * This driver implements an interface whereby programs such as mount(8), ++ * umount(8), and df(1) may obtain all the process information they need to do ++ * their jobs without needing to use /proc. ++ * ++ */ ++ ++#ifndef _LINUX_DEVMTAB_H ++#define _LINUX_DEVMTAB_H ++ ++ ++/******************************************************* ++ * The list of all ioctl(2) commands suported by devmtab. ++ * For the devmtab ioctls, I have commandeered some of the ++ * higher bits of byte 0xeb. ++ *******************************************************/ ++#define DEVMTAB_COUNT_FILESYSTEMS 0xebaa /* Get a list of all fs */ ++#define DEVMTAB_GET_FILESYSTEMS 0xebab /* Get a list of all fs */ ++#define DEVMTAB_COUNT_MOUNTS 0xebac /* Returns number of mounted filesystems */ ++#define DEVMTAB_GET_MOUNTS 0xebad /* Get a list of a mounted fs */ ++#define DEVMTAB_SET_ROOTFS_DEVNAME 0xebae /* Replace /dev/root with real name */ ++ ++/******************************************************* ++ * devmtab ioctl(2) structures ++ *******************************************************/ ++ ++/* An array of these is returned by the DEVMTAB_GET_FILESYSTEMS ioctl. ++ */ ++struct k_fstype { ++ char mnt_type[255]; /* filesystem type: ext2, nfs, etc. */ ++ int mnt_nodev; /* Is this a device-less filesystem? */ ++}; ++ ++/* An array of these is returned by the DEVMTAB_GET_MOUNTS ioctl. ++ * This struct should be the same as what libc returns via the ++ * getmntent(3) function (excat this comes from the kernel, not ++ * from whatever noise is in /etc/mtab at the moment... */ ++struct k_mntent { ++ char mnt_fsname[255]; /* name of mounted file system */ ++ char mnt_dir[255]; /* path of file system mount point */ ++ char mnt_type[255]; /* filesystem type: ext2, nfs, etc. */ ++ char mnt_opts[255]; /* Comma-separated list of mount options */ ++ int mnt_freq; /* dump frequency in days */ ++ int mnt_passno; /* pass number for parallel fsck */ ++}; ++ ++#endif /* _LINUX_DEVMTAB_H */ +diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/devps.h linux/include/linux/devps.h +--- linux-2.2.18-9.virgin/include/linux/devps.h Wed Dec 31 17:00:00 1969 ++++ linux/include/linux/devps.h Mon Sep 25 17:00:57 2000 +@@ -0,0 +1,78 @@ ++/* ++ * -- ++ * ++ * Copyright (C) 2000 Erik Andersen ++ * ++ * May be copied or modified under the terms of the GNU General Public License. ++ * See linux/COPYING for more information. ++ * ++ * This driver implements an interface whereby programs such as ps(1), top(1), ++ * killall(1) and the like may obtain all the process information they need to ++ * do their jobs. ++ * ++ */ ++ ++#ifndef _LINUX_DEVPS_H ++#define _LINUX_DEVPS_H ++ ++ ++/******************************************************* ++ * The list of all ioctl(2) commands suported by devps. ++ * For the devps ioctls, I have commandeered some of the ++ * higher bits of byte 0xeb. ++ *******************************************************/ ++#define DEVPS_GET_NUM_PIDS 0xeba1 /* Get a list of all PIDs */ ++#define DEVPS_GET_PID_LIST 0xeba2 /* Get a list of all PIDs */ ++#define DEVPS_GET_PID_INFO 0xeba3 /* Get info about a specific PID */ ++#define DEVPS_GET_CURRENT_PID 0xeba4 /* Get the current PID */ ++ ++/******************************************************* ++ * devps ioctl(2) structures ++ *******************************************************/ ++ ++ ++struct pid_info ++{ ++ char name[16]; ++ long flags; ++ pid_t pgrp; ++ clock_t tms_cutime; ++ clock_t tms_cstime; ++ clock_t tms_utime; ++ clock_t tms_stime; ++ unsigned long min_flt; ++ unsigned long cmin_flt; ++ unsigned long maj_flt; ++ unsigned long cmaj_flt; ++ pid_t session; ++ pid_t pid; ++ pid_t ppid; ++ int tty; ++ unsigned long start_time; ++ unsigned long uid,euid,suid,fsuid; ++ unsigned long gid,egid,sgid,fsgid; ++ long priority, nice; ++ char state; ++ int processor; ++ unsigned long nswap, cnswap; ++ char command_line[256]; ++ char environment[256]; ++ char root[256]; ++ char cwd[256]; ++#if 0 ++ /* TODO: Add in this (and probably more) stuff */ ++ ++ int resident; ++ int size; ++ int share; ++ unsigned long vsize; ++ char exe[MAX_PATH]; ++ unsigned long vm_total, vm_locked, vm_rss, vm_data, vm_stack, vm_exec, vm_lib; ++ unsigned long start_code, end_code, start_data, eip, esp; ++ unsigned long signal, blocked; ++#endif ++ ++ ++}; ++ ++#endif /* _LINUX_DEVPS_H */ +diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/fs.h linux/include/linux/fs.h +--- linux-2.2.18-9.virgin/include/linux/fs.h Mon Sep 18 15:08:47 2000 ++++ linux/include/linux/fs.h Mon Sep 25 17:37:50 2000 +@@ -573,6 +573,16 @@ + struct semaphore s_vfs_rename_sem; /* Kludge */ + }; + ++/* fs/super.c */ ++#include ++ ++extern int count_kfstypes( void); ++extern void get_kfstype_list( int count, struct k_fstype* fstypelist); ++extern int count_mounted_filesystems( void); ++extern int get_filesystem_info(char *buf); ++extern int get_filesystem_list(char *buf); ++extern void get_mtab_entries( int count, struct k_mntent* mntentlist); ++ + /* + * VFS helper functions.. + */ +diff -urN --exclude=.version --exclude=.config* --exclude=.*depend linux-2.2.18-9.virgin/include/linux/miscdevice.h linux/include/linux/miscdevice.h +--- linux-2.2.18-9.virgin/include/linux/miscdevice.h Mon Aug 9 13:04:41 1999 ++++ linux/include/linux/miscdevice.h Mon Sep 25 16:33:17 2000 +@@ -11,6 +11,8 @@ + #define APOLLO_MOUSE_MINOR 7 + #define PC110PAD_MINOR 9 + #define MAC_MOUSE_MINOR 10 ++#define DEVPS_MINOR 21 ++#define DEVMTAB_MINOR 22 + #define WATCHDOG_MINOR 130 /* Watchdog timer */ + #define TEMP_MINOR 131 /* Temperature Sensor */ + #define RTC_MINOR 135 diff --git a/kill.c b/kill.c new file mode 100644 index 000000000..499be111e --- /dev/null +++ b/kill.c @@ -0,0 +1,154 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini kill/killall implementation for busybox + * + * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 1999-2002 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 + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +static const int KILL = 0; +static const int KILLALL = 1; + + +extern int kill_main(int argc, char **argv) +{ + int whichApp, sig = SIGTERM, quiet, errors; + const char *name; + +#ifdef BB_KILLALL + /* Figure out what we are trying to do here */ + whichApp = (strcmp(applet_name, "killall") == 0)? KILLALL : KILL; +#else + whichApp = KILL; +#endif + + errors=0; + quiet=0; + argc--; + argv++; + /* Parse any options */ + if (argc < 1) + show_usage(); + + while (argc > 0 && **argv == '-') { + while (*++(*argv)) { + switch (**argv) { +#ifdef BB_KILLALL + case 'q': + quiet++; + break; +#endif + case 'l': + if(argc>1) { + for(argv++; *argv; argv++) { + name = u_signal_names(*argv, &sig, -1); + if(name!=NULL) + printf("%s\n", name); + } + } else { + int col = 0; + for(sig=1; sig < NSIG; sig++) { + name = u_signal_names(0, &sig, 1); + if(name==NULL) /* unnamed */ + continue; + col += printf("%2d) %-16s", sig, name); + if (col > 60) { + printf("\n"); + col = 0; + } + } + printf("\n"); + } + return EXIT_SUCCESS; + case '-': + show_usage(); + default: + name = u_signal_names(*argv, &sig, 0); + if(name==NULL) + error_msg_and_die( "bad signal name: %s", *argv); + argc--; + argv++; + goto do_it_now; + } + argc--; + argv++; + } + } + +do_it_now: + + if (whichApp == KILL) { + /* Looks like they want to do a kill. Do that */ + while (--argc >= 0) { + int pid; + + if (!isdigit(**argv)) + perror_msg_and_die( "Bad PID"); + pid = strtol(*argv, NULL, 0); + if (kill(pid, sig) != 0) { + perror_msg( "Could not kill pid '%d'", pid); + errors++; + } + argv++; + } + } +#ifdef BB_KILLALL + else { + pid_t myPid=getpid(); + /* Looks like they want to do a killall. Do that */ + while (--argc >= 0) { + long* pidList; + + pidList = find_pid_by_name(*argv); + if (!pidList || *pidList<=0) { + errors++; + if (!quiet) + error_msg( "%s: no process killed", *argv); + } else { + for(; *pidList!=0; pidList++) { + if (*pidList==myPid) + continue; + if (kill(*pidList, sig) != 0) { + errors++; + if (!quiet) + perror_msg( "Could not kill pid '%d'", *pidList); + } + } + } + + /* Note that we don't bother to free the memory + * allocated in find_pid_by_name(). It will be freed + * upon exit, so we can save a byte or two */ + argv++; + } + } +#endif + + return errors; +} diff --git a/klogd.c b/klogd.c new file mode 100644 index 000000000..75c7e1057 --- /dev/null +++ b/klogd.c @@ -0,0 +1,160 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini klogd implementation for busybox + * + * Copyright (C) 2001 by Gennady Feldman . + * Changes: Made this a standalone busybox module which uses standalone + * syslog() client interface. + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen + * + * Copyright (C) 2000 by Karl M. Hegbloom + * + * "circular buffer" Copyright (C) 2000 by Gennady Feldman + * + * Maintainer: Gennady Feldman as of Mar 12, 2001 + * + * 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 /* for our signal() handlers */ +#include /* strncpy() */ +#include /* errno and friends */ +#include +#include +#include + +#if __GNU_LIBRARY__ < 5 +# ifdef __alpha__ +# define klogctl syslog +# endif +#else +# include +#endif + +#include "busybox.h" + +static void klogd_signal(int sig) +{ + klogctl(7, NULL, 0); + klogctl(0, 0, 0); + //logMessage(0, "Kernel log daemon exiting."); + syslog_msg(LOG_SYSLOG, LOG_NOTICE, "Kernel log daemon exiting."); + exit(TRUE); +} + +static void doKlogd (void) __attribute__ ((noreturn)); +static void doKlogd (void) +{ + int priority = LOG_INFO; + char log_buffer[4096]; + int i, n, lastc; + char *start; + + /* Set up sig handlers */ + signal(SIGINT, klogd_signal); + signal(SIGKILL, klogd_signal); + signal(SIGTERM, klogd_signal); + signal(SIGHUP, SIG_IGN); + + /* "Open the log. Currently a NOP." */ + klogctl(1, NULL, 0); + + syslog_msg(LOG_SYSLOG, LOG_NOTICE, "klogd started: " BB_BANNER); + + while (1) { + /* Use kernel syscalls */ + memset(log_buffer, '\0', sizeof(log_buffer)); + n = klogctl(2, log_buffer, sizeof(log_buffer)); + if (n < 0) { + char message[80]; + + if (errno == EINTR) + continue; + snprintf(message, 79, "klogd: Error return from sys_sycall: %d - %s.\n", + errno, strerror(errno)); + syslog_msg(LOG_SYSLOG, LOG_ERR, message); + exit(1); + } + + /* klogctl buffer parsing modelled after code in dmesg.c */ + start=&log_buffer[0]; + lastc='\0'; + for (i=0; i') i++; + start = &log_buffer[i]; + } + if (log_buffer[i] == '\n') { + log_buffer[i] = '\0'; /* zero terminate this message */ + syslog_msg(LOG_KERN, priority, start); + start = &log_buffer[i+1]; + priority = LOG_INFO; + } + lastc = log_buffer[i]; + } + } +} + +extern int klogd_main(int argc, char **argv) +{ + /* no options, no getopt */ + int opt; +#ifndef __uClinux__ /* fork() not available in uClinux */ + int doFork = TRUE; +#endif /* __uClinux__ */ + + /* do normal option parsing */ + while ((opt = getopt(argc, argv, "n")) > 0) { + switch (opt) { + case 'n': +#ifndef __uClinux__ /* fork() not available in uClinux */ + doFork = FALSE; +#endif /* __uClinux__ */ + break; + default: + show_usage(); + } + } + +#ifndef __uClinux__ /* fork() not available in uClinux */ + if (doFork == TRUE) { + if (daemon(0, 1) < 0) + perror_msg_and_die("daemon"); + } +#endif /* __uClinux__ */ + + doKlogd(); + + return EXIT_SUCCESS; +} + +/* +Local Variables +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/lash.c b/lash.c new file mode 100644 index 000000000..eb88da311 --- /dev/null +++ b/lash.c @@ -0,0 +1,1650 @@ +/* vi: set sw=4 ts=4: */ +/* + * lash -- the BusyBox Lame-Ass SHell + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999-2002 Erik Andersen + * + * Based in part on ladsh.c by Michael K. Johnson and Erik W. Troan, which is + * under the following liberal license: "We have placed this source code in the + * public domain. Use it in any project, free or commercial." + * + * 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 + * + */ + +/* This shell's parsing engine is officially at a dead-end. + * Future work shell work should be done using hush.c + */ + +//For debugging/development on the shell only... +//#define DEBUG_SHELL + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" +#include "cmdedit.h" + +#ifdef BB_LOCALE_SUPPORT +#include +#endif + +#include +#define expand_t glob_t + + +static const int MAX_READ = 128; /* size of input buffer for `read' builtin */ +#define JOB_STATUS_FORMAT "[%d] %-22s %.40s\n" + + +enum redir_type { REDIRECT_INPUT, REDIRECT_OVERWRITE, + REDIRECT_APPEND +}; + +static const unsigned int DEFAULT_CONTEXT=0x1; +static const unsigned int IF_TRUE_CONTEXT=0x2; +static const unsigned int IF_FALSE_CONTEXT=0x4; +static const unsigned int THEN_EXP_CONTEXT=0x8; +static const unsigned int ELSE_EXP_CONTEXT=0x10; + + +struct jobset { + struct job *head; /* head of list of running jobs */ + struct job *fg; /* current foreground job */ +}; + +struct redir_struct { + enum redir_type type; /* type of redirection */ + int fd; /* file descriptor being redirected */ + char *filename; /* file to redirect fd to */ +}; + +struct child_prog { + pid_t pid; /* 0 if exited */ + char **argv; /* program name and arguments */ + int num_redirects; /* elements in redirection array */ + struct redir_struct *redirects; /* I/O redirects */ + int is_stopped; /* is the program currently running? */ + struct job *family; /* pointer back to the child's parent job */ +}; + +struct job { + int jobid; /* job number */ + int num_progs; /* total number of programs in job */ + int running_progs; /* number of programs running */ + char *text; /* name of job */ + char *cmdbuf; /* buffer various argv's point into */ + pid_t pgrp; /* process group ID for the job */ + struct child_prog *progs; /* array of programs in job */ + struct job *next; /* to track background commands */ + int stopped_progs; /* number of programs alive, but stopped */ + unsigned int job_context; /* bitmask defining current context */ + struct jobset *job_list; +}; + +struct built_in_command { + char *cmd; /* name */ + char *descr; /* description */ + int (*function) (struct child_prog *); /* function ptr */ +}; + +struct close_me { + int fd; + struct close_me *next; +}; + +/* function prototypes for builtins */ +static int builtin_cd(struct child_prog *cmd); +static int builtin_exec(struct child_prog *cmd); +static int builtin_exit(struct child_prog *cmd); +static int builtin_fg_bg(struct child_prog *cmd); +static int builtin_help(struct child_prog *cmd); +static int builtin_jobs(struct child_prog *dummy); +static int builtin_pwd(struct child_prog *dummy); +static int builtin_export(struct child_prog *cmd); +static int builtin_source(struct child_prog *cmd); +static int builtin_unset(struct child_prog *cmd); +static int builtin_read(struct child_prog *cmd); + + +/* function prototypes for shell stuff */ +static void mark_open(int fd); +static void mark_closed(int fd); +static void close_all(void); +static void checkjobs(struct jobset *job_list); +static void remove_job(struct jobset *j_list, struct job *job); +static int get_command(FILE * source, char *command); +static int parse_command(char **command_ptr, struct job *job, int *inbg); +static int run_command(struct job *newjob, int inbg, int outpipe[2]); +static int pseudo_exec(struct child_prog *cmd) __attribute__ ((noreturn)); +static int busy_loop(FILE * input); + + +/* Table of built-in functions (these are non-forking builtins, meaning they + * can change global variables in the parent shell process but they will not + * work with pipes and redirects; 'unset foo | whatever' will not work) */ +static struct built_in_command bltins[] = { + {"bg", "Resume a job in the background", builtin_fg_bg}, + {"cd", "Change working directory", builtin_cd}, + {"exec", "Exec command, replacing this shell with the exec'd process", builtin_exec}, + {"exit", "Exit from shell()", builtin_exit}, + {"fg", "Bring job into the foreground", builtin_fg_bg}, + {"jobs", "Lists the active jobs", builtin_jobs}, + {"export", "Set environment variable", builtin_export}, + {"unset", "Unset environment variable", builtin_unset}, + {"read", "Input environment variable", builtin_read}, + {".", "Source-in and run commands in a file", builtin_source}, + /* to do: add ulimit */ + {NULL, NULL, NULL} +}; + +/* Table of forking built-in functions (things that fork cannot change global + * variables in the parent process, such as the current working directory) */ +static struct built_in_command bltins_forking[] = { + {"pwd", "Print current directory", builtin_pwd}, + {"help", "List shell built-in commands", builtin_help}, + {NULL, NULL, NULL} +}; + + +static int shell_context; /* Type prompt trigger (PS1 or PS2) */ + + +/* Globals that are static to this file */ +static const char *cwd; +static char *local_pending_command = NULL; +static struct jobset job_list = { NULL, NULL }; +static int argc; +static char **argv; +static struct close_me *close_me_head; +static int last_return_code; +static int last_bg_pid; +static unsigned int last_jobid; +static int shell_terminal; +static pid_t shell_pgrp; +static char *PS1; +static char *PS2 = "> "; + + +#ifdef DEBUG_SHELL +static inline void debug_printf(const char *format, ...) +{ + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); +} +#else +static inline void debug_printf(const char *format, ...) { } +#endif + +/* + Most builtins need access to the struct child_prog that has + their arguments, previously coded as cmd->progs[0]. That coding + can exhibit a bug, if the builtin is not the first command in + a pipeline: "echo foo | exec sort" will attempt to exec foo. + +builtin previous use notes +------ ----------------- --------- +cd cmd->progs[0] +exec cmd->progs[0] squashed bug: didn't look for applets or forking builtins +exit cmd->progs[0] +fg_bg cmd->progs[0], job_list->head, job_list->fg +help 0 +jobs job_list->head +pwd 0 +export cmd->progs[0] +source cmd->progs[0] +unset cmd->progs[0] +read cmd->progs[0] + +I added "struct job *family;" to struct child_prog, +and switched API to builtin_foo(struct child_prog *child); +So cmd->text becomes child->family->text + cmd->job_context becomes child->family->job_context + cmd->progs[0] becomes *child + job_list becomes child->family->job_list + */ + +/* built-in 'cd ' handler */ +static int builtin_cd(struct child_prog *child) +{ + char *newdir; + + if (child->argv[1] == NULL) + newdir = getenv("HOME"); + else + newdir = child->argv[1]; + if (chdir(newdir)) { + printf("cd: %s: %m\n", newdir); + return EXIT_FAILURE; + } + cwd = xgetcwd((char *)cwd); + if (!cwd) + cwd = unknown; + return EXIT_SUCCESS; +} + +/* built-in 'exec' handler */ +static int builtin_exec(struct child_prog *child) +{ + if (child->argv[1] == NULL) + return EXIT_SUCCESS; /* Really? */ + child->argv++; + close_all(); + pseudo_exec(child); + /* never returns */ +} + +/* built-in 'exit' handler */ +static int builtin_exit(struct child_prog *child) +{ + if (child->argv[1] == NULL) + exit(EXIT_SUCCESS); + + exit (atoi(child->argv[1])); +} + +/* built-in 'fg' and 'bg' handler */ +static int builtin_fg_bg(struct child_prog *child) +{ + int i, jobnum; + struct job *job=NULL; + + /* If they gave us no args, assume they want the last backgrounded task */ + if (!child->argv[1]) { + for (job = child->family->job_list->head; job; job = job->next) { + if (job->jobid == last_jobid) { + break; + } + } + if (!job) { + error_msg("%s: no current job", child->argv[0]); + return EXIT_FAILURE; + } + } else { + if (sscanf(child->argv[1], "%%%d", &jobnum) != 1) { + error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]); + return EXIT_FAILURE; + } + for (job = child->family->job_list->head; job; job = job->next) { + if (job->jobid == jobnum) { + break; + } + } + if (!job) { + error_msg("%s: %d: no such job", child->argv[0], jobnum); + return EXIT_FAILURE; + } + } + + if (*child->argv[0] == 'f') { + /* Put the job into the foreground. */ + tcsetpgrp(shell_terminal, job->pgrp); + + child->family->job_list->fg = job; + } + + /* Restart the processes in the job */ + for (i = 0; i < job->num_progs; i++) + job->progs[i].is_stopped = 0; + + job->stopped_progs = 0; + + if ( (i=kill(- job->pgrp, SIGCONT)) < 0) { + if (i == ESRCH) { + remove_job(&job_list, job); + } else { + perror_msg("kill (SIGCONT)"); + } + } + + return EXIT_SUCCESS; +} + +/* built-in 'help' handler */ +static int builtin_help(struct child_prog *dummy) +{ + struct built_in_command *x; + + printf("\nBuilt-in commands:\n"); + printf("-------------------\n"); + for (x = bltins; x->cmd; x++) { + if (x->descr==NULL) + continue; + printf("%s\t%s\n", x->cmd, x->descr); + } + for (x = bltins_forking; x->cmd; x++) { + if (x->descr==NULL) + continue; + printf("%s\t%s\n", x->cmd, x->descr); + } + printf("\n\n"); + return EXIT_SUCCESS; +} + +/* built-in 'jobs' handler */ +static int builtin_jobs(struct child_prog *child) +{ + struct job *job; + char *status_string; + + for (job = child->family->job_list->head; job; job = job->next) { + if (job->running_progs == job->stopped_progs) + status_string = "Stopped"; + else + status_string = "Running"; + + printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text); + } + return EXIT_SUCCESS; +} + + +/* built-in 'pwd' handler */ +static int builtin_pwd(struct child_prog *dummy) +{ + cwd = xgetcwd((char *)cwd); + if (!cwd) + cwd = unknown; + puts(cwd); + return EXIT_SUCCESS; +} + +/* built-in 'export VAR=value' handler */ +static int builtin_export(struct child_prog *child) +{ + int res; + char *v = child->argv[1]; + + if (v == NULL) { + char **e; + for (e = environ; *e; e++) { + puts(*e); + } + return 0; + } + res = putenv(v); + if (res) + fprintf(stderr, "export: %m\n"); +#ifdef BB_FEATURE_SH_FANCY_PROMPT + if (strncmp(v, "PS1=", 4)==0) + PS1 = getenv("PS1"); +#endif + +#ifdef BB_LOCALE_SUPPORT + if(strncmp(v, "LC_ALL=", 7)==0) + setlocale(LC_ALL, getenv("LC_ALL")); + if(strncmp(v, "LC_CTYPE=", 9)==0) + setlocale(LC_CTYPE, getenv("LC_CTYPE")); +#endif + + return (res); +} + +/* built-in 'read VAR' handler */ +static int builtin_read(struct child_prog *child) +{ + int res = 0, len, newlen; + char *s; + char string[MAX_READ]; + + if (child->argv[1]) { + /* argument (VAR) given: put "VAR=" into buffer */ + snprintf(string, sizeof(string)-1, "%s=", child->argv[1]); + len = strlen(string); + fgets(&string[len], sizeof(string) - len, stdin); /* read string */ + newlen = strlen(string); + if(newlen > len) + string[--newlen] = '\0'; /* chomp trailing newline */ + /* + ** string should now contain "VAR=" + ** copy it (putenv() won't do that, so we must make sure + ** the string resides in a static buffer!) + */ + res = -1; + if((s = strdup(string))) + res = putenv(s); + if (res) + fprintf(stderr, "read: %m\n"); + } + else + fgets(string, sizeof(string), stdin); + + return (res); +} + +/* Built-in '.' handler (read-in and execute commands from file) */ +static int builtin_source(struct child_prog *child) +{ + FILE *input; + int status; + int fd; + + if (child->argv[1] == NULL) + return EXIT_FAILURE; + + input = fopen(child->argv[1], "r"); + if (!input) { + printf( "Couldn't open file '%s'\n", child->argv[1]); + return EXIT_FAILURE; + } + + fd=fileno(input); + mark_open(fd); + /* Now run the file */ + status = busy_loop(input); + fclose(input); + mark_closed(fd); + return (status); +} + +/* built-in 'unset VAR' handler */ +static int builtin_unset(struct child_prog *child) +{ + if (child->argv[1] == NULL) { + printf( "unset: parameter required.\n"); + return EXIT_FAILURE; + } + unsetenv(child->argv[1]); + return EXIT_SUCCESS; +} + +static void mark_open(int fd) +{ + struct close_me *new = xmalloc(sizeof(struct close_me)); + new->fd = fd; + new->next = close_me_head; + close_me_head = new; +} + +static void mark_closed(int fd) +{ + struct close_me *tmp; + if (close_me_head == NULL || close_me_head->fd != fd) + error_msg_and_die("corrupt close_me"); + tmp = close_me_head; + close_me_head = close_me_head->next; + free(tmp); +} + +static void close_all() +{ + struct close_me *c, *tmp; + for (c=close_me_head; c; c=tmp) { + close(c->fd); + tmp=c->next; + free(c); + } + close_me_head = NULL; +} + + +/* free up all memory from a job */ +static void free_job(struct job *cmd) +{ + int i; + struct jobset *keep; + + for (i = 0; i < cmd->num_progs; i++) { + free(cmd->progs[i].argv); + if (cmd->progs[i].redirects) + free(cmd->progs[i].redirects); + } + if (cmd->progs) + free(cmd->progs); + if (cmd->text) + free(cmd->text); + if (cmd->cmdbuf) + free(cmd->cmdbuf); + keep = cmd->job_list; + memset(cmd, 0, sizeof(struct job)); + cmd->job_list = keep; +} + +/* remove a job from a jobset */ +static void remove_job(struct jobset *j_list, struct job *job) +{ + struct job *prevjob; + + free_job(job); + if (job == j_list->head) { + j_list->head = job->next; + } else { + prevjob = j_list->head; + while (prevjob->next != job) + prevjob = prevjob->next; + prevjob->next = job->next; + } + + if (j_list->head) + last_jobid = j_list->head->jobid; + else + last_jobid = 0; + + free(job); +} + +/* Checks to see if any background processes have exited -- if they + have, figure out why and see if a job has completed */ +static void checkjobs(struct jobset *j_list) +{ + struct job *job; + pid_t childpid; + int status; + int prognum = 0; + + while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { + for (job = j_list->head; job; job = job->next) { + prognum = 0; + while (prognum < job->num_progs && + job->progs[prognum].pid != childpid) prognum++; + if (prognum < job->num_progs) + break; + } + + /* This happens on backticked commands */ + if(job==NULL) + return; + + if (WIFEXITED(status) || WIFSIGNALED(status)) { + /* child exited */ + job->running_progs--; + job->progs[prognum].pid = 0; + + if (!job->running_progs) { + printf(JOB_STATUS_FORMAT, job->jobid, "Done", job->text); + last_jobid=0; + remove_job(j_list, job); + } + } else { + /* child stopped */ + job->stopped_progs++; + job->progs[prognum].is_stopped = 1; + +#if 0 + /* Printing this stuff is a pain, since it tends to + * overwrite the prompt an inconveinient moments. So + * don't do that. */ + if (job->stopped_progs == job->num_progs) { + printf(JOB_STATUS_FORMAT, job->jobid, "Stopped", + job->text); + } +#endif + } + } + + if (childpid == -1 && errno != ECHILD) + perror_msg("waitpid"); +} + +/* squirrel != NULL means we squirrel away copies of stdin, stdout, + * and stderr if they are redirected. */ +static int setup_redirects(struct child_prog *prog, int squirrel[]) +{ + int i; + int openfd; + int mode = O_RDONLY; + struct redir_struct *redir = prog->redirects; + + for (i = 0; i < prog->num_redirects; i++, redir++) { + switch (redir->type) { + case REDIRECT_INPUT: + mode = O_RDONLY; + break; + case REDIRECT_OVERWRITE: + mode = O_WRONLY | O_CREAT | O_TRUNC; + break; + case REDIRECT_APPEND: + mode = O_WRONLY | O_CREAT | O_APPEND; + break; + } + + openfd = open(redir->filename, mode, 0666); + if (openfd < 0) { + /* this could get lost if stderr has been redirected, but + bash and ash both lose it as well (though zsh doesn't!) */ + perror_msg("error opening %s", redir->filename); + return 1; + } + + if (openfd != redir->fd) { + if (squirrel && redir->fd < 3) { + squirrel[redir->fd] = dup(redir->fd); + } + dup2(openfd, redir->fd); + close(openfd); + } + } + + return 0; +} + +static void restore_redirects(int squirrel[]) +{ + int i, fd; + for (i=0; i<3; i++) { + fd = squirrel[i]; + if (fd != -1) { + /* No error checking. I sure wouldn't know what + * to do with an error if I found one! */ + dup2(fd, i); + close(fd); + } + } +} + +static inline void cmdedit_set_initial_prompt(void) +{ +#ifndef BB_FEATURE_SH_FANCY_PROMPT + PS1 = NULL; +#else + PS1 = getenv("PS1"); + if(PS1==0) + PS1 = "\\w \\$ "; +#endif +} + +static inline void setup_prompt_string(char **prompt_str) +{ +#ifndef BB_FEATURE_SH_FANCY_PROMPT + /* Set up the prompt */ + if (shell_context == 0) { + if (PS1) + free(PS1); + PS1=xmalloc(strlen(cwd)+4); + sprintf(PS1, "%s %s", cwd, ( geteuid() != 0 ) ? "$ ":"# "); + *prompt_str = PS1; + } else { + *prompt_str = PS2; + } +#else + *prompt_str = (shell_context==0)? PS1 : PS2; +#endif +} + +static int get_command(FILE * source, char *command) +{ + char *prompt_str; + + if (source == NULL) { + if (local_pending_command) { + /* a command specified (-c option): return it & mark it done */ + strcpy(command, local_pending_command); + free(local_pending_command); + local_pending_command = NULL; + return 0; + } + return 1; + } + + if (source == stdin) { + setup_prompt_string(&prompt_str); + +#ifdef BB_FEATURE_COMMAND_EDITING + /* + ** enable command line editing only while a command line + ** is actually being read; otherwise, we'll end up bequeathing + ** atexit() handlers and other unwanted stuff to our + ** child processes (rob@sysgo.de) + */ + cmdedit_read_input(prompt_str, command); + return 0; +#else + fputs(prompt_str, stdout); +#endif + } + + if (!fgets(command, BUFSIZ - 2, source)) { + if (source == stdin) + printf("\n"); + return 1; + } + + return 0; +} + +static char* itoa(register int i) +{ + static char a[7]; /* Max 7 ints */ + register char *b = a + sizeof(a) - 1; + int sign = (i < 0); + + if (sign) + i = -i; + *b = 0; + do + { + *--b = '0' + (i % 10); + i /= 10; + } + while (i); + if (sign) + *--b = '-'; + return b; +} + +char * strsep_space( char *string, int * ix) +{ + char *token, *begin; + + begin = string; + + /* Short circuit the trivial case */ + if ( !string || ! string[*ix]) + return NULL; + + /* Find the end of the token. */ + while( string && string[*ix] && !isspace(string[*ix]) ) { + (*ix)++; + } + + /* Find the end of any whitespace trailing behind + * the token and let that be part of the token */ + while( string && string[*ix] && isspace(string[*ix]) ) { + (*ix)++; + } + + if (! string && *ix==0) { + /* Nothing useful was found */ + return NULL; + } + + token = xmalloc(*ix+1); + token[*ix] = '\0'; + strncpy(token, string, *ix); + + return token; +} + +static int expand_arguments(char *command) +{ + int total_length=0, length, i, retval, ix = 0; + expand_t expand_result; + char *tmpcmd, *cmd, *cmd_copy; + char *src, *dst, *var; + const char *out_of_space = "out of space during expansion"; + int flags = GLOB_NOCHECK +#ifdef GLOB_BRACE + | GLOB_BRACE +#endif +#ifdef GLOB_TILDE + | GLOB_TILDE +#endif + ; + + /* get rid of the terminating \n */ + chomp(command); + + /* Fix up escape sequences to be the Real Thing(tm) */ + while( command && command[ix]) { + if (command[ix] == '\\') { + const char *tmp = command+ix+1; + command[ix] = process_escape_sequence( &tmp ); + memmove(command+ix + 1, tmp, strlen(tmp)+1); + } + ix++; + } + /* Use glob and then fixup environment variables and such */ + + /* It turns out that glob is very stupid. We have to feed it one word at a + * time since it can't cope with a full string. Here we convert command + * (char*) into cmd (char**, one word per string) */ + + /* We need a clean copy, so strsep can mess up the copy while + * we write stuff into the original (in a minute) */ + cmd = cmd_copy = strdup(command); + *command = '\0'; + for (ix = 0, tmpcmd = cmd; + (tmpcmd = strsep_space(cmd, &ix)) != NULL; cmd += ix, ix=0) { + if (*tmpcmd == '\0') + break; + /* we need to trim() the result for glob! */ + trim(tmpcmd); + retval = glob(tmpcmd, flags, NULL, &expand_result); + free(tmpcmd); /* Free mem allocated by strsep_space */ + if (retval == GLOB_NOSPACE) { + /* Mem may have been allocated... */ + globfree (&expand_result); + error_msg(out_of_space); + return FALSE; + } else if (retval != 0) { + /* Some other error. GLOB_NOMATCH shouldn't + * happen because of the GLOB_NOCHECK flag in + * the glob call. */ + error_msg("syntax error"); + return FALSE; + } else { + /* Convert from char** (one word per string) to a simple char*, + * but don't overflow command which is BUFSIZ in length */ + for (i=0; i < expand_result.gl_pathc; i++) { + length=strlen(expand_result.gl_pathv[i]); + if (total_length+length+1 >= BUFSIZ) { + error_msg(out_of_space); + return FALSE; + } + strcat(command+total_length, " "); + total_length+=1; + strcat(command+total_length, expand_result.gl_pathv[i]); + total_length+=length; + } + globfree (&expand_result); + } + } + free(cmd_copy); + trim(command); + + /* Now do the shell variable substitutions which + * wordexp can't do for us, namely $? and $! */ + src = command; + while((dst = strchr(src,'$')) != NULL){ + var = NULL; + switch(*(dst+1)) { + case '?': + var = itoa(last_return_code); + break; + case '!': + if (last_bg_pid==-1) + *(var)='\0'; + else + var = itoa(last_bg_pid); + break; + /* Everything else like $$, $#, $[0-9], etc. should all be + * expanded by wordexp(), so we can in theory skip that stuff + * here, but just to be on the safe side (i.e., since uClibc + * wordexp doesn't do this stuff yet), lets leave it in for + * now. */ + case '$': + var = itoa(getpid()); + break; + case '#': + var = itoa(argc-1); + break; + case '0':case '1':case '2':case '3':case '4': + case '5':case '6':case '7':case '8':case '9': + { + int ixx=*(dst + 1)-48+1; + if (ixx >= argc) { + var='\0'; + } else { + var = argv[ixx]; + } + } + break; + + } + if (var) { + /* a single character construction was found, and + * already handled in the case statement */ + src=dst+2; + } else { + /* Looks like an environment variable */ + char delim_hold; + int num_skip_chars=0; + int dstlen = strlen(dst); + /* Is this a ${foo} type variable? */ + if (dstlen >=2 && *(dst+1) == '{') { + src=strchr(dst+1, '}'); + num_skip_chars=1; + } else { + src=dst+1; + while(isalnum(*src) || *src=='_') src++; + } + if (src == NULL) { + src = dst+dstlen; + } + delim_hold=*src; + *src='\0'; /* temporary */ + var = getenv(dst + 1 + num_skip_chars); + *src=delim_hold; + src += num_skip_chars; + } + if (var == NULL) { + /* Seems we got an un-expandable variable. So delete it. */ + var = ""; + } + { + int subst_len = strlen(var); + int trail_len = strlen(src); + if (dst+subst_len+trail_len >= command+BUFSIZ) { + error_msg(out_of_space); + return FALSE; + } + /* Move stuff to the end of the string to accommodate + * filling the created gap with the new stuff */ + memmove(dst+subst_len, src, trail_len+1); + /* Now copy in the new stuff */ + memcpy(dst, var, subst_len); + src = dst+subst_len; + } + } + + return TRUE; +} + +/* Return cmd->num_progs as 0 if no command is present (e.g. an empty + line). If a valid command is found, command_ptr is set to point to + the beginning of the next command (if the original command had more + then one job associated with it) or NULL if no more commands are + present. */ +static int parse_command(char **command_ptr, struct job *job, int *inbg) +{ + char *command; + char *return_command = NULL; + char *src, *buf, *chptr; + int argc_l = 0; + int done = 0; + int argv_alloced; + int i, saw_quote = 0; + char quote = '\0'; + int count; + struct child_prog *prog; + + /* skip leading white space */ + while (**command_ptr && isspace(**command_ptr)) + (*command_ptr)++; + + /* this handles empty lines or leading '#' characters */ + if (!**command_ptr || (**command_ptr == '#')) { + job->num_progs=0; + return 0; + } + + *inbg = 0; + job->num_progs = 1; + job->progs = xmalloc(sizeof(*job->progs)); + + /* We set the argv elements to point inside of this string. The + memory is freed by free_job(). Allocate twice the original + length in case we need to quote every single character. + + Getting clean memory relieves us of the task of NULL + terminating things and makes the rest of this look a bit + cleaner (though it is, admittedly, a tad less efficient) */ + job->cmdbuf = command = xcalloc(2*strlen(*command_ptr) + 1, sizeof(char)); + job->text = NULL; + + prog = job->progs; + prog->num_redirects = 0; + prog->redirects = NULL; + prog->is_stopped = 0; + prog->family = job; + + argv_alloced = 5; + prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced); + prog->argv[0] = job->cmdbuf; + + buf = command; + src = *command_ptr; + while (*src && !done) { + if (quote == *src) { + quote = '\0'; + } else if (quote) { + if (*src == '\\') { + src++; + if (!*src) { + error_msg("character expected after \\"); + free_job(job); + return 1; + } + + /* in shell, "\'" should yield \' */ + if (*src != quote) { + *buf++ = '\\'; + *buf++ = '\\'; + } + } else if (*src == '*' || *src == '?' || *src == '[' || + *src == ']') *buf++ = '\\'; + *buf++ = *src; + } else if (isspace(*src)) { + if (*prog->argv[argc_l] || saw_quote) { + buf++, argc_l++; + /* +1 here leaves room for the NULL which ends argv */ + if ((argc_l + 1) == argv_alloced) { + argv_alloced += 5; + prog->argv = xrealloc(prog->argv, + sizeof(*prog->argv) * + argv_alloced); + } + prog->argv[argc_l] = buf; + saw_quote = 0; + } + } else + switch (*src) { + case '"': + case '\'': + quote = *src; + saw_quote = 1; + break; + + case '#': /* comment */ + if (*(src-1)== '$') + *buf++ = *src; + else + done = 1; + break; + + case '>': /* redirects */ + case '<': + i = prog->num_redirects++; + prog->redirects = xrealloc(prog->redirects, + sizeof(*prog->redirects) * + (i + 1)); + + prog->redirects[i].fd = -1; + if (buf != prog->argv[argc_l]) { + /* the stuff before this character may be the file number + being redirected */ + prog->redirects[i].fd = + strtol(prog->argv[argc_l], &chptr, 10); + + if (*chptr && *prog->argv[argc_l]) { + buf++, argc_l++; + prog->argv[argc_l] = buf; + } + } + + if (prog->redirects[i].fd == -1) { + if (*src == '>') + prog->redirects[i].fd = 1; + else + prog->redirects[i].fd = 0; + } + + if (*src++ == '>') { + if (*src == '>') + prog->redirects[i].type = + REDIRECT_APPEND, src++; + else + prog->redirects[i].type = REDIRECT_OVERWRITE; + } else { + prog->redirects[i].type = REDIRECT_INPUT; + } + + /* This isn't POSIX sh compliant. Oh well. */ + chptr = src; + while (isspace(*chptr)) + chptr++; + + if (!*chptr) { + error_msg("file name expected after %c", *(src-1)); + free_job(job); + job->num_progs=0; + return 1; + } + + prog->redirects[i].filename = buf; + while (*chptr && !isspace(*chptr)) + *buf++ = *chptr++; + + src = chptr - 1; /* we src++ later */ + prog->argv[argc_l] = ++buf; + break; + + case '|': /* pipe */ + /* finish this command */ + if (*prog->argv[argc_l] || saw_quote) + argc_l++; + if (!argc_l) { + error_msg("empty command in pipe"); + free_job(job); + job->num_progs=0; + return 1; + } + prog->argv[argc_l] = NULL; + + /* and start the next */ + job->num_progs++; + job->progs = xrealloc(job->progs, + sizeof(*job->progs) * job->num_progs); + prog = job->progs + (job->num_progs - 1); + prog->num_redirects = 0; + prog->redirects = NULL; + prog->is_stopped = 0; + prog->family = job; + argc_l = 0; + + argv_alloced = 5; + prog->argv = xmalloc(sizeof(*prog->argv) * argv_alloced); + prog->argv[0] = ++buf; + + src++; + while (*src && isspace(*src)) + src++; + + if (!*src) { + error_msg("empty command in pipe"); + free_job(job); + job->num_progs=0; + return 1; + } + src--; /* we'll ++ it at the end of the loop */ + + break; + + case '&': /* background */ + *inbg = 1; + case ';': /* multiple commands */ + done = 1; + return_command = *command_ptr + (src - *command_ptr) + 1; + break; + + case '\\': + src++; + if (!*src) { + error_msg("character expected after \\"); + free_job(job); + return 1; + } + if (*src == '*' || *src == '[' || *src == ']' + || *src == '?') *buf++ = '\\'; + /* fallthrough */ + default: + *buf++ = *src; + } + + src++; + } + + if (*prog->argv[argc_l] || saw_quote) { + argc_l++; + } + if (!argc_l) { + free_job(job); + return 0; + } + prog->argv[argc_l] = NULL; + + if (!return_command) { + job->text = xmalloc(strlen(*command_ptr) + 1); + strcpy(job->text, *command_ptr); + } else { + /* This leaves any trailing spaces, which is a bit sloppy */ + count = return_command - *command_ptr; + job->text = xmalloc(count + 1); + strncpy(job->text, *command_ptr, count); + job->text[count] = '\0'; + } + + *command_ptr = return_command; + + return 0; +} + +/* Run the child_prog, no matter what kind of command it uses. + */ +static int pseudo_exec(struct child_prog *child) +{ + struct built_in_command *x; +#ifdef BB_FEATURE_SH_STANDALONE_SHELL + char *name; +#endif + + /* Check if the command matches any of the non-forking builtins. + * Depending on context, this might be redundant. But it's + * easier to waste a few CPU cycles than it is to figure out + * if this is one of those cases. + */ + for (x = bltins; x->cmd; x++) { + if (strcmp(child->argv[0], x->cmd) == 0 ) { + _exit(x->function(child)); + } + } + + /* Check if the command matches any of the forking builtins. */ + for (x = bltins_forking; x->cmd; x++) { + if (strcmp(child->argv[0], x->cmd) == 0) { + applet_name=x->cmd; + _exit (x->function(child)); + } + } +#ifdef BB_FEATURE_SH_STANDALONE_SHELL + /* Check if the command matches any busybox internal + * commands ("applets") here. Following discussions from + * November 2000 on busybox@busybox.net, don't use + * get_last_path_component(). This way explicit (with + * slashes) filenames will never be interpreted as an + * applet, just like with builtins. This way the user can + * override an applet with an explicit filename reference. + * The only downside to this change is that an explicit + * /bin/foo invocation will fork and exec /bin/foo, even if + * /bin/foo is a symlink to busybox. + */ + name = child->argv[0]; + +#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN + /* If you enable BB_FEATURE_SH_APPLETS_ALWAYS_WIN, then + * if you run /bin/cat, it will use BusyBox cat even if + * /bin/cat exists on the filesystem and is _not_ busybox. + * Some systems want this, others do not. Choose wisely. :-) + */ + name = get_last_path_component(name); +#endif + + { + char** argv_l=child->argv; + int argc_l; + for(argc_l=0;*argv_l!=NULL; argv_l++, argc_l++); + optind = 1; + run_applet_by_name(name, argc_l, child->argv); + } +#endif + + execvp(child->argv[0], child->argv); + + /* Do not use perror_msg_and_die() here, since we must not + * call exit() but should call _exit() instead */ + fprintf(stderr, "%s: %m\n", child->argv[0]); + _exit(EXIT_FAILURE); +} + +static void insert_job(struct job *newjob, int inbg) +{ + struct job *thejob; + struct jobset *j_list=newjob->job_list; + + /* find the ID for thejob to use */ + newjob->jobid = 1; + for (thejob = j_list->head; thejob; thejob = thejob->next) + if (thejob->jobid >= newjob->jobid) + newjob->jobid = thejob->jobid + 1; + + /* add thejob to the list of running jobs */ + if (!j_list->head) { + thejob = j_list->head = xmalloc(sizeof(*thejob)); + } else { + for (thejob = j_list->head; thejob->next; thejob = thejob->next) /* nothing */; + thejob->next = xmalloc(sizeof(*thejob)); + thejob = thejob->next; + } + + *thejob = *newjob; /* physically copy the struct job */ + thejob->next = NULL; + thejob->running_progs = thejob->num_progs; + thejob->stopped_progs = 0; + + if (inbg) { + /* we don't wait for background thejobs to return -- append it + to the list of backgrounded thejobs and leave it alone */ + printf("[%d] %d\n", thejob->jobid, + newjob->progs[newjob->num_progs - 1].pid); + last_jobid = newjob->jobid; + last_bg_pid=newjob->progs[newjob->num_progs - 1].pid; + } else { + newjob->job_list->fg = thejob; + + /* move the new process group into the foreground */ + /* suppress messages when run from /linuxrc mag@sysgo.de */ + if (tcsetpgrp(shell_terminal, newjob->pgrp) && errno != ENOTTY) + perror_msg("tcsetpgrp"); + } +} + +static int run_command(struct job *newjob, int inbg, int outpipe[2]) +{ + /* struct job *thejob; */ + int i; + int nextin, nextout; + int pipefds[2]; /* pipefd[0] is for reading */ + struct built_in_command *x; + struct child_prog *child; +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &i; + (void) &nextin; + (void) &nextout; +#endif + + nextin = 0, nextout = 1; + for (i = 0; i < newjob->num_progs; i++) { + child = & (newjob->progs[i]); + + if ((i + 1) < newjob->num_progs) { + if (pipe(pipefds)<0) perror_msg_and_die("pipe"); + nextout = pipefds[1]; + } else { + if (outpipe[1]!=-1) { + nextout = outpipe[1]; + } else { + nextout = 1; + } + } + + + /* Check if the command matches any non-forking builtins, + * but only if this is a simple command. + * Non-forking builtins within pipes have to fork anyway, + * and are handled in pseudo_exec. "echo foo | read bar" + * is doomed to failure, and doesn't work on bash, either. + */ + if (newjob->num_progs == 1) { + for (x = bltins; x->cmd; x++) { + if (strcmp(child->argv[0], x->cmd) == 0 ) { + int squirrel[] = {-1, -1, -1}; + int rcode; + setup_redirects(child, squirrel); + rcode = x->function(child); + restore_redirects(squirrel); + return rcode; + } + } + } + + if (!(child->pid = fork())) + { + /* Set the handling for job control signals back to the default. */ + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGTSTP, SIG_DFL); + signal(SIGTTIN, SIG_DFL); + signal(SIGTTOU, SIG_DFL); + signal(SIGCHLD, SIG_DFL); + + close_all(); + + if (outpipe[1]!=-1) { + close(outpipe[0]); + } + if (nextin != 0) { + dup2(nextin, 0); + close(nextin); + } + + if (nextout != 1) { + dup2(nextout, 1); + dup2(nextout, 2); /* Really? */ + close(nextout); + close(pipefds[0]); + } + + /* explicit redirects override pipes */ + setup_redirects(child,NULL); + + pseudo_exec(child); + } + if (outpipe[1]!=-1) { + close(outpipe[1]); + } + + /* put our child in the process group whose leader is the + first process in this pipe */ + setpgid(child->pid, newjob->progs[0].pid); + if (nextin != 0) + close(nextin); + if (nextout != 1) + close(nextout); + + /* If there isn't another process, nextin is garbage + but it doesn't matter */ + nextin = pipefds[0]; + } + + newjob->pgrp = newjob->progs[0].pid; + + insert_job(newjob, inbg); + + return 0; +} + +static int busy_loop(FILE * input) +{ + char *command; + char *next_command = NULL; + struct job newjob; + pid_t parent_pgrp; + int i; + int inbg; + int status; + newjob.job_list = &job_list; + newjob.job_context = DEFAULT_CONTEXT; + + /* save current owner of TTY so we can restore it on exit */ + parent_pgrp = tcgetpgrp(shell_terminal); + + command = (char *) xcalloc(BUFSIZ, sizeof(char)); + + while (1) { + if (!job_list.fg) { + /* no job is in the foreground */ + + /* see if any background processes have exited */ + checkjobs(&job_list); + + if (!next_command) { + if (get_command(input, command)) + break; + next_command = command; + } + + if (expand_arguments(next_command) == FALSE) { + free(command); + command = (char *) xcalloc(BUFSIZ, sizeof(char)); + next_command = NULL; + continue; + } + + if (!parse_command(&next_command, &newjob, &inbg) && + newjob.num_progs) { + int pipefds[2] = {-1,-1}; + debug_printf( "job=%p fed to run_command by busy_loop()'\n", + &newjob); + run_command(&newjob, inbg, pipefds); + } + else { + free(command); + command = (char *) xcalloc(BUFSIZ, sizeof(char)); + next_command = NULL; + } + } else { + /* a job is running in the foreground; wait for it */ + i = 0; + while (!job_list.fg->progs[i].pid || + job_list.fg->progs[i].is_stopped == 1) i++; + + if (waitpid(job_list.fg->progs[i].pid, &status, WUNTRACED)<0) { + if (errno != ECHILD) { + perror_msg_and_die("waitpid(%d)",job_list.fg->progs[i].pid); + } + } + + if (WIFEXITED(status) || WIFSIGNALED(status)) { + /* the child exited */ + job_list.fg->running_progs--; + job_list.fg->progs[i].pid = 0; + + last_return_code=WEXITSTATUS(status); + + if (!job_list.fg->running_progs) { + /* child exited */ + remove_job(&job_list, job_list.fg); + job_list.fg = NULL; + } + } else { + /* the child was stopped */ + job_list.fg->stopped_progs++; + job_list.fg->progs[i].is_stopped = 1; + + if (job_list.fg->stopped_progs == job_list.fg->running_progs) { + printf("\n" JOB_STATUS_FORMAT, job_list.fg->jobid, + "Stopped", job_list.fg->text); + job_list.fg = NULL; + } + } + + if (!job_list.fg) { + /* move the shell to the foreground */ + /* suppress messages when run from /linuxrc mag@sysgo.de */ + if (tcsetpgrp(shell_terminal, getpgrp()) && errno != ENOTTY) + perror_msg("tcsetpgrp"); + } + } + } + free(command); + + /* return controlling TTY back to parent process group before exiting */ + if (tcsetpgrp(shell_terminal, parent_pgrp) && errno != ENOTTY) + perror_msg("tcsetpgrp"); + + /* return exit status if called with "-c" */ + if (input == NULL && WIFEXITED(status)) + return WEXITSTATUS(status); + + return 0; +} + + +#ifdef BB_FEATURE_CLEAN_UP +void free_memory(void) +{ + if (cwd && cwd!=unknown) { + free((char*)cwd); + } + if (local_pending_command) + free(local_pending_command); + + if (job_list.fg && !job_list.fg->running_progs) { + remove_job(&job_list, job_list.fg); + } +} +#endif + +/* Make sure we have a controlling tty. If we get started under a job + * aware app (like bash for example), make sure we are now in charge so + * we don't fight over who gets the foreground */ +static void setup_job_control() +{ + int status; + + /* Loop until we are in the foreground. */ + while ((status = tcgetpgrp (shell_terminal)) >= 0) { + if (status == (shell_pgrp = getpgrp ())) { + break; + } + kill (- shell_pgrp, SIGTTIN); + } + + /* Ignore interactive and job-control signals. */ + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + signal(SIGCHLD, SIG_IGN); + + /* Put ourselves in our own process group. */ + setsid(); + shell_pgrp = getpid (); + setpgid (shell_pgrp, shell_pgrp); + + /* Grab control of the terminal. */ + tcsetpgrp(shell_terminal, shell_pgrp); +} + +int lash_main(int argc_l, char **argv_l) +{ + int opt, interactive=FALSE; + FILE *input = stdin; + argc = argc_l; + argv = argv_l; + + /* These variables need re-initializing when recursing */ + last_jobid = 0; + local_pending_command = NULL; + close_me_head = NULL; + job_list.head = NULL; + job_list.fg = NULL; + last_return_code=1; + + if (argv[0] && argv[0][0] == '-') { + FILE *prof_input; + prof_input = fopen("/etc/profile", "r"); + if (prof_input) { + int tmp_fd = fileno(prof_input); + mark_open(tmp_fd); + /* Now run the file */ + busy_loop(prof_input); + fclose(prof_input); + mark_closed(tmp_fd); + } + } + + while ((opt = getopt(argc_l, argv_l, "cxi")) > 0) { + switch (opt) { + case 'c': + input = NULL; + if (local_pending_command != 0) + error_msg_and_die("multiple -c arguments"); + local_pending_command = xstrdup(argv[optind]); + optind++; + argv = argv+optind; + break; + case 'i': + interactive = TRUE; + break; + default: + show_usage(); + } + } + /* A shell is interactive if the `-i' flag was given, or if all of + * the following conditions are met: + * no -c command + * no arguments remaining or the -s flag given + * standard input is a terminal + * standard output is a terminal + * Refer to Posix.2, the description of the `sh' utility. */ + if (argv[optind]==NULL && input==stdin && + isatty(fileno(stdin)) && isatty(fileno(stdout))) { + interactive=TRUE; + } + setup_job_control(); + if (interactive==TRUE) { + //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]); + /* Looks like they want an interactive shell */ + printf( "\n\n" BB_BANNER " Built-in shell (lash)\n"); + printf( "Enter 'help' for a list of built-in commands.\n\n"); + } else if (local_pending_command==NULL) { + //printf( "optind=%d argv[optind]='%s'\n", optind, argv[optind]); + input = xfopen(argv[optind], "r"); + mark_open(fileno(input)); /* be lazy, never mark this closed */ + } + + /* initialize the cwd -- this is never freed...*/ + cwd = xgetcwd(0); + if (!cwd) + cwd = unknown; + +#ifdef BB_FEATURE_CLEAN_UP + atexit(free_memory); +#endif + +#ifdef BB_FEATURE_COMMAND_EDITING + cmdedit_set_initial_prompt(); +#else + PS1 = NULL; +#endif + + return (busy_loop(input)); +} diff --git a/length.c b/length.c new file mode 100644 index 000000000..73becd28a --- /dev/null +++ b/length.c @@ -0,0 +1,13 @@ +/* vi: set sw=4 ts=4: */ +#include +#include +#include +#include "busybox.h" + +extern int length_main(int argc, char **argv) +{ + if (argc != 2 || **(argv + 1) == '-') + show_usage(); + printf("%lu\n", (long)strlen(argv[1])); + return EXIT_SUCCESS; +} diff --git a/libbb/.cvsignore b/libbb/.cvsignore new file mode 100644 index 000000000..2bbe016f5 --- /dev/null +++ b/libbb/.cvsignore @@ -0,0 +1 @@ +loop.h diff --git a/libbb/Makefile b/libbb/Makefile new file mode 100644 index 000000000..2c8ab2b5d --- /dev/null +++ b/libbb/Makefile @@ -0,0 +1,11 @@ +# Silly wrapper makefile. This Makefile is _not_ used by the build system for +# busybox, it is just to make working on libbb more conveinient. +# -Erik Andersen + +all: + make -C .. libbb.a + +clean: + - rm -rf libbb.a + - find . -name \*.o -exec rm -f {} \; + diff --git a/libbb/README b/libbb/README new file mode 100644 index 000000000..38934c292 --- /dev/null +++ b/libbb/README @@ -0,0 +1,14 @@ +Please see the LICENSE file for copyright information. + +libbb is BusyBox's utility library. This all used to be in a single file +(utility.c to be specific). When I split utility.c up to create libbb, I did +not carefully fix up the copyright and licensing information. I'll do that for +the next release. + +For now, just trust me that a bunch of people have worked on this stuff, +and it is all GPL'ed. + + Erik Andersen + + + diff --git a/libbb/arith.c b/libbb/arith.c new file mode 100644 index 000000000..e5b3213cb --- /dev/null +++ b/libbb/arith.c @@ -0,0 +1,376 @@ +/* Copyright (c) 2001 Aaron Lehmann + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/* This is my infix parser/evaluator. It is optimized for size, intended + * as a replacement for yacc-based parsers. However, it may well be faster + * than a comparable parser writen in yacc. The supported operators are + * listed in #defines below. Parens, order of operations, and error handling + * are supported. This code is threadsafe. The exact expression format should + * be that which POSIX specifies for shells. */ + +/* The code uses a simple two-stack algorithm. See + * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html + * for a detailed explaination of the infix-to-postfix algorithm on which + * this is based (this code differs in that it applies operators immediately + * to the stack instead of adding them to a queue to end up with an + * expression). */ + +/* To use the routine, call it with an expression string and error return + * pointer */ + +/* + * Aug 24, 2001 Manuel Novoa III + * + * Reduced the generated code size by about 30% (i386) and fixed several bugs. + * + * 1) In arith_apply(): + * a) Cached values of *numptr and &(numptr[-1]). + * b) Removed redundant test for zero denominator. + * + * 2) In arith(): + * a) Eliminated redundant code for processing operator tokens by moving + * to a table-based implementation. Also folded handling of parens + * into the table. + * b) Combined all 3 loops which called arith_apply to reduce generated + * code size at the cost of speed. + * + * 3) The following expressions were treated as valid by the original code: + * 1() , 0! , 1 ( *3 ) . + * These bugs have been fixed by internally enclosing the expression in + * parens and then checking that all binary ops and right parens are + * preceded by a valid expression (NUM_TOKEN). + * + * Note: It may be desireable to replace Aaron's test for whitespace with + * ctype's isspace() if it is used by another busybox applet or if additional + * whitespace chars should be considered. Look below the "#include"s for a + * precompiler test. + */ + +/* + * Aug 26, 2001 Manuel Novoa III + * + * Return 0 for null expressions. Pointed out by vodz. + * + * Merge in Aaron's comments previously posted to the busybox list, + * modified slightly to take account of my changes to the code. + * + * TODO: May want to allow access to variables in the arith code. + * This would: + * 1) allow us to evaluate $A as 0 if A isn't set (although this + * would require changes to ash.c too). + * 2) allow us to write expressions as $(( A + 2 )). + * This could be done using a callback function passed to the + * arith() function of by requiring such a function with fixed + * name as an extern. + */ + +#include +#include +#include +#include +#include "libbb.h" + +/* + * Use "#if 1" below for Aaron's original test for whitespace. + * Use "#if 0" for ctype's isspace(). + * */ +#if 1 +#undef isspace +#define isspace(arithval) \ + (arithval == ' ' || arithval == '\n' || arithval == '\t') +#endif + +typedef char operator; + +/* An operator's token id is a bit of a bitfield. The lower 5 bits are the + * precedence, and high 3 are an ID unique accross operators of that + * precedence. The ID portion is so that multiple operators can have the + * same precedence, ensuring that the leftmost one is evaluated first. + * Consider * and /. */ + +#define tok_decl(prec,id) (((id)<<5)|(prec)) +#define PREC(op) ((op)&0x1F) + +#define TOK_LPAREN tok_decl(0,0) + +#define TOK_OR tok_decl(1,0) + +#define TOK_AND tok_decl(2,0) + +#define TOK_BOR tok_decl(3,0) + +#define TOK_BXOR tok_decl(4,0) + +#define TOK_BAND tok_decl(5,0) + +#define TOK_EQ tok_decl(6,0) +#define TOK_NE tok_decl(6,1) + +#define TOK_LT tok_decl(7,0) +#define TOK_GT tok_decl(7,1) +#define TOK_GE tok_decl(7,2) +#define TOK_LE tok_decl(7,3) + +#define TOK_LSHIFT tok_decl(8,0) +#define TOK_RSHIFT tok_decl(8,1) + +#define TOK_ADD tok_decl(9,0) +#define TOK_SUB tok_decl(9,1) + +#define TOK_MUL tok_decl(10,0) +#define TOK_DIV tok_decl(10,1) +#define TOK_REM tok_decl(10,2) + +/* For now all unary operators have the same precedence, and that's used to + * identify them as unary operators */ +#define UNARYPREC 14 +#define TOK_BNOT tok_decl(UNARYPREC,0) +#define TOK_NOT tok_decl(UNARYPREC,1) +#define TOK_UMINUS tok_decl(UNARYPREC,2) +#define TOK_UPLUS tok_decl(UNARYPREC,3) + +#define TOK_NUM tok_decl(15,0) +#define TOK_RPAREN tok_decl(15,1) +#define TOK_ERROR tok_decl(15,2) /* just a place-holder really */ + +#define ARITH_APPLY(op) arith_apply(op, numstack, &numstackptr) +#define NUMPTR (*numstackptr) + +/* "applying" a token means performing it on the top elements on the integer + * stack. For a unary operator it will only change the top element, but a + * binary operator will pop two arguments and push a result */ +static short arith_apply(operator op, long *numstack, long **numstackptr) +{ + long numptr_val; + long *NUMPTR_M1; + + if (NUMPTR == numstack) goto err; /* There is no operator that can work + without arguments */ + NUMPTR_M1 = NUMPTR - 1; + if (op == TOK_UMINUS) + *NUMPTR_M1 *= -1; + else if (op == TOK_NOT) + *NUMPTR_M1 = !(*NUMPTR_M1); + else if (op == TOK_BNOT) + *NUMPTR_M1 = ~(*NUMPTR_M1); + else if (op != TOK_UPLUS) { + /* Binary operators */ + if (NUMPTR_M1 == numstack) goto err; /* ... and binary operators need two + arguments */ + numptr_val = *--NUMPTR; /* ... and they pop one */ + NUMPTR_M1 = NUMPTR - 1; + if (op == TOK_BOR) + *NUMPTR_M1 |= numptr_val; + else if (op == TOK_OR) + *NUMPTR_M1 = numptr_val || *NUMPTR_M1; + else if (op == TOK_BAND) + *NUMPTR_M1 &= numptr_val; + else if (op == TOK_AND) + *NUMPTR_M1 = *NUMPTR_M1 && numptr_val; + else if (op == TOK_EQ) + *NUMPTR_M1 = (*NUMPTR_M1 == numptr_val); + else if (op == TOK_NE) + *NUMPTR_M1 = (*NUMPTR_M1 != numptr_val); + else if (op == TOK_GE) + *NUMPTR_M1 = (*NUMPTR_M1 >= numptr_val); + else if (op == TOK_RSHIFT) + *NUMPTR_M1 >>= numptr_val; + else if (op == TOK_LSHIFT) + *NUMPTR_M1 <<= numptr_val; + else if (op == TOK_GT) + *NUMPTR_M1 = (*NUMPTR_M1 > numptr_val); + else if (op == TOK_LT) + *NUMPTR_M1 = (*NUMPTR_M1 < numptr_val); + else if (op == TOK_LE) + *NUMPTR_M1 = (*NUMPTR_M1 <= numptr_val); + else if (op == TOK_MUL) + *NUMPTR_M1 *= numptr_val; + else if (op == TOK_ADD) + *NUMPTR_M1 += numptr_val; + else if (op == TOK_SUB) + *NUMPTR_M1 -= numptr_val; + else if(numptr_val==0) /* zero divisor check */ + return -2; + else if (op == TOK_DIV) + *NUMPTR_M1 /= numptr_val; + else if (op == TOK_REM) + *NUMPTR_M1 %= numptr_val; + /* WARNING!!! WARNING!!! WARNING!!! */ + /* Any new operators should be added BEFORE the zero divisor check! */ + } + return 0; +err: return(-1); +} + +static const char endexpression[] = ")"; + +/* + and - (in that order) must be last */ +static const char op_char[] = "!<>=|&*/%~()+-"; +static const char op_token[] = { + /* paired with equal */ + TOK_NE, TOK_LE, TOK_GE, + /* paired with self -- note: ! is special-cased below*/ + TOK_ERROR, TOK_LSHIFT, TOK_RSHIFT, TOK_EQ, TOK_OR, TOK_AND, + /* singles */ + TOK_NOT, TOK_LT, TOK_GT, TOK_ERROR, TOK_BOR, TOK_BAND, + TOK_MUL, TOK_DIV, TOK_REM, TOK_BNOT, TOK_LPAREN, TOK_RPAREN, + TOK_ADD, TOK_SUB, TOK_UPLUS, TOK_UMINUS +}; + +#define NUM_PAIR_EQUAL 3 +#define NUM_PAIR_SAME 6 + +extern long arith (const char *expr, int *errcode) +{ + register char arithval; /* Current character under analysis */ + operator lasttok, op; + unsigned char prec; + + const char *p = endexpression; + + size_t datasizes = strlen(expr) + 2; + + /* Stack of integers */ + /* The proof that there can be no more than strlen(startbuf)/2+1 integers + * in any given correct or incorrect expression is left as an excersize to + * the reader. */ + long *numstack = alloca(((datasizes)/2)*sizeof(long)), + *numstackptr = numstack; + /* Stack of operator tokens */ + operator *stack = alloca((datasizes) * sizeof(operator)), + *stackptr = stack; + + *numstack = 0; + *stackptr++ = lasttok = TOK_LPAREN; /* start off with a left paren */ + + loop: + if ((arithval = *expr) == 0) { + if (p == endexpression) { /* Null expression. */ + *errcode = 0; + return *numstack; + } + + /* This is only reached after all tokens have been extracted from the + * input stream. If there are still tokens on the operator stack, they + * are to be applied in order. At the end, there should be a final + * result on the integer stack */ + + if (expr != endexpression + 1) { /* If we haven't done so already, */ + expr = endexpression; /* append a closing right paren */ + goto loop; /* and let the loop process it. */ + } + /* At this point, we're done with the expression. */ + if (numstackptr != numstack+1) {/* ... but if there isn't, it's bad */ + err: + return (*errcode = -1); + /* NOTREACHED */ + } + return *numstack; + } else { + /* Continue processing the expression. */ + if (isspace(arithval)) { + goto prologue; /* Skip whitespace */ + } + if ((unsigned)arithval-'0' <= 9) /* isdigit */ { + *numstackptr++ = strtol(expr, (char **) &expr, 10); + lasttok = TOK_NUM; + goto loop; + } +#if 1 + if ((p = strchr(op_char, arithval)) == NULL) { + goto err; + } +#else + for ( p=op_char ; *p != arithval ; p++ ) { + if (!*p) { + goto err; + } + } +#endif + p = op_token + (int)(p - op_char); + ++expr; + if ((p >= op_token + NUM_PAIR_EQUAL) || (*expr != '=')) { + p += NUM_PAIR_EQUAL; + if ((p >= op_token + NUM_PAIR_SAME + NUM_PAIR_EQUAL) + || (*expr != arithval) || (arithval == '!')) { + --expr; + if (arithval == '=') { /* single = */ + goto err; + } + p += NUM_PAIR_SAME; + /* Plus and minus are binary (not unary) _only_ if the last + * token was as number, or a right paren (which pretends to be + * a number, since it evaluates to one). Think about it. + * It makes sense. */ + if ((lasttok != TOK_NUM) + && (p >= op_token + NUM_PAIR_SAME + NUM_PAIR_EQUAL + + sizeof(op_char) - 2)) { + p += 2; /* Unary plus or minus */ + } + } + } + op = *p; + + /* We don't want a unary operator to cause recursive descent on the + * stack, because there can be many in a row and it could cause an + * operator to be evaluated before its argument is pushed onto the + * integer stack. */ + /* But for binary operators, "apply" everything on the operator + * stack until we find an operator with a lesser priority than the + * one we have just extracted. */ + /* Left paren is given the lowest priority so it will never be + * "applied" in this way */ + prec = PREC(op); + if ((prec > 0) && (prec != UNARYPREC)) { /* not left paren or unary */ + if (lasttok != TOK_NUM) { /* binary op must be preceded by a num */ + goto err; + } + while (stackptr != stack) { + if (op == TOK_RPAREN) { + /* The algorithm employed here is simple: while we don't + * hit an open paren nor the bottom of the stack, pop + * tokens and apply them */ + if (stackptr[-1] == TOK_LPAREN) { + --stackptr; + lasttok = TOK_NUM; /* Any operator directly after a */ + /* close paren should consider itself binary */ + goto prologue; + } + } else if (PREC(stackptr[-1]) < prec) { + break; + } + *errcode = ARITH_APPLY(*--stackptr); + if(*errcode) return *errcode; + } + if (op == TOK_RPAREN) { + goto err; + } + } + + /* Push this operator to the stack and remember it. */ + *stackptr++ = lasttok = op; + + prologue: + ++expr; + goto loop; + } +} diff --git a/libbb/ask_confirmation.c b/libbb/ask_confirmation.c new file mode 100644 index 000000000..d4d943ad7 --- /dev/null +++ b/libbb/ask_confirmation.c @@ -0,0 +1,49 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 "libbb.h" + + +int ask_confirmation() +{ + int c = '\0'; + int ret = 0; + + while (c != '\n') { + c = getchar(); + if ( c != '\n' ) { + ret = ((c=='y')||(c=='Y')) ? 1 : 0; + } + } + return ret; +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/chomp.c b/libbb/chomp.c new file mode 100644 index 000000000..94404a98d --- /dev/null +++ b/libbb/chomp.c @@ -0,0 +1,45 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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" + + +void chomp(char *s) +{ + char *lc = last_char_is(s, '\n'); + + if(lc) + *lc = 0; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/concat_path_file.c b/libbb/concat_path_file.c new file mode 100644 index 000000000..e62b99ef6 --- /dev/null +++ b/libbb/concat_path_file.c @@ -0,0 +1,45 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 + */ + +/* concatenate path and file name to new allocation buffer, + * not addition '/' if path name already have '/' +*/ + +#include +#include "libbb.h" + +extern char *concat_path_file(const char *path, const char *filename) +{ + char *outbuf; + char *lc; + + if (!path) + path=""; + lc = last_char_is(path, '/'); + while (*filename == '/') + filename++; + outbuf = xmalloc(strlen(path)+strlen(filename)+1+(lc==NULL)); + sprintf(outbuf, "%s%s%s", path, (lc==NULL)? "/" : "", filename); + + return outbuf; +} diff --git a/libbb/copy_file.c b/libbb/copy_file.c new file mode 100644 index 000000000..f24fa01d2 --- /dev/null +++ b/libbb/copy_file.c @@ -0,0 +1,271 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini copy_file implementation for busybox + * + * 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libbb.h" + +#define CONFIG_FEATURE_PRESERVE_HARDLINKS + +int copy_file(const char *source, const char *dest, int flags) +{ + struct stat source_stat; + struct stat dest_stat; + int dest_exists = 0; + int status = 0; + + if ((!(flags & FILEUTILS_PRESERVE_SYMLINKS) && + stat(source, &source_stat) < 0) || + ((flags & FILEUTILS_PRESERVE_SYMLINKS) && + lstat(source, &source_stat) < 0)) { + perror_msg("%s", source); + return -1; + } + + if (lstat(dest, &dest_stat) < 0) { + if (errno != ENOENT) { + perror_msg("unable to stat `%s'", dest); + return -1; + } + } else { + if (source_stat.st_dev == dest_stat.st_dev && + source_stat.st_ino == dest_stat.st_ino) { + error_msg("`%s' and `%s' are the same file", source, dest); + return -1; + } + dest_exists = 1; + } + + if (S_ISDIR(source_stat.st_mode)) { + DIR *dp; + struct dirent *d; + mode_t saved_umask = 0; + + if (!(flags & FILEUTILS_RECUR)) { + error_msg("%s: omitting directory", source); + return -1; + } + + /* Create DEST. */ + if (dest_exists) { + if (!S_ISDIR(dest_stat.st_mode)) { + error_msg("`%s' is not a directory", dest); + return -1; + } + } else { + mode_t mode; + saved_umask = umask(0); + + mode = source_stat.st_mode; + if (!(flags & FILEUTILS_PRESERVE_STATUS)) + mode = source_stat.st_mode & ~saved_umask; + mode |= S_IRWXU; + + if (mkdir(dest, mode) < 0) { + umask(saved_umask); + perror_msg("cannot create directory `%s'", dest); + return -1; + } + + umask(saved_umask); + } + + /* Recursively copy files in SOURCE. */ + if ((dp = opendir(source)) == NULL) { + perror_msg("unable to open directory `%s'", source); + status = -1; + goto end; + } + + while ((d = readdir(dp)) != NULL) { + char *new_source, *new_dest; + + if (strcmp(d->d_name, ".") == 0 || + strcmp(d->d_name, "..") == 0) + continue; + + new_source = concat_path_file(source, d->d_name); + new_dest = concat_path_file(dest, d->d_name); + if (copy_file(new_source, new_dest, flags) < 0) + status = -1; + free(new_source); + free(new_dest); + } + /* closedir have only EBADF error, but "dp" not changes */ + closedir(dp); + + if (!dest_exists && + chmod(dest, source_stat.st_mode & ~saved_umask) < 0) { + perror_msg("unable to change permissions of `%s'", dest); + status = -1; + } + } else if (S_ISREG(source_stat.st_mode)) { + FILE *sfp, *dfp=NULL; +#ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS + char *link_name; + + if (!(flags & FILEUTILS_PRESERVE_SYMLINKS) && + is_in_ino_dev_hashtable(&source_stat, &link_name)) { + if (link(link_name, dest) < 0) { + perror_msg("unable to link `%s'", dest); + return -1; + } + + return 0; + } +#endif + + if ((sfp = wfopen(source, "r")) == NULL) { + return -1; + } + + if (dest_exists) { + if (flags & FILEUTILS_INTERACTIVE) { + fprintf(stderr, "%s: overwrite `%s'? ", applet_name, dest); + if (!ask_confirmation()) { + fclose (sfp); + return 0; + } + } + + if ((dfp = fopen(dest, "w")) == NULL) { + if (!(flags & FILEUTILS_FORCE)) { + perror_msg("unable to open `%s'", dest); + fclose (sfp); + return -1; + } + + if (unlink(dest) < 0) { + perror_msg("unable to remove `%s'", dest); + fclose (sfp); + return -1; + } + + dest_exists = 0; + } + } + + if (!dest_exists) { + int fd; + + if ((fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode)) < 0 || + (dfp = fdopen(fd, "w")) == NULL) { + if (fd >= 0) + close(fd); + perror_msg("unable to open `%s'", dest); + fclose (sfp); + return -1; + } + } + + if (copy_file_chunk(sfp, dfp, -1) < 0) + status = -1; + + if (fclose(dfp) < 0) { + perror_msg("unable to close `%s'", dest); + status = -1; + } + + if (fclose(sfp) < 0) { + perror_msg("unable to close `%s'", source); + status = -1; + } + } + else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) || + S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode) || + S_ISLNK(source_stat.st_mode)) { + + if (dest_exists && + ((flags & FILEUTILS_FORCE) == 0 || unlink(dest) < 0)) { + perror_msg("unable to remove `%s'", dest); + return -1; + + } + } else { + error_msg("internal error: unrecognized file type"); + return -1; + } + if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) || + S_ISSOCK(source_stat.st_mode)) { + if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { + perror_msg("unable to create `%s'", dest); + return -1; + } + } else if (S_ISFIFO(source_stat.st_mode)) { + if (mkfifo(dest, source_stat.st_mode) < 0) { + perror_msg("cannot create fifo `%s'", dest); + return -1; + } + } else if (S_ISLNK(source_stat.st_mode)) { + char *lpath; + + lpath = xreadlink(source); + if (symlink(lpath, dest) < 0) { + perror_msg("cannot create symlink `%s'", dest); + return -1; + } + free(lpath); + +#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) + if (flags & FILEUTILS_PRESERVE_STATUS) + if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0) + perror_msg("unable to preserve ownership of `%s'", dest); +#endif + +#ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS + add_to_ino_dev_hashtable(&source_stat, dest); +#endif + + return 0; + } + +#ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS + add_to_ino_dev_hashtable(&source_stat, dest); +#endif + +end: + + if (flags & FILEUTILS_PRESERVE_STATUS) { + struct utimbuf times; + + times.actime = source_stat.st_atime; + times.modtime = source_stat.st_mtime; + if (utime(dest, ×) < 0) + perror_msg("unable to preserve times of `%s'", dest); + if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { + source_stat.st_mode &= ~(S_ISUID | S_ISGID); + perror_msg("unable to preserve ownership of `%s'", dest); + } + if (chmod(dest, source_stat.st_mode) < 0) + perror_msg("unable to preserve permissions of `%s'", dest); + } + + return status; +} diff --git a/libbb/copy_file_chunk.c b/libbb/copy_file_chunk.c new file mode 100644 index 000000000..63d2ab173 --- /dev/null +++ b/libbb/copy_file_chunk.c @@ -0,0 +1,70 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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" + +/* Copy CHUNKSIZE bytes (or until EOF if CHUNKSIZE equals -1) from SRC_FILE + * to DST_FILE. */ +extern int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize) +{ + size_t nread, nwritten, size; + char buffer[BUFSIZ]; + + while (chunksize != 0) { + if (chunksize > BUFSIZ) + size = BUFSIZ; + else + size = chunksize; + + nread = fread (buffer, 1, size, src_file); + + if (nread != size && ferror (src_file)) { + perror_msg ("read"); + return -1; + } else if (nread == 0) { + if (chunksize != -1) { + error_msg ("Unable to read all data"); + return -1; + } + + return 0; + } + + nwritten = fwrite (buffer, 1, nread, dst_file); + + if (nwritten != nread) { + if (ferror (dst_file)) + perror_msg ("write"); + else + error_msg ("Unable to write all data"); + return -1; + } + + if (chunksize != -1) + chunksize -= nwritten; + } + + return 0; +} diff --git a/libbb/copyfd.c b/libbb/copyfd.c new file mode 100644 index 000000000..aa938d105 --- /dev/null +++ b/libbb/copyfd.c @@ -0,0 +1,59 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999-2001 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 "libbb.h" + + +extern int copyfd(int fd1, int fd2) +{ + char buf[8192]; + ssize_t nread, nwrote; + + while (1) { + nread = safe_read(fd1, buf, sizeof(buf)); + if (nread == 0) + break; + if (nread == -1) { + perror_msg("read"); + return -1; + } + + nwrote = full_write(fd2, buf, nread); + if (nwrote == -1) { + perror_msg("write"); + return -1; + } + } + + return 0; +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/create_icmp_socket.c b/libbb/create_icmp_socket.c new file mode 100644 index 000000000..d804b3987 --- /dev/null +++ b/libbb/create_icmp_socket.c @@ -0,0 +1,37 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * create raw socket for icmp protocol test permision + * and drop root privilegies if running setuid + * + */ + +#include +#include +#include +#include +#include +#include "libbb.h" + +int create_icmp_socket(void) +{ + struct protoent *proto; + int sock; + + proto = getprotobyname("icmp"); + /* if getprotobyname failed, just silently force + * proto->p_proto to have the correct value for "icmp" */ + if ((sock = socket(AF_INET, SOCK_RAW, + (proto ? proto->p_proto : 1))) < 0) { /* 1 == ICMP */ + if (errno == EPERM) + error_msg_and_die("permission denied. (are you root?)"); + else + perror_msg_and_die(can_not_create_raw_socket); + } + + /* drop root privs if running setuid */ + setuid(getuid()); + + return sock; +} diff --git a/libbb/device_open.c b/libbb/device_open.c new file mode 100644 index 000000000..30b33d7f0 --- /dev/null +++ b/libbb/device_open.c @@ -0,0 +1,53 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include "libbb.h" + + +/* try to open up the specified device */ +extern int device_open(char *device, int mode) +{ + int m, f, fd = -1; + + m = mode | O_NONBLOCK; + + /* Retry up to 5 times */ + for (f = 0; f < 5; f++) + if ((fd = open(device, m, 0600)) >= 0) + break; + if (fd < 0) + return fd; + /* Reset original flags. */ + if (m != mode) + fcntl(fd, F_SETFL, mode); + return fd; +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/dirname.c b/libbb/dirname.c new file mode 100644 index 000000000..2aebd3815 --- /dev/null +++ b/libbb/dirname.c @@ -0,0 +1,55 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini dirname function. + * + * 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 + */ + +#include +#include "libbb.h" + +#if defined __GNU_LIBRARY___ < 5 + +/* Return a string containing the path name of the parent + * directory of PATH. */ + +char *dirname(char *path) +{ + char *s; + + /* Go to the end of the string. */ + s = path + strlen(path) - 1; + + /* Strip off trailing /s (unless it is also the leading /). */ + while (path < s && s[0] == '/') + s--; + + /* Strip the last component. */ + while (path <= s && s[0] != '/') + s--; + + while (path < s && s[0] == '/') + s--; + + if (s < path) + return "."; + + s[1] = '\0'; + return path; +} + +#endif diff --git a/libbb/error_msg.c b/libbb/error_msg.c new file mode 100644 index 000000000..58308b6be --- /dev/null +++ b/libbb/error_msg.c @@ -0,0 +1,46 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include +#include +#include "libbb.h" + +extern void error_msg(const char *s, ...) +{ + va_list p; + + va_start(p, s); + verror_msg(s, p); + va_end(p); + putc('\n', stderr); +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/error_msg_and_die.c b/libbb/error_msg_and_die.c new file mode 100644 index 000000000..67a79c375 --- /dev/null +++ b/libbb/error_msg_and_die.c @@ -0,0 +1,47 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include +#include +#include "libbb.h" + +extern void error_msg_and_die(const char *s, ...) +{ + va_list p; + + va_start(p, s); + verror_msg(s, p); + va_end(p); + putc('\n', stderr); + exit(EXIT_FAILURE); +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/fgets_str.c b/libbb/fgets_str.c new file mode 100644 index 000000000..6588f9482 --- /dev/null +++ b/libbb/fgets_str.c @@ -0,0 +1,67 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 "libbb.h" + +/* Read up to (and including) TERMINATING_STRING from FILE and return it. + * Return NULL on EOF. */ + +char *fgets_str(FILE *file, const char *terminating_string) +{ + char *linebuf = NULL; + const int term_length = strlen(terminating_string); + int end_string_offset; + int linebufsz = 0; + int idx = 0; + int ch; + + while (1) { + ch = fgetc(file); + if (ch == EOF) { + free(linebuf); + return NULL; + } + + /* grow the line buffer as necessary */ + while (idx > linebufsz - 2) { + linebuf = xrealloc(linebuf, linebufsz += 1000); + } + + linebuf[idx] = ch; + idx++; + + /* Check for terminating string */ + end_string_offset = idx - term_length; + if ((end_string_offset > 0) && (memcmp(&linebuf[end_string_offset], terminating_string, term_length) == 0)) { + idx -= term_length; + break; + } + } + linebuf[idx] = '\0'; + return(linebuf); +} + diff --git a/libbb/find_mount_point.c b/libbb/find_mount_point.c new file mode 100644 index 000000000..1eb5dc942 --- /dev/null +++ b/libbb/find_mount_point.c @@ -0,0 +1,75 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include "libbb.h" + + +#include +/* + * Given a block device, find the mount table entry if that block device + * is mounted. + * + * Given any other file (or directory), find the mount table entry for its + * filesystem. + */ +extern struct mntent *find_mount_point(const char *name, const char *table) +{ + struct stat s; + dev_t mountDevice; + FILE *mountTable; + struct mntent *mountEntry; + + if (stat(name, &s) != 0) + return 0; + + if ((s.st_mode & S_IFMT) == S_IFBLK) + mountDevice = s.st_rdev; + else + mountDevice = s.st_dev; + + + if ((mountTable = setmntent(table, "r")) == 0) + return 0; + + while ((mountEntry = getmntent(mountTable)) != 0) { + if (strcmp(name, mountEntry->mnt_dir) == 0 + || strcmp(name, mountEntry->mnt_fsname) == 0) /* String match. */ + break; + if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == mountDevice) /* Match the device. */ + break; + if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == mountDevice) /* Match the directory's mount point. */ + break; + } + endmntent(mountTable); + return mountEntry; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/find_pid_by_name.c b/libbb/find_pid_by_name.c new file mode 100644 index 000000000..fc3742ab2 --- /dev/null +++ b/libbb/find_pid_by_name.c @@ -0,0 +1,183 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include +#include +#include +#include "libbb.h" + +#define READ_BUF_SIZE 50 + +#define COMM_LEN 16 /* synchronize with size of comm in struct task_struct + in /usr/include/linux/sched.h */ + +/* For Erik's nifty devps device driver */ +#ifdef BB_FEATURE_USE_DEVPS_PATCH +#include + +/* find_pid_by_name() + * + * This finds the pid of the specified process, + * by using the /dev/ps device driver. + * + * Returns a list of all matching PIDs + */ +extern long* find_pid_by_name( char* pidName) +{ + int fd, i, j; + char device[] = "/dev/ps"; + pid_t num_pids; + pid_t* pid_array = NULL; + long* pidList=NULL; + + /* open device */ + fd = open(device, O_RDONLY); + if (fd < 0) + perror_msg_and_die("open failed for `%s'", device); + + /* Find out how many processes there are */ + if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) + perror_msg_and_die("\nDEVPS_GET_PID_LIST"); + + /* Allocate some memory -- grab a few extras just in case + * some new processes start up while we wait. The kernel will + * just ignore any extras if we give it too many, and will trunc. + * the list if we give it too few. */ + pid_array = (pid_t*) xcalloc( num_pids+10, sizeof(pid_t)); + pid_array[0] = num_pids+10; + + /* Now grab the pid list */ + if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) + perror_msg_and_die("\nDEVPS_GET_PID_LIST"); + + /* Now search for a match */ + for (i=1, j=0; id_name, "..") == 0) + continue; + + /* If it isn't a number, we don't want it */ + if (!isdigit(*next->d_name)) + continue; + + sprintf(filename, "/proc/%s/status", next->d_name); + if (! (status = fopen(filename, "r")) ) { + continue; + } + if (fgets(buffer, READ_BUF_SIZE-1, status) == NULL) { + fclose(status); + continue; + } + fclose(status); + + /* Buffer should contain a string like "Name: binary_name" */ + sscanf(buffer, "%*s %s", name); + if (strncmp(name, pidName, COMM_LEN-1) == 0) { + pidList=xrealloc( pidList, sizeof(long) * (i+2)); + pidList[i++]=strtol(next->d_name, NULL, 0); + } + } + + if (pidList) { + pidList[i]=0; + } else { + pidList=xrealloc( pidList, sizeof(long)); + pidList[0]=-1; + } + return pidList; +} +#endif /* BB_FEATURE_USE_DEVPS_PATCH */ + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/find_root_device.c b/libbb/find_root_device.c new file mode 100644 index 000000000..e5f698659 --- /dev/null +++ b/libbb/find_root_device.c @@ -0,0 +1,87 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen + * Patched by a bunch of people. Feel free to acknowledge your work. + * + * 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 "libbb.h" + + + +extern char *find_real_root_device_name(const char* name) +{ + DIR *dir; + struct dirent *entry; + struct stat statBuf, rootStat; + char *fileName = NULL; + dev_t dev; + + if (stat("/", &rootStat) != 0) + perror_msg("could not stat '/'"); + else { + /* This check is here in case they pass in /dev name */ + if ((rootStat.st_mode & S_IFMT) == S_IFBLK) + dev = rootStat.st_rdev; + else + dev = rootStat.st_dev; + + dir = opendir("/dev"); + if (!dir) + perror_msg("could not open '/dev'"); + else { + while((entry = readdir(dir)) != NULL) { + + /* Must skip ".." since that is "/", and so we + * would get a false positive on ".." */ + if (strcmp(entry->d_name, "..") == 0) + continue; + + fileName = concat_path_file("/dev", entry->d_name); + + /* Some char devices have the same dev_t as block + * devices, so make sure this is a block device */ + if (stat(fileName, &statBuf) == 0 && + S_ISBLK(statBuf.st_mode)!=0 && + statBuf.st_rdev == dev) + break; + free(fileName); + fileName=NULL; + } + closedir(dir); + } + } + if(fileName==NULL) + fileName=xstrdup("/dev/root"); + return fileName; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/full_read.c b/libbb/full_read.c new file mode 100644 index 000000000..b91cdcbc9 --- /dev/null +++ b/libbb/full_read.c @@ -0,0 +1,63 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * 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 + */ + +#include +#include +#include "libbb.h" + +/* + * Read all of the supplied buffer from a file. + * This does multiple reads as necessary. + * Returns the amount read, or -1 on an error. + * A short read is returned on an end of file. + */ +ssize_t full_read(int fd, void *buf, size_t len) +{ + ssize_t cc; + ssize_t total; + + total = 0; + + while (len > 0) { + cc = safe_read(fd, buf, len); + + if (cc < 0) + return cc; /* read() returns -1 on failure. */ + + if (cc == 0) + break; + + buf = ((char *)buf) + cc; + total += cc; + len -= cc; + } + + return total; +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/full_write.c b/libbb/full_write.c new file mode 100644 index 000000000..c485a2402 --- /dev/null +++ b/libbb/full_write.c @@ -0,0 +1,60 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * 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 + */ + +#include +#include +#include "libbb.h" + +/* + * Write all of the supplied buffer out to a file. + * This does multiple writes as necessary. + * Returns the amount written, or -1 on an error. + */ +ssize_t full_write(int fd, const void *buf, size_t len) +{ + ssize_t cc; + ssize_t total; + + total = 0; + + while (len > 0) { + cc = safe_write(fd, buf, len); + + if (cc < 0) + return cc; /* write() returns -1 on failure. */ + + total += cc; + buf = ((const char *)buf) + cc; + len -= cc; + } + + return total; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/get_console.c b/libbb/get_console.c new file mode 100644 index 000000000..39c00e62e --- /dev/null +++ b/libbb/get_console.c @@ -0,0 +1,122 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 "libbb.h" + + + + + +/* From */ +static const int KDGKBTYPE = 0x4B33; /* get keyboard type */ +static const int KB_84 = 0x01; +static const int KB_101 = 0x02; /* this is what we always answer */ + +int is_a_console(int fd) +{ + char arg; + + arg = 0; + return (ioctl(fd, KDGKBTYPE, &arg) == 0 + && ((arg == KB_101) || (arg == KB_84))); +} + +static int open_a_console(char *fnam) +{ + int fd; + + /* try read-only */ + fd = open(fnam, O_RDWR); + + /* if failed, try read-only */ + if (fd < 0 && errno == EACCES) + fd = open(fnam, O_RDONLY); + + /* if failed, try write-only */ + if (fd < 0 && errno == EACCES) + fd = open(fnam, O_WRONLY); + + /* if failed, fail */ + if (fd < 0) + return -1; + + /* if not a console, fail */ + if (!is_a_console(fd)) { + close(fd); + return -1; + } + + /* success */ + return fd; +} + +/* + * Get an fd for use with kbd/console ioctls. + * We try several things because opening /dev/console will fail + * if someone else used X (which does a chown on /dev/console). + * + * if tty_name is non-NULL, try this one instead. + */ + +int get_console_fd(void) +{ + int fd; + + if (-1 == (fd = open_a_console("/dev/console"))) + return -1; + else + return fd; + + fd = open_a_console(CURRENT_TTY); + if (fd >= 0) + return fd; + + fd = open_a_console(CURRENT_VC); + if (fd >= 0) + return fd; + + fd = open_a_console(CONSOLE_DEV); + if (fd >= 0) + return fd; + + for (fd = 0; fd < 3; fd++) + if (is_a_console(fd)) + return fd; + + error_msg("Couldn't get a file descriptor referring to the console"); + return -1; /* total failure */ +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/get_last_path_component.c b/libbb/get_last_path_component.c new file mode 100644 index 000000000..6af726c83 --- /dev/null +++ b/libbb/get_last_path_component.c @@ -0,0 +1,56 @@ +/* vi: set sw=4 ts=4: */ +/* + * get_last_path_component implementation for busybox + * + * Copyright (C) 2001 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 + * + */ + +/* Set to 1 if you want basename() behavior for NULL or "". */ +/* WARNING!!! Doing so will break basename applet at least! */ +#define EMULATE_BASENAME 0 + +char *get_last_path_component(char *path) +{ +#if EMULATE_BASENAME + static const char null_or_empty[] = "."; +#endif + char *first = path; + char *last; + +#if EMULATE_BASENAME + if (!path || !*path) { + return (char *) null_or_empty; + } +#endif + + last = path - 1; + + while (*path) { + if ((*path != '/') && (path > ++last)) { + last = first = path; + } + ++path; + } + + if (*first == '/') { + last = first; + } + last[1] = 0; + + return first; +} diff --git a/libbb/get_line_from_file.c b/libbb/get_line_from_file.c new file mode 100644 index 000000000..0d9720b17 --- /dev/null +++ b/libbb/get_line_from_file.c @@ -0,0 +1,82 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. + * If you wrote this, please acknowledge your work. + * + * 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" + +/* get_line_from_file() - This function reads an entire line from a text file, + * up to a newline. It returns a malloc'ed char * which must be stored and + * free'ed by the caller. If 'c' is nonzero, the trailing '\n' (if any) + * is removed. In event of a read error or EOF, NULL is returned. */ + +static char *private_get_line_from_file(FILE *file, int c) +{ +#define GROWBY (80) /* how large we will grow strings by */ + + int ch; + int idx = 0; + char *linebuf = NULL; + int linebufsz = 0; + + while ((ch = getc(file)) != EOF) { + /* grow the line buffer as necessary */ + if (idx > linebufsz - 2) { + linebuf = xrealloc(linebuf, linebufsz += GROWBY); + } + linebuf[idx++] = (char)ch; + if (ch == '\n' || ch == '\0') { + if (c) { + --idx; + } + break; + } + } + if (linebuf) { + if (ferror(file)) { + free(linebuf); + return NULL; + } + linebuf[idx] = 0; + } + return linebuf; +} + +extern char *get_line_from_file(FILE *file) +{ + return private_get_line_from_file(file, 0); +} + +extern char *get_chomped_line_from_file(FILE *file) +{ + return private_get_line_from_file(file, 1); +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/gz_open.c b/libbb/gz_open.c new file mode 100644 index 000000000..a0187534d --- /dev/null +++ b/libbb/gz_open.c @@ -0,0 +1,62 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 "libbb.h" + +extern FILE *gz_open(FILE *compressed_file, int *pid) +{ + int unzip_pipe[2]; + + if (pipe(unzip_pipe)!=0) { + error_msg("pipe error"); + return(NULL); + } +#ifndef __uClinux__ + if ((*pid = fork()) == -1) { + error_msg("fork failed"); + return(NULL); + } + if (*pid==0) { + /* child process */ + close(unzip_pipe[0]); + unzip(compressed_file, fdopen(unzip_pipe[1], "w")); + fflush(NULL); + fclose(compressed_file); + close(unzip_pipe[1]); + exit(EXIT_SUCCESS); + } +#else + return NULL; +#endif /* __uClinux__ */ + close(unzip_pipe[1]); + if (unzip_pipe[0] == -1) { + error_msg("gzip stream init failed"); + } + return(fdopen(unzip_pipe[0], "r")); +} diff --git a/libbb/herror_msg.c b/libbb/herror_msg.c new file mode 100644 index 000000000..1081a56b1 --- /dev/null +++ b/libbb/herror_msg.c @@ -0,0 +1,44 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include + +#include "libbb.h" + +extern void herror_msg(const char *s, ...) +{ + va_list p; + + va_start(p, s); + vherror_msg(s, p); + va_end(p); +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/herror_msg_and_die.c b/libbb/herror_msg_and_die.c new file mode 100644 index 000000000..a47c7ff95 --- /dev/null +++ b/libbb/herror_msg_and_die.c @@ -0,0 +1,45 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include + +#include "libbb.h" + +extern void herror_msg_and_die(const char *s, ...) +{ + va_list p; + + va_start(p, s); + vherror_msg(s, p); + va_end(p); + exit(EXIT_FAILURE); +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/human_readable.c b/libbb/human_readable.c new file mode 100644 index 000000000..7bdad36a9 --- /dev/null +++ b/libbb/human_readable.c @@ -0,0 +1,88 @@ +/* + * June 30, 2001 Manuel Novoa III + * + * All-integer version (hey, not everyone has floating point) of + * make_human_readable_str, modified from similar code I had written + * for busybox several months ago. + * + * Notes: + * 1) I'm using an unsigned long long to hold the product size * block_size, + * as df (which calls this routine) could request a representation of a + * partition size in bytes > max of unsigned long. If long longs aren't + * available, it would be possible to do what's needed using polynomial + * representations (say, powers of 1024) and manipulating coefficients. + * The base ten "bytes" output could be handled similarly. + * + * 2) This routine always outputs a decimal point and a tenths digit when + * display_unit != 0. Hence, it isn't uncommon for the returned string + * to have a length of 5 or 6. + * + * It might be nice to add a flag to indicate no decimal digits in + * that case. This could be either an additional parameter, or a + * special value of display_unit. Such a flag would also be nice for du. + * + * Some code to omit the decimal point and tenths digit is sketched out + * and "#if 0"'d below. + */ + +#include +#include "libbb.h" + +const char *make_human_readable_str(unsigned long size, + unsigned long block_size, + unsigned long display_unit) +{ + /* The code will adjust for additional (appended) units. */ + static const char zero_and_units[] = { '0', 0, 'k', 'M', 'G', 'T' }; + static const char fmt[] = "%Lu"; + static const char fmt_tenths[] = "%Lu.%d%c"; + + static char str[21]; /* Sufficient for 64 bit unsigned integers. */ + + unsigned long long val; + int frac; + const char *u; + const char *f; + + u = zero_and_units; + f = fmt; + frac = 0; + + val = ((unsigned long long) size) * block_size; + if (val == 0) { + return u; + } + + if (display_unit) { + val += display_unit/2; /* Deal with rounding. */ + val /= display_unit; /* Don't combine with the line above!!! */ + } else { + ++u; + while ((val >= KILOBYTE) + && (u < zero_and_units + sizeof(zero_and_units) - 1)) { + f = fmt_tenths; + ++u; + frac = ((((int)(val % KILOBYTE)) * 10) + (KILOBYTE/2)) / KILOBYTE; + val /= KILOBYTE; + } + if (frac >= 10) { /* We need to round up here. */ + ++val; + frac = 0; + } +#if 0 + /* Sample code to omit decimal point and tenths digit. */ + if ( /* no_tenths */ 1 ) { + if ( frac >= 5 ) { + ++val; + } + f = "%Lu%*c" /* fmt_no_tenths */ ; + frac = 1; + } +#endif + } + + /* If f==fmt then 'frac' and 'u' are ignored. */ + snprintf(str, sizeof(str), f, val, frac, *u); + + return str; +} diff --git a/libbb/inode_hash.c b/libbb/inode_hash.c new file mode 100644 index 000000000..36484e6ae --- /dev/null +++ b/libbb/inode_hash.c @@ -0,0 +1,109 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 "libbb.h" + +#define HASH_SIZE 311 /* Should be prime */ +#define hash_inode(i) ((i) % HASH_SIZE) + +typedef struct ino_dev_hash_bucket_struct { + struct ino_dev_hash_bucket_struct *next; + ino_t ino; + dev_t dev; + char name[1]; +} ino_dev_hashtable_bucket_t; + +static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE]; + +/* + * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in + * `ino_dev_hashtable', else return 0 + * + * If NAME is a non-NULL pointer to a character pointer, and there is + * a match, then set *NAME to the value of the name slot in that + * bucket. + */ +int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name) +{ + ino_dev_hashtable_bucket_t *bucket; + + bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)]; + while (bucket != NULL) { + if ((bucket->ino == statbuf->st_ino) && + (bucket->dev == statbuf->st_dev)) + { + if (name) *name = bucket->name; + return 1; + } + bucket = bucket->next; + } + return 0; +} + +/* Add statbuf to statbuf hash table */ +void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) +{ + int i; + size_t s; + ino_dev_hashtable_bucket_t *bucket; + + i = hash_inode(statbuf->st_ino); + s = name ? strlen(name) : 0; + bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s); + bucket->ino = statbuf->st_ino; + bucket->dev = statbuf->st_dev; + if (name) + strcpy(bucket->name, name); + else + bucket->name[0] = '\0'; + bucket->next = ino_dev_hashtable[i]; + ino_dev_hashtable[i] = bucket; +} + +/* Clear statbuf hash table */ +void reset_ino_dev_hashtable(void) +{ + int i; + ino_dev_hashtable_bucket_t *bucket; + + for (i = 0; i < HASH_SIZE; i++) { + while (ino_dev_hashtable[i] != NULL) { + bucket = ino_dev_hashtable[i]->next; + free(ino_dev_hashtable[i]); + ino_dev_hashtable[i] = bucket; + } + } +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/interface.c b/libbb/interface.c new file mode 100644 index 000000000..5b1c418e9 --- /dev/null +++ b/libbb/interface.c @@ -0,0 +1,2172 @@ +/* + * ifconfig This file contains an implementation of the command + * that either displays or sets the characteristics of + * one or more of the system's networking interfaces. + * + * Version: $Id: interface.c,v 1.8 2003/07/28 06:37:04 andersen Exp $ + * + * Author: Fred N. van Kempen, + * and others. Copyright 1993 MicroWalt Corporation + * + * 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. + * + * Patched to support 'add' and 'del' keywords for INET(4) addresses + * by Mrs. Brisby + * + * {1.34} - 19980630 - Arnaldo Carvalho de Melo + * - gettext instead of catgets for i18n + * 10/1998 - Andi Kleen. Use interface list primitives. + * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu + * (default AF was wrong) + * stolen from net-tools-1.59 and stripped down for busybox by + * Erik Andersen + */ + +/* + * Heavily modified by Manuel Novoa III Mar 12, 2001 + * + * Pruned unused code using KEEP_UNUSED define. + * Added print_bytes_scaled function to reduce code size. + * Added some (potentially) missing defines. + * Improved display support for -a and for a named interface. + */ + +/* #define KEEP_UNUSED */ + +/* + * + * Protocol Families. + * + */ +#define HAVE_AFINET 1 +#undef HAVE_AFINET6 +#undef HAVE_AFIPX +#undef HAVE_AFATALK +#undef HAVE_AFNETROM +#undef HAVE_AFX25 +#undef HAVE_AFECONET +#undef HAVE_AFASH + +/* + * + * Device Hardware types. + * + */ +#define HAVE_HWETHER 1 +#define HAVE_HWPPP 1 +#undef HAVE_HWSLIP + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if 0 +#include +#endif +#include "libbb.h" + +#define _(x) x +#define _PATH_PROCNET_DEV "/proc/net/dev" +#define new(p) ((p) = xcalloc(1,sizeof(*(p)))) +#define KRELEASE(maj,min,patch) ((maj) * 65536 + (min)*256 + (patch)) + +static int procnetdev_vsn = 1; + +#ifdef DEBUG +#include +#endif + + +/* Ugh. But libc5 doesn't provide POSIX types. */ +#include + + +#ifdef HAVE_HWSLIP +#include +#endif + +#if HAVE_AFINET6 + +#ifndef _LINUX_IN6_H +/* + * This is in linux/include/net/ipv6.h. + */ + +struct in6_ifreq { + struct in6_addr ifr6_addr; + __u32 ifr6_prefixlen; + unsigned int ifr6_ifindex; +}; + +#endif + +#endif /* HAVE_AFINET6 */ + +#if HAVE_AFIPX +#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) +#include +#else +#include "ipx.h" +#endif +#endif +#if 0 +#include "net-support.h" +#include "pathnames.h" +#include "version.h" +#include "../intl.h" +#include "interface.h" +#include "sockets.h" +#include "util.h" +#endif + +/* Defines for glibc2.0 users. */ +#ifndef SIOCSIFTXQLEN +#define SIOCSIFTXQLEN 0x8943 +#define SIOCGIFTXQLEN 0x8942 +#endif + +/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */ +#ifndef ifr_qlen +#define ifr_qlen ifr_ifru.ifru_mtu +#endif + +#ifndef HAVE_TXQUEUELEN +#define HAVE_TXQUEUELEN 1 +#endif + +#ifndef IFF_DYNAMIC +#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */ +#endif + +/* This structure defines protocol families and their handlers. */ +struct aftype { + const char *name; + const char *title; + int af; + int alen; + char *(*print) (unsigned char *); + char *(*sprint) (struct sockaddr *, int numeric); + int (*input) (int type, char *bufp, struct sockaddr *); + void (*herror) (char *text); + int (*rprint) (int options); + int (*rinput) (int typ, int ext, char **argv); + + /* may modify src */ + int (*getmask) (char *src, struct sockaddr * mask, char *name); + + int fd; + char *flag_file; +}; + +static struct aftype *aftypes[]; + +#ifdef KEEP_UNUSED + +static int flag_unx; +#ifdef HAVE_AFIPX +static int flag_ipx; +#endif +#ifdef HAVE_AFX25 +static int flag_ax25; +#endif +#ifdef HAVE_AFATALK +static int flag_ddp; +#endif +#ifdef HAVE_AFNETROM +static int flag_netrom; +#endif +static int flag_inet; +#ifdef HAVE_AFINET6 +static int flag_inet6; +#endif +#ifdef HAVE_AFECONET +static int flag_econet; +#endif +#ifdef HAVE_AFX25 +static int flag_x25 = 0; +#endif +#ifdef HAVE_AFASH +static int flag_ash; +#endif + + +static struct aftrans_t { + char *alias; + char *name; + int *flag; +} aftrans[] = { + +#ifdef HAVE_AFX25 + { + "ax25", "ax25", &flag_ax25 + }, +#endif + { + "ip", "inet", &flag_inet + }, +#ifdef HAVE_AFINET6 + { + "ip6", "inet6", &flag_inet6 + }, +#endif +#ifdef HAVE_AFIPX + { + "ipx", "ipx", &flag_ipx + }, +#endif +#ifdef HAVE_AFATALK + { + "appletalk", "ddp", &flag_ddp + }, +#endif +#ifdef HAVE_AFNETROM + { + "netrom", "netrom", &flag_netrom + }, +#endif + { + "inet", "inet", &flag_inet + }, +#ifdef HAVE_AFINET6 + { + "inet6", "inet6", &flag_inet6 + }, +#endif +#ifdef HAVE_AFATALK + { + "ddp", "ddp", &flag_ddp + }, +#endif + { + "unix", "unix", &flag_unx + }, + { + "tcpip", "inet", &flag_inet + }, +#ifdef HAVE_AFECONET + { + "econet", "ec", &flag_econet + }, +#endif +#ifdef HAVE_AFX25 + { + "x25", "x25", &flag_x25 + }, +#endif +#ifdef HAVE_AFASH + { + "ash", "ash", &flag_ash + }, +#endif + { + 0, 0, 0 + } +}; + +static char afname[256] = ""; +#endif /* KEEP_UNUSED */ + +#if HAVE_AFUNIX + +/* Display a UNIX domain address. */ +static char *UNIX_print(unsigned char *ptr) +{ + return (ptr); +} + + +/* Display a UNIX domain address. */ +static char *UNIX_sprint(struct sockaddr *sap, int numeric) +{ + static char buf[64]; + + if (sap->sa_family == 0xFFFF || sap->sa_family == 0) + return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf)); + return (UNIX_print(sap->sa_data)); +} + + +static struct aftype unix_aftype = +{ + "unix", "UNIX Domain", AF_UNIX, 0, + UNIX_print, UNIX_sprint, NULL, NULL, + NULL, NULL, NULL, + -1, + "/proc/net/unix" +}; +#endif /* HAVE_AFUNIX */ + +#if HAVE_AFINET + +#if 0 +extern int h_errno; /* some netdb.h versions don't export this */ +#endif + +/* cache */ +struct addr { + struct sockaddr_in addr; + char *name; + int host; + struct addr *next; +}; + +static struct addr *INET_nn = NULL; /* addr-to-name cache */ + +#ifdef KEEP_UNUSED +static int INET_resolve(char *name, struct sockaddr_in *sin, int hostfirst) +{ + struct hostent *hp; + struct netent *np; + + /* Grmpf. -FvK */ + sin->sin_family = AF_INET; + sin->sin_port = 0; + + /* Default is special, meaning 0.0.0.0. */ + if (!strcmp(name, "default")) { + sin->sin_addr.s_addr = INADDR_ANY; + return (1); + } + /* Look to see if it's a dotted quad. */ + if (inet_aton(name, &sin->sin_addr)) { + return 0; + } + /* If we expect this to be a hostname, try hostname database first */ +#ifdef DEBUG + if (hostfirst) fprintf (stderr, "gethostbyname (%s)\n", name); +#endif + if (hostfirst && + (hp = gethostbyname(name)) != (struct hostent *) NULL) { + memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], + sizeof(struct in_addr)); + return 0; + } + /* Try the NETWORKS database to see if this is a known network. */ +#ifdef DEBUG + fprintf (stderr, "getnetbyname (%s)\n", name); +#endif + if ((np = getnetbyname(name)) != (struct netent *) NULL) { + sin->sin_addr.s_addr = htonl(np->n_net); + return 1; + } + if (hostfirst) { + /* Don't try again */ + errno = h_errno; + return -1; + } +#ifdef DEBUG + res_init(); + _res.options |= RES_DEBUG; +#endif + +#ifdef DEBUG + fprintf (stderr, "gethostbyname (%s)\n", name); +#endif + if ((hp = gethostbyname(name)) == (struct hostent *) NULL) { + errno = h_errno; + return -1; + } + memcpy((char *) &sin->sin_addr, (char *) hp->h_addr_list[0], + sizeof(struct in_addr)); + + return 0; +} +#endif /* KEEP_UNUSED */ + +/* numeric: & 0x8000: default instead of *, + * & 0x4000: host instead of net, + * & 0x0fff: don't resolve + */ +static int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in, + int numeric, unsigned int netmask) +{ + struct hostent *ent; + struct netent *np; + struct addr *pn; + unsigned long ad, host_ad; + int host = 0; + + /* Grmpf. -FvK */ + if (s_in->sin_family != AF_INET) { +#ifdef DEBUG + fprintf(stderr, "rresolve: unsupport address family %d !\n", s_in->sin_family); +#endif + errno = EAFNOSUPPORT; + return (-1); + } + ad = (unsigned long) s_in->sin_addr.s_addr; +#ifdef DEBUG + fprintf (stderr, "rresolve: %08lx, mask %08x, num %08x \n", ad, netmask, numeric); +#endif + if (ad == INADDR_ANY) { + if ((numeric & 0x0FFF) == 0) { + if (numeric & 0x8000) + safe_strncpy(name, "default", len); + else + safe_strncpy(name, "*", len); + return (0); + } + } + if (numeric & 0x0FFF) { + safe_strncpy(name, inet_ntoa(s_in->sin_addr), len); + return (0); + } + + if ((ad & (~netmask)) != 0 || (numeric & 0x4000)) + host = 1; +#if 0 + INET_nn = NULL; +#endif + pn = INET_nn; + while (pn != NULL) { + if (pn->addr.sin_addr.s_addr == ad && pn->host == host) { + safe_strncpy(name, pn->name, len); +#ifdef DEBUG + fprintf (stderr, "rresolve: found %s %08lx in cache\n", (host? "host": "net"), ad); +#endif + return (0); + } + pn = pn->next; + } + + host_ad = ntohl(ad); + np = NULL; + ent = NULL; + if (host) { +#ifdef DEBUG + fprintf (stderr, "gethostbyaddr (%08lx)\n", ad); +#endif + ent = gethostbyaddr((char *) &ad, 4, AF_INET); + if (ent != NULL) + safe_strncpy(name, ent->h_name, len); + } else { +#ifdef DEBUG + fprintf (stderr, "getnetbyaddr (%08lx)\n", host_ad); +#endif +#if 0 + np = getnetbyaddr(host_ad, AF_INET); + if (np != NULL) + safe_strncpy(name, np->n_name, len); +#endif + } + if ((ent == NULL) && (np == NULL)) + safe_strncpy(name, inet_ntoa(s_in->sin_addr), len); + pn = (struct addr *) xmalloc(sizeof(struct addr)); + pn->addr = *s_in; + pn->next = INET_nn; + pn->host = host; + pn->name = (char *) xmalloc(strlen(name) + 1); + strcpy(pn->name, name); + INET_nn = pn; + + return (0); +} + +#ifdef KEEP_UNUSED +static void INET_reserror(char *text) +{ + herror(text); +} + +/* Display an Internet socket address. */ +static char *INET_print(unsigned char *ptr) +{ + return (inet_ntoa((*(struct in_addr *) ptr))); +} +#endif /* KEEP_UNUSED */ + +/* Display an Internet socket address. */ +static char *INET_sprint(struct sockaddr *sap, int numeric) +{ + static char buff[128]; + + if (sap->sa_family == 0xFFFF || sap->sa_family == 0) + return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff)); + + if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap, + numeric, 0xffffff00) != 0) + return (NULL); + + return (buff); +} + +#ifdef KEEP_UNUSED +static char *INET_sprintmask(struct sockaddr *sap, int numeric, + unsigned int netmask) +{ + static char buff[128]; + + if (sap->sa_family == 0xFFFF || sap->sa_family == 0) + return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff)); + if (INET_rresolve(buff, sizeof(buff), (struct sockaddr_in *) sap, + numeric, netmask) != 0) + return (NULL); + return (buff); +} + +static int INET_getsock(char *bufp, struct sockaddr *sap) +{ + char *sp = bufp, *bp; + unsigned int i; + unsigned val; + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *) sap; + sin->sin_family = AF_INET; + sin->sin_port = 0; + + val = 0; + bp = (char *) &val; + for (i = 0; i < sizeof(sin->sin_addr.s_addr); i++) { + *sp = toupper(*sp); + + if ((*sp >= 'A') && (*sp <= 'F')) + bp[i] |= (int) (*sp - 'A') + 10; + else if ((*sp >= '0') && (*sp <= '9')) + bp[i] |= (int) (*sp - '0'); + else + return (-1); + + bp[i] <<= 4; + sp++; + *sp = toupper(*sp); + + if ((*sp >= 'A') && (*sp <= 'F')) + bp[i] |= (int) (*sp - 'A') + 10; + else if ((*sp >= '0') && (*sp <= '9')) + bp[i] |= (int) (*sp - '0'); + else + return (-1); + + sp++; + } + sin->sin_addr.s_addr = htonl(val); + + return (sp - bufp); +} + +static int INET_input(int type, char *bufp, struct sockaddr *sap) +{ + switch (type) { + case 1: + return (INET_getsock(bufp, sap)); + case 256: + return (INET_resolve(bufp, (struct sockaddr_in *) sap, 1)); + default: + return (INET_resolve(bufp, (struct sockaddr_in *) sap, 0)); + } +} + +static int INET_getnetmask(char *adr, struct sockaddr *m, char *name) +{ + struct sockaddr_in *mask = (struct sockaddr_in *) m; + char *slash, *end; + int prefix; + + if ((slash = strchr(adr, '/')) == NULL) + return 0; + + *slash++ = '\0'; + prefix = strtoul(slash, &end, 0); + if (*end != '\0') + return -1; + + if (name) { + sprintf(name, "/%d", prefix); + } + mask->sin_family = AF_INET; + mask->sin_addr.s_addr = htonl(~(0xffffffffU >> prefix)); + return 1; +} +#endif /* KEEP_UNUSED */ + +static struct aftype inet_aftype = +{ + "inet", "DARPA Internet", AF_INET, sizeof(unsigned long), + NULL /* UNUSED INET_print */, INET_sprint, + NULL /* UNUSED INET_input */, NULL /* UNUSED INET_reserror */, + NULL /*INET_rprint */ , NULL /*INET_rinput */ , + NULL /* UNUSED INET_getnetmask */, + -1, + NULL +}; + +#endif /* HAVE_AFINET */ + +/* Display an UNSPEC address. */ +static char *UNSPEC_print(unsigned char *ptr) +{ + static char buff[sizeof(struct sockaddr)*3+1]; + char *pos; + unsigned int i; + + pos = buff; + for (i = 0; i < sizeof(struct sockaddr); i++) { + /* careful -- not every libc's sprintf returns # bytes written */ + sprintf(pos, "%02X-", (*ptr++ & 0377)); + pos += 3; + } + /* Erase trailing "-". Works as long as sizeof(struct sockaddr) != 0 */ + *--pos = '\0'; + return (buff); +} + +/* Display an UNSPEC socket address. */ +static char *UNSPEC_sprint(struct sockaddr *sap, int numeric) +{ + static char buf[64]; + + if (sap->sa_family == 0xFFFF || sap->sa_family == 0) + return safe_strncpy(buf, _("[NONE SET]"), sizeof(buf)); + return (UNSPEC_print(sap->sa_data)); +} + +static struct aftype unspec_aftype = +{ + "unspec", "UNSPEC", AF_UNSPEC, 0, + UNSPEC_print, UNSPEC_sprint, NULL, NULL, + NULL, +}; + +static struct aftype *aftypes[] = +{ +#if HAVE_AFUNIX + &unix_aftype, +#endif +#if HAVE_AFINET + &inet_aftype, +#endif +#if HAVE_AFINET6 + &inet6_aftype, +#endif +#if HAVE_AFAX25 + &ax25_aftype, +#endif +#if HAVE_AFNETROM + &netrom_aftype, +#endif +#if HAVE_AFROSE + &rose_aftype, +#endif +#if HAVE_AFIPX + &ipx_aftype, +#endif +#if HAVE_AFATALK + &ddp_aftype, +#endif +#if HAVE_AFECONET + &ec_aftype, +#endif +#if HAVE_AFASH + &ash_aftype, +#endif +#if HAVE_AFX25 + &x25_aftype, +#endif + &unspec_aftype, + NULL +}; + +#ifdef KEEP_UNUSED +static short sVafinit = 0; + +static void afinit() +{ + unspec_aftype.title = _("UNSPEC"); +#if HAVE_AFUNIX + unix_aftype.title = _("UNIX Domain"); +#endif +#if HAVE_AFINET + inet_aftype.title = _("DARPA Internet"); +#endif +#if HAVE_AFINET6 + inet6_aftype.title = _("IPv6"); +#endif +#if HAVE_AFAX25 + ax25_aftype.title = _("AMPR AX.25"); +#endif +#if HAVE_AFNETROM + netrom_aftype.title = _("AMPR NET/ROM"); +#endif +#if HAVE_AFIPX + ipx_aftype.title = _("Novell IPX"); +#endif +#if HAVE_AFATALK + ddp_aftype.title = _("Appletalk DDP"); +#endif +#if HAVE_AFECONET + ec_aftype.title = _("Econet"); +#endif +#if HAVE_AFX25 + x25_aftype.title = _("CCITT X.25"); +#endif +#if HAVE_AFROSE + rose_aftype.title = _("AMPR ROSE"); +#endif +#if HAVE_AFASH + ash_aftype.title = _("Ash"); +#endif + sVafinit = 1; +} + +static int aftrans_opt(const char *arg) +{ + struct aftrans_t *paft; + char *tmp1, *tmp2; + char buf[256]; + + safe_strncpy(buf, arg, sizeof(buf)); + + tmp1 = buf; + + while (tmp1) { + + tmp2 = strchr(tmp1, ','); + + if (tmp2) + *(tmp2++) = '\0'; + + paft = aftrans; + for (paft = aftrans; paft->alias; paft++) { + if (strcmp(tmp1, paft->alias)) + continue; + if (strlen(paft->name) + strlen(afname) + 1 >= sizeof(afname)) { + fprintf(stderr, _("Too much address family arguments.\n")); + return (0); + } + if (paft->flag) + (*paft->flag)++; + if (afname[0]) + strcat(afname, ","); + strcat(afname, paft->name); + break; + } + if (!paft->alias) { + fprintf(stderr, _("Unknown address family `%s'.\n"), tmp1); + return (1); + } + tmp1 = tmp2; + } + + return (0); +} + +/* set the default AF list from the program name or a constant value */ +static void aftrans_def(char *tool, char *argv0, char *dflt) +{ + char *tmp; + char *buf; + + strcpy(afname, dflt); + + if (!(tmp = strrchr(argv0, '/'))) + tmp = argv0; /* no slash?! */ + else + tmp++; + + if (!(buf = strdup(tmp))) + return; + + if (strlen(tool) >= strlen(tmp)) { + free(buf); + return; + } + tmp = buf + (strlen(tmp) - strlen(tool)); + + if (strcmp(tmp, tool) != 0) { + free(buf); + return; + } + *tmp = '\0'; + if ((tmp = strchr(buf, '_'))) + *tmp = '\0'; + + afname[0] = '\0'; + if (aftrans_opt(buf)) + strcpy(afname, buf); + + free(buf); +} + +/* Check our protocol family table for this family. */ +static struct aftype *get_aftype(const char *name) +{ + struct aftype **afp; + +#ifdef KEEP_UNUSED + if (!sVafinit) + afinit(); +#endif /* KEEP_UNUSED */ + + afp = aftypes; + while (*afp != NULL) { + if (!strcmp((*afp)->name, name)) + return (*afp); + afp++; + } + if (strchr(name, ',')) + fprintf(stderr, _("Please don't supply more than one address family.\n")); + return (NULL); +} +#endif /* KEEP_UNUSED */ + +/* Check our protocol family table for this family. */ +static struct aftype *get_afntype(int af) +{ + struct aftype **afp; + +#ifdef KEEP_UNUSED + if (!sVafinit) + afinit(); +#endif /* KEEP_UNUSED */ + + afp = aftypes; + while (*afp != NULL) { + if ((*afp)->af == af) + return (*afp); + afp++; + } + return (NULL); +} + +/* Check our protocol family table for this family and return its socket */ +static int get_socket_for_af(int af) +{ + struct aftype **afp; + +#ifdef KEEP_UNUSED + if (!sVafinit) + afinit(); +#endif /* KEEP_UNUSED */ + + afp = aftypes; + while (*afp != NULL) { + if ((*afp)->af == af) + return (*afp)->fd; + afp++; + } + return -1; +} + +#ifdef KEEP_UNUSED +/* type: 0=all, 1=getroute */ +static void print_aflist(int type) { + int count = 0; + char * txt; + struct aftype **afp; + +#ifdef KEEP_UNUSED + if (!sVafinit) + afinit(); +#endif /* KEEP_UNUSED */ + + afp = aftypes; + while (*afp != NULL) { + if ((type == 1 && ((*afp)->rprint == NULL)) || ((*afp)->af == 0)) { + afp++; continue; + } + if ((count % 3) == 0) fprintf(stderr,count?"\n ":" "); + txt = (*afp)->name; if (!txt) txt = ".."; + fprintf(stderr,"%s (%s) ",txt,_((*afp)->title)); + count++; + afp++; + } + fprintf(stderr,"\n"); +} +#endif /* KEEP_UNUSED */ + +struct user_net_device_stats { + unsigned long long rx_packets; /* total packets received */ + unsigned long long tx_packets; /* total packets transmitted */ + unsigned long long rx_bytes; /* total bytes received */ + unsigned long long tx_bytes; /* total bytes transmitted */ + unsigned long rx_errors; /* bad packets received */ + unsigned long tx_errors; /* packet transmit problems */ + unsigned long rx_dropped; /* no space in linux buffers */ + unsigned long tx_dropped; /* no space available in linux */ + unsigned long rx_multicast; /* multicast packets received */ + unsigned long rx_compressed; + unsigned long tx_compressed; + unsigned long collisions; + + /* detailed rx_errors: */ + unsigned long rx_length_errors; + unsigned long rx_over_errors; /* receiver ring buff overflow */ + unsigned long rx_crc_errors; /* recved pkt with crc error */ + unsigned long rx_frame_errors; /* recv'd frame alignment error */ + unsigned long rx_fifo_errors; /* recv'r fifo overrun */ + unsigned long rx_missed_errors; /* receiver missed packet */ + /* detailed tx_errors */ + unsigned long tx_aborted_errors; + unsigned long tx_carrier_errors; + unsigned long tx_fifo_errors; + unsigned long tx_heartbeat_errors; + unsigned long tx_window_errors; +}; + +struct interface { + struct interface *next, *prev; + char name[IFNAMSIZ]; /* interface name */ + short type; /* if type */ + short flags; /* various flags */ + int metric; /* routing metric */ + int mtu; /* MTU value */ + int tx_queue_len; /* transmit queue length */ + struct ifmap map; /* hardware setup */ + struct sockaddr addr; /* IP address */ + struct sockaddr dstaddr; /* P-P IP address */ + struct sockaddr broadaddr; /* IP broadcast address */ + struct sockaddr netmask; /* IP network mask */ + struct sockaddr ipxaddr_bb; /* IPX network address */ + struct sockaddr ipxaddr_sn; /* IPX network address */ + struct sockaddr ipxaddr_e3; /* IPX network address */ + struct sockaddr ipxaddr_e2; /* IPX network address */ + struct sockaddr ddpaddr; /* Appletalk DDP address */ + struct sockaddr ecaddr; /* Econet address */ + int has_ip; + int has_ipx_bb; + int has_ipx_sn; + int has_ipx_e3; + int has_ipx_e2; + int has_ax25; + int has_ddp; + int has_econet; + char hwaddr[32]; /* HW address */ + int statistics_valid; + struct user_net_device_stats stats; /* statistics */ + int keepalive; /* keepalive value for SLIP */ + int outfill; /* outfill value for SLIP */ +}; + + +int interface_opt_a = 0; /* show all interfaces */ + +#ifdef KEEP_UNUSED +static int opt_i = 0; /* show the statistics */ +static int opt_v = 0; /* debugging output flag */ + +static int addr_family = 0; /* currently selected AF */ +#endif /* KEEP_UNUSED */ + +static struct interface *int_list, *int_last; +static int skfd = -1; /* generic raw socket desc. */ + + +static int sockets_open(int family) +{ + struct aftype **aft; + int sfd = -1; + static int force = -1; + + if (force < 0) { + force = 0; + if (get_kernel_revision() < KRELEASE(2, 1, 0)) + force = 1; + if (access("/proc/net", R_OK)) + force = 1; + } + for (aft = aftypes; *aft; aft++) { + struct aftype *af = *aft; + int type = SOCK_DGRAM; + if (af->af == AF_UNSPEC) + continue; + if (family && family != af->af) + continue; + if (af->fd != -1) { + sfd = af->fd; + continue; + } + /* Check some /proc file first to not stress kmod */ + if (!family && !force && af->flag_file) { + if (access(af->flag_file, R_OK)) + continue; + } +#if HAVE_AFNETROM + if (af->af == AF_NETROM) + type = SOCK_SEQPACKET; +#endif +#if HAVE_AFX25 + if (af->af == AF_X25) + type = SOCK_SEQPACKET; +#endif + af->fd = socket(af->af, type, 0); + if (af->fd >= 0) + sfd = af->fd; + } + if (sfd < 0) + fprintf(stderr, _("No usable address families found.\n")); + return sfd; +} + +/* like strcmp(), but knows about numbers */ +static int nstrcmp(const char *astr, const char *b) +{ + const char *a = astr; + + while (*a == *b) { + if (*a == '\0') + return 0; + a++; + b++; + } + if (isdigit(*a)) { + if (!isdigit(*b)) + return -1; + while (a > astr) { + a--; + if (!isdigit(*a)) { + a++; + break; + } + if (!isdigit(*b)) + return -1; + b--; + } + return atoi(a) > atoi(b) ? 1 : -1; + } + return *a - *b; +} + +static struct interface *add_interface(char *name) +{ + struct interface *ife, **nextp, *new; + + for (ife = int_last; ife; ife = ife->prev) { + int n = nstrcmp(ife->name, name); + if (n == 0) + return ife; + if (n < 0) + break; + } + new(new); + safe_strncpy(new->name, name, IFNAMSIZ); + nextp = ife ? &ife->next : &int_list; + new->prev = ife; + new->next = *nextp; + if (new->next) + new->next->prev = new; + else + int_last = new; + *nextp = new; + return new; +} + + +static int if_readconf(void) +{ + int numreqs = 30; + struct ifconf ifc; + struct ifreq *ifr; + int n, err = -1; + int skfd2; + + /* SIOCGIFCONF currently seems to only work properly on AF_INET sockets + (as of 2.1.128) */ + skfd2 = get_socket_for_af(AF_INET); + if (skfd2 < 0) { + fprintf(stderr, _("warning: no inet socket available: %s\n"), + strerror(errno)); + /* Try to soldier on with whatever socket we can get hold of. */ + skfd2 = sockets_open(0); + if (skfd2 < 0) + return -1; + } + + ifc.ifc_buf = NULL; + for (;;) { + ifc.ifc_len = sizeof(struct ifreq) * numreqs; + ifc.ifc_buf = xrealloc(ifc.ifc_buf, ifc.ifc_len); + + if (ioctl(skfd2, SIOCGIFCONF, &ifc) < 0) { + perror("SIOCGIFCONF"); + goto out; + } + if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) { + /* assume it overflowed and try again */ + numreqs += 10; + continue; + } + break; + } + + ifr = ifc.ifc_req; + for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq)) { + add_interface(ifr->ifr_name); + ifr++; + } + err = 0; + +out: + free(ifc.ifc_buf); + return err; +} + +static char *get_name(char *name, char *p) +{ + while (isspace(*p)) + p++; + while (*p) { + if (isspace(*p)) + break; + if (*p == ':') { /* could be an alias */ + char *dot = p, *dotname = name; + *name++ = *p++; + while (isdigit(*p)) + *name++ = *p++; + if (*p != ':') { /* it wasn't, backup */ + p = dot; + name = dotname; + } + if (*p == '\0') + return NULL; + p++; + break; + } + *name++ = *p++; + } + *name++ = '\0'; + return p; +} + +static int get_dev_fields(char *bp, struct interface *ife) +{ + switch (procnetdev_vsn) { + case 3: + sscanf(bp, + "%Lu %Lu %lu %lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu %lu", + &ife->stats.rx_bytes, + &ife->stats.rx_packets, + &ife->stats.rx_errors, + &ife->stats.rx_dropped, + &ife->stats.rx_fifo_errors, + &ife->stats.rx_frame_errors, + &ife->stats.rx_compressed, + &ife->stats.rx_multicast, + + &ife->stats.tx_bytes, + &ife->stats.tx_packets, + &ife->stats.tx_errors, + &ife->stats.tx_dropped, + &ife->stats.tx_fifo_errors, + &ife->stats.collisions, + &ife->stats.tx_carrier_errors, + &ife->stats.tx_compressed); + break; + case 2: + sscanf(bp, "%Lu %Lu %lu %lu %lu %lu %Lu %Lu %lu %lu %lu %lu %lu", + &ife->stats.rx_bytes, + &ife->stats.rx_packets, + &ife->stats.rx_errors, + &ife->stats.rx_dropped, + &ife->stats.rx_fifo_errors, + &ife->stats.rx_frame_errors, + + &ife->stats.tx_bytes, + &ife->stats.tx_packets, + &ife->stats.tx_errors, + &ife->stats.tx_dropped, + &ife->stats.tx_fifo_errors, + &ife->stats.collisions, + &ife->stats.tx_carrier_errors); + ife->stats.rx_multicast = 0; + break; + case 1: + sscanf(bp, "%Lu %lu %lu %lu %lu %Lu %lu %lu %lu %lu %lu", + &ife->stats.rx_packets, + &ife->stats.rx_errors, + &ife->stats.rx_dropped, + &ife->stats.rx_fifo_errors, + &ife->stats.rx_frame_errors, + + &ife->stats.tx_packets, + &ife->stats.tx_errors, + &ife->stats.tx_dropped, + &ife->stats.tx_fifo_errors, + &ife->stats.collisions, + &ife->stats.tx_carrier_errors); + ife->stats.rx_bytes = 0; + ife->stats.tx_bytes = 0; + ife->stats.rx_multicast = 0; + break; + } + return 0; +} + +static inline int procnetdev_version(char *buf) +{ + if (strstr(buf, "compressed")) + return 3; + if (strstr(buf, "bytes")) + return 2; + return 1; +} + +static int if_readlist_proc(char *target) +{ + static int proc_read; + FILE *fh; + char buf[512]; + struct interface *ife; + int err; + + if (proc_read) + return 0; + if (!target) + proc_read = 1; + + fh = fopen(_PATH_PROCNET_DEV, "r"); + if (!fh) { + fprintf(stderr, _("Warning: cannot open %s (%s). Limited output.\n"), + _PATH_PROCNET_DEV, strerror(errno)); + return if_readconf(); + } + fgets(buf, sizeof buf, fh); /* eat line */ + fgets(buf, sizeof buf, fh); + +#if 0 /* pretty, but can't cope with missing fields */ + fmt = proc_gen_fmt(_PATH_PROCNET_DEV, 1, fh, + "face", "", /* parsed separately */ + "bytes", "%lu", + "packets", "%lu", + "errs", "%lu", + "drop", "%lu", + "fifo", "%lu", + "frame", "%lu", + "compressed", "%lu", + "multicast", "%lu", + "bytes", "%lu", + "packets", "%lu", + "errs", "%lu", + "drop", "%lu", + "fifo", "%lu", + "colls", "%lu", + "carrier", "%lu", + "compressed", "%lu", + NULL); + if (!fmt) + return -1; +#else + procnetdev_vsn = procnetdev_version(buf); +#endif + + err = 0; + while (fgets(buf, sizeof buf, fh)) { + char *s, name[128]; + s = get_name(name, buf); + ife = add_interface(name); + get_dev_fields(s, ife); + ife->statistics_valid = 1; + if (target && !strcmp(target,name)) + break; + } + if (ferror(fh)) { + perror(_PATH_PROCNET_DEV); + err = -1; + proc_read = 0; + } + +#if 0 + free(fmt); +#endif + fclose(fh); + return err; +} + +static int if_readlist(void) +{ + int err = if_readlist_proc(NULL); + if (!err) + err = if_readconf(); + return err; +} + +static int for_all_interfaces(int (*doit) (struct interface *, void *), void *cookie) +{ + struct interface *ife; + + if (!int_list && (if_readlist() < 0)) + return -1; + for (ife = int_list; ife; ife = ife->next) { + int err = doit(ife, cookie); + if (err) + return err; + } + return 0; +} + +/* Support for fetching an IPX address */ + +#if HAVE_AFIPX +static int ipx_getaddr(int sock, int ft, struct ifreq *ifr) +{ + ((struct sockaddr_ipx *) &ifr->ifr_addr)->sipx_type = ft; + return ioctl(sock, SIOCGIFADDR, ifr); +} +#endif + + +/* Fetch the interface configuration from the kernel. */ +static int if_fetch(struct interface *ife) +{ + struct ifreq ifr; + int fd; + char *ifname = ife->name; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) + return (-1); + ife->flags = ifr.ifr_flags; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) + memset(ife->hwaddr, 0, 32); + else + memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8); + + ife->type = ifr.ifr_hwaddr.sa_family; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) + ife->metric = 0; + else + ife->metric = ifr.ifr_metric; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0) + ife->mtu = 0; + else + ife->mtu = ifr.ifr_mtu; + +#ifdef HAVE_HWSLIP + if (ife->type == ARPHRD_SLIP || ife->type == ARPHRD_CSLIP || + ife->type == ARPHRD_SLIP6 || ife->type == ARPHRD_CSLIP6 || + ife->type == ARPHRD_ADAPT) { +#ifdef SIOCGOUTFILL + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGOUTFILL, &ifr) < 0) + ife->outfill = 0; + else + ife->outfill = (unsigned int) ifr.ifr_data; +#endif +#ifdef SIOCGKEEPALIVE + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGKEEPALIVE, &ifr) < 0) + ife->keepalive = 0; + else + ife->keepalive = (unsigned int) ifr.ifr_data; +#endif + } +#endif + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) + memset(&ife->map, 0, sizeof(struct ifmap)); + else + memcpy(&ife->map, &ifr.ifr_map, sizeof(struct ifmap)); + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0) + memset(&ife->map, 0, sizeof(struct ifmap)); + else + ife->map = ifr.ifr_map; + +#ifdef HAVE_TXQUEUELEN + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFTXQLEN, &ifr) < 0) + ife->tx_queue_len = -1; /* unknown value */ + else + ife->tx_queue_len = ifr.ifr_qlen; +#else + ife->tx_queue_len = -1; /* unknown value */ +#endif + +#if HAVE_AFINET + /* IPv4 address? */ + fd = get_socket_for_af(AF_INET); + if (fd >= 0) { + strcpy(ifr.ifr_name, ifname); + ifr.ifr_addr.sa_family = AF_INET; + if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) { + ife->has_ip = 1; + ife->addr = ifr.ifr_addr; + strcpy(ifr.ifr_name, ifname); + if (ioctl(fd, SIOCGIFDSTADDR, &ifr) < 0) + memset(&ife->dstaddr, 0, sizeof(struct sockaddr)); + else + ife->dstaddr = ifr.ifr_dstaddr; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(fd, SIOCGIFBRDADDR, &ifr) < 0) + memset(&ife->broadaddr, 0, sizeof(struct sockaddr)); + else + ife->broadaddr = ifr.ifr_broadaddr; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(fd, SIOCGIFNETMASK, &ifr) < 0) + memset(&ife->netmask, 0, sizeof(struct sockaddr)); + else + ife->netmask = ifr.ifr_netmask; + } else + memset(&ife->addr, 0, sizeof(struct sockaddr)); + } +#endif + +#if HAVE_AFATALK + /* DDP address maybe ? */ + fd = get_socket_for_af(AF_APPLETALK); + if (fd >= 0) { + strcpy(ifr.ifr_name, ifname); + if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) { + ife->ddpaddr = ifr.ifr_addr; + ife->has_ddp = 1; + } + } +#endif + +#if HAVE_AFIPX + /* Look for IPX addresses with all framing types */ + fd = get_socket_for_af(AF_IPX); + if (fd >= 0) { + strcpy(ifr.ifr_name, ifname); + if (!ipx_getaddr(fd, IPX_FRAME_ETHERII, &ifr)) { + ife->has_ipx_bb = 1; + ife->ipxaddr_bb = ifr.ifr_addr; + } + strcpy(ifr.ifr_name, ifname); + if (!ipx_getaddr(fd, IPX_FRAME_SNAP, &ifr)) { + ife->has_ipx_sn = 1; + ife->ipxaddr_sn = ifr.ifr_addr; + } + strcpy(ifr.ifr_name, ifname); + if (!ipx_getaddr(fd, IPX_FRAME_8023, &ifr)) { + ife->has_ipx_e3 = 1; + ife->ipxaddr_e3 = ifr.ifr_addr; + } + strcpy(ifr.ifr_name, ifname); + if (!ipx_getaddr(fd, IPX_FRAME_8022, &ifr)) { + ife->has_ipx_e2 = 1; + ife->ipxaddr_e2 = ifr.ifr_addr; + } + } +#endif + +#if HAVE_AFECONET + /* Econet address maybe? */ + fd = get_socket_for_af(AF_ECONET); + if (fd >= 0) { + strcpy(ifr.ifr_name, ifname); + if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) { + ife->ecaddr = ifr.ifr_addr; + ife->has_econet = 1; + } + } +#endif + + return 0; +} + + +static int do_if_fetch(struct interface *ife) +{ + if (if_fetch(ife) < 0) { + char *errmsg; + if (errno == ENODEV) { + /* Give better error message for this case. */ + errmsg = _("Device not found"); + } else { + errmsg = strerror(errno); + } + fprintf(stderr, _("%s: error fetching interface information: %s\n"), + ife->name, errmsg); + return -1; + } + return 0; +} + +/* This structure defines hardware protocols and their handlers. */ +struct hwtype { + const char *name; + const char *title; + int type; + int alen; + char *(*print) (unsigned char *); + int (*input) (char *, struct sockaddr *); + int (*activate) (int fd); + int suppress_null_addr; +}; + +static struct hwtype unspec_hwtype = +{ + "unspec", "UNSPEC", -1, 0, + UNSPEC_print, NULL, NULL +}; + +static struct hwtype loop_hwtype = +{ + "loop", "Local Loopback", ARPHRD_LOOPBACK, 0, + NULL, NULL, NULL +}; + +#if HAVE_HWETHER +#include +#include + +static struct hwtype ether_hwtype; + +/* Display an Ethernet address in readable format. */ +static char *pr_ether(unsigned char *ptr) +{ + static char buff[64]; + + snprintf(buff, sizeof(buff), "%02X:%02X:%02X:%02X:%02X:%02X", + (ptr[0] & 0377), (ptr[1] & 0377), (ptr[2] & 0377), + (ptr[3] & 0377), (ptr[4] & 0377), (ptr[5] & 0377) + ); + return (buff); +} + +#ifdef KEEP_UNUSED +/* Input an Ethernet address and convert to binary. */ +static int in_ether(char *bufp, struct sockaddr *sap) +{ + unsigned char *ptr; + char c, *orig; + int i; + unsigned val; + + sap->sa_family = ether_hwtype.type; + ptr = sap->sa_data; + + i = 0; + orig = bufp; + while ((*bufp != '\0') && (i < ETH_ALEN)) { + val = 0; + c = *bufp++; + if (isdigit(c)) + val = c - '0'; + else if (c >= 'a' && c <= 'f') + val = c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + val = c - 'A' + 10; + else { +#ifdef DEBUG + fprintf(stderr, _("in_ether(%s): invalid ether address!\n"), orig); +#endif + errno = EINVAL; + return (-1); + } + val <<= 4; + c = *bufp; + if (isdigit(c)) + val |= c - '0'; + else if (c >= 'a' && c <= 'f') + val |= c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + val |= c - 'A' + 10; + else if (c == ':' || c == 0) + val >>= 4; + else { +#ifdef DEBUG + fprintf(stderr, _("in_ether(%s): invalid ether address!\n"), orig); +#endif + errno = EINVAL; + return (-1); + } + if (c != 0) + bufp++; + *ptr++ = (unsigned char) (val & 0377); + i++; + + /* We might get a semicolon here - not required. */ + if (*bufp == ':') { + if (i == ETH_ALEN) { +#ifdef DEBUG + fprintf(stderr, _("in_ether(%s): trailing : ignored!\n"), + orig) +#endif + ; /* nothing */ + } + bufp++; + } + } + + /* That's it. Any trailing junk? */ + if ((i == ETH_ALEN) && (*bufp != '\0')) { +#ifdef DEBUG + fprintf(stderr, _("in_ether(%s): trailing junk!\n"), orig); + errno = EINVAL; + return (-1); +#endif + } +#ifdef DEBUG + fprintf(stderr, "in_ether(%s): %s\n", orig, pr_ether(sap->sa_data)); +#endif + + return (0); +} +#endif /* KEEP_UNUSED */ + + +static struct hwtype ether_hwtype = +{ + "ether", "Ethernet", ARPHRD_ETHER, ETH_ALEN, + pr_ether, NULL /* UNUSED in_ether */, NULL +}; + + +#endif /* HAVE_HWETHER */ + + +#if HAVE_HWPPP + +#include + +#ifdef KEEP_UNUSED +/* Start the PPP encapsulation on the file descriptor. */ +static int do_ppp(int fd) +{ + fprintf(stderr, _("You cannot start PPP with this program.\n")); + return -1; +} +#endif /* KEEP_UNUSED */ + +static struct hwtype ppp_hwtype = +{ + "ppp", "Point-Point Protocol", ARPHRD_PPP, 0, + NULL, NULL, NULL /* UNUSED do_ppp */, 0 +}; + + +#endif /* HAVE_PPP */ + +static struct hwtype *hwtypes[] = +{ + + &loop_hwtype, + +#if HAVE_HWSLIP + &slip_hwtype, + &cslip_hwtype, + &slip6_hwtype, + &cslip6_hwtype, + &adaptive_hwtype, +#endif +#if HAVE_HWSTRIP + &strip_hwtype, +#endif +#if HAVE_HWASH + &ash_hwtype, +#endif +#if HAVE_HWETHER + ðer_hwtype, +#endif +#if HAVE_HWTR + &tr_hwtype, +#ifdef ARPHRD_IEEE802_TR + &tr_hwtype1, +#endif +#endif +#if HAVE_HWAX25 + &ax25_hwtype, +#endif +#if HAVE_HWNETROM + &netrom_hwtype, +#endif +#if HAVE_HWROSE + &rose_hwtype, +#endif +#if HAVE_HWTUNNEL + &tunnel_hwtype, +#endif +#if HAVE_HWPPP + &ppp_hwtype, +#endif +#if HAVE_HWHDLCLAPB + &hdlc_hwtype, + &lapb_hwtype, +#endif +#if HAVE_HWARC + &arcnet_hwtype, +#endif +#if HAVE_HWFR + &dlci_hwtype, + &frad_hwtype, +#endif +#if HAVE_HWSIT + &sit_hwtype, +#endif +#if HAVE_HWFDDI + &fddi_hwtype, +#endif +#if HAVE_HWHIPPI + &hippi_hwtype, +#endif +#if HAVE_HWIRDA + &irda_hwtype, +#endif +#if HAVE_HWEC + &ec_hwtype, +#endif +#if HAVE_HWX25 + &x25_hwtype, +#endif + &unspec_hwtype, + NULL +}; + +#ifdef KEEP_UNUSED +static short sVhwinit = 0; + +static void hwinit() +{ + loop_hwtype.title = _("Local Loopback"); + unspec_hwtype.title = _("UNSPEC"); +#if HAVE_HWSLIP + slip_hwtype.title = _("Serial Line IP"); + cslip_hwtype.title = _("VJ Serial Line IP"); + slip6_hwtype.title = _("6-bit Serial Line IP"); + cslip6_hwtype.title = _("VJ 6-bit Serial Line IP"); + adaptive_hwtype.title = _("Adaptive Serial Line IP"); +#endif +#if HAVE_HWETHER + ether_hwtype.title = _("Ethernet"); +#endif +#if HAVE_HWASH + ash_hwtype.title = _("Ash"); +#endif +#if HAVE_HWFDDI + fddi_hwtype.title = _("Fiber Distributed Data Interface"); +#endif +#if HAVE_HWHIPPI + hippi_hwtype.title = _("HIPPI"); +#endif +#if HAVE_HWAX25 + ax25_hwtype.title = _("AMPR AX.25"); +#endif +#if HAVE_HWROSE + rose_hwtype.title = _("AMPR ROSE"); +#endif +#if HAVE_HWNETROM + netrom_hwtype.title = _("AMPR NET/ROM"); +#endif +#if HAVE_HWX25 + x25_hwtype.title = _("generic X.25"); +#endif +#if HAVE_HWTUNNEL + tunnel_hwtype.title = _("IPIP Tunnel"); +#endif +#if HAVE_HWPPP + ppp_hwtype.title = _("Point-to-Point Protocol"); +#endif +#if HAVE_HWHDLCLAPB + hdlc_hwtype.title = _("(Cisco)-HDLC"); + lapb_hwtype.title = _("LAPB"); +#endif +#if HAVE_HWARC + arcnet_hwtype.title = _("ARCnet"); +#endif +#if HAVE_HWFR + dlci_hwtype.title = _("Frame Relay DLCI"); + frad_hwtype.title = _("Frame Relay Access Device"); +#endif +#if HAVE_HWSIT + sit_hwtype.title = _("IPv6-in-IPv4"); +#endif +#if HAVE_HWIRDA + irda_hwtype.title = _("IrLAP"); +#endif +#if HAVE_HWTR + tr_hwtype.title = _("16/4 Mbps Token Ring"); +#ifdef ARPHRD_IEEE802_TR + tr_hwtype1.title = _("16/4 Mbps Token Ring (New)") ; +#endif +#endif +#if HAVE_HWEC + ec_hwtype.title = _("Econet"); +#endif + sVhwinit = 1; +} +#endif /* KEEP_UNUSED */ + +#ifdef IFF_PORTSEL +static const char *if_port_text[][4] = +{ + /* Keep in step with */ + {"unknown", NULL, NULL, NULL}, + {"10base2", "bnc", "coax", NULL}, + {"10baseT", "utp", "tpe", NULL}, + {"AUI", "thick", "db15", NULL}, + {"100baseT", NULL, NULL, NULL}, + {"100baseTX", NULL, NULL, NULL}, + {"100baseFX", NULL, NULL, NULL}, + {NULL, NULL, NULL, NULL}, +}; +#endif + +/* Check our hardware type table for this type. */ +static struct hwtype *get_hwntype(int type) +{ + struct hwtype **hwp; + +#ifdef KEEP_UNUSED + if (!sVhwinit) + hwinit(); +#endif /* KEEP_UNUSED */ + + hwp = hwtypes; + while (*hwp != NULL) { + if ((*hwp)->type == type) + return (*hwp); + hwp++; + } + return (NULL); +} + +/* return 1 if address is all zeros */ +static int hw_null_address(struct hwtype *hw, void *ap) +{ + unsigned int i; + unsigned char *address = (unsigned char *)ap; + for (i = 0; i < hw->alen; i++) + if (address[i]) + return 0; + return 1; +} + +static const char TRext[] = "\0\0k\0M"; + +static void print_bytes_scaled(unsigned long long ull, const char *end) +{ + unsigned long long int_part; + unsigned long frac_part; + const char *ext; + int i; + + frac_part = 0; + ext = TRext; + int_part = ull; + for (i=0 ; i<2 ; i++) { + if (int_part >= 1024) { + frac_part = ((int_part % 1024) * 10) / 1024; + int_part /= 1024; + ext += 2; /* Kb, Mb */ + } + } + + printf("X bytes:%Lu (%Lu.%lu %siB)%s", ull, int_part, frac_part, ext, end); +} + +static void ife_print(struct interface *ptr) +{ + struct aftype *ap; + struct hwtype *hw; + int hf; + int can_compress = 0; + +#if HAVE_AFIPX + static struct aftype *ipxtype = NULL; +#endif +#if HAVE_AFECONET + static struct aftype *ectype = NULL; +#endif +#if HAVE_AFATALK + static struct aftype *ddptype = NULL; +#endif +#if HAVE_AFINET6 + FILE *f; + char addr6[40], devname[20]; + struct sockaddr_in6 sap; + int plen, scope, dad_status, if_idx; + extern struct aftype inet6_aftype; + char addr6p[8][5]; +#endif + + ap = get_afntype(ptr->addr.sa_family); + if (ap == NULL) + ap = get_afntype(0); + + hf = ptr->type; + + if (hf == ARPHRD_CSLIP || hf == ARPHRD_CSLIP6) + can_compress = 1; + + hw = get_hwntype(hf); + if (hw == NULL) + hw = get_hwntype(-1); + + printf(_("%-9.9s Link encap:%s "), ptr->name, _(hw->title)); + /* For some hardware types (eg Ash, ATM) we don't print the + hardware address if it's null. */ + if (hw->print != NULL && (! (hw_null_address(hw, ptr->hwaddr) && + hw->suppress_null_addr))) + printf(_("HWaddr %s "), hw->print(ptr->hwaddr)); +#ifdef IFF_PORTSEL + if (ptr->flags & IFF_PORTSEL) { + printf(_("Media:%s"), if_port_text[ptr->map.port][0]); + if (ptr->flags & IFF_AUTOMEDIA) + printf(_("(auto)")); + } +#endif + printf("\n"); + +#if HAVE_AFINET + if (ptr->has_ip) { + printf(_(" %s addr:%s "), ap->name, + ap->sprint(&ptr->addr, 1)); + if (ptr->flags & IFF_POINTOPOINT) { + printf(_(" P-t-P:%s "), ap->sprint(&ptr->dstaddr, 1)); + } + if (ptr->flags & IFF_BROADCAST) { + printf(_(" Bcast:%s "), ap->sprint(&ptr->broadaddr, 1)); + } + printf(_(" Mask:%s\n"), ap->sprint(&ptr->netmask, 1)); + } +#endif + +#if HAVE_AFINET6 + /* FIXME: should be integrated into interface.c. */ + + if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) { + while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", + addr6p[0], addr6p[1], addr6p[2], addr6p[3], + addr6p[4], addr6p[5], addr6p[6], addr6p[7], + &if_idx, &plen, &scope, &dad_status, devname) != EOF) { + if (!strcmp(devname, ptr->name)) { + sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", + addr6p[0], addr6p[1], addr6p[2], addr6p[3], + addr6p[4], addr6p[5], addr6p[6], addr6p[7]); + inet6_aftype.input(1, addr6, (struct sockaddr *) &sap); + printf(_(" inet6 addr: %s/%d"), + inet6_aftype.sprint((struct sockaddr *) &sap, 1), plen); + printf(_(" Scope:")); + switch (scope) { + case 0: + printf(_("Global")); + break; + case IPV6_ADDR_LINKLOCAL: + printf(_("Link")); + break; + case IPV6_ADDR_SITELOCAL: + printf(_("Site")); + break; + case IPV6_ADDR_COMPATv4: + printf(_("Compat")); + break; + case IPV6_ADDR_LOOPBACK: + printf(_("Host")); + break; + default: + printf(_("Unknown")); + } + printf("\n"); + } + } + fclose(f); + } +#endif + +#if HAVE_AFIPX + if (ipxtype == NULL) + ipxtype = get_afntype(AF_IPX); + + if (ipxtype != NULL) { + if (ptr->has_ipx_bb) + printf(_(" IPX/Ethernet II addr:%s\n"), + ipxtype->sprint(&ptr->ipxaddr_bb, 1)); + if (ptr->has_ipx_sn) + printf(_(" IPX/Ethernet SNAP addr:%s\n"), + ipxtype->sprint(&ptr->ipxaddr_sn, 1)); + if (ptr->has_ipx_e2) + printf(_(" IPX/Ethernet 802.2 addr:%s\n"), + ipxtype->sprint(&ptr->ipxaddr_e2, 1)); + if (ptr->has_ipx_e3) + printf(_(" IPX/Ethernet 802.3 addr:%s\n"), + ipxtype->sprint(&ptr->ipxaddr_e3, 1)); + } +#endif + +#if HAVE_AFATALK + if (ddptype == NULL) + ddptype = get_afntype(AF_APPLETALK); + if (ddptype != NULL) { + if (ptr->has_ddp) + printf(_(" EtherTalk Phase 2 addr:%s\n"), ddptype->sprint(&ptr->ddpaddr, 1)); + } +#endif + +#if HAVE_AFECONET + if (ectype == NULL) + ectype = get_afntype(AF_ECONET); + if (ectype != NULL) { + if (ptr->has_econet) + printf(_(" econet addr:%s\n"), ectype->sprint(&ptr->ecaddr, 1)); + } +#endif + + printf(" "); + /* DONT FORGET TO ADD THE FLAGS IN ife_print_short, too */ + if (ptr->flags == 0) + printf(_("[NO FLAGS] ")); + if (ptr->flags & IFF_UP) + printf(_("UP ")); + if (ptr->flags & IFF_BROADCAST) + printf(_("BROADCAST ")); + if (ptr->flags & IFF_DEBUG) + printf(_("DEBUG ")); + if (ptr->flags & IFF_LOOPBACK) + printf(_("LOOPBACK ")); + if (ptr->flags & IFF_POINTOPOINT) + printf(_("POINTOPOINT ")); + if (ptr->flags & IFF_NOTRAILERS) + printf(_("NOTRAILERS ")); + if (ptr->flags & IFF_RUNNING) + printf(_("RUNNING ")); + if (ptr->flags & IFF_NOARP) + printf(_("NOARP ")); + if (ptr->flags & IFF_PROMISC) + printf(_("PROMISC ")); + if (ptr->flags & IFF_ALLMULTI) + printf(_("ALLMULTI ")); + if (ptr->flags & IFF_SLAVE) + printf(_("SLAVE ")); + if (ptr->flags & IFF_MASTER) + printf(_("MASTER ")); + if (ptr->flags & IFF_MULTICAST) + printf(_("MULTICAST ")); +#ifdef HAVE_DYNAMIC + if (ptr->flags & IFF_DYNAMIC) + printf(_("DYNAMIC ")); +#endif + /* DONT FORGET TO ADD THE FLAGS IN ife_print_short */ + printf(_(" MTU:%d Metric:%d"), + ptr->mtu, ptr->metric ? ptr->metric : 1); +#ifdef SIOCSKEEPALIVE + if (ptr->outfill || ptr->keepalive) + printf(_(" Outfill:%d Keepalive:%d"), + ptr->outfill, ptr->keepalive); +#endif + printf("\n"); + + /* If needed, display the interface statistics. */ + + if (ptr->statistics_valid) { + /* XXX: statistics are currently only printed for the primary address, + * not for the aliases, although strictly speaking they're shared + * by all addresses. + */ + printf(" "); + + printf(_("RX packets:%Lu errors:%lu dropped:%lu overruns:%lu frame:%lu\n"), + ptr->stats.rx_packets, ptr->stats.rx_errors, + ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors, + ptr->stats.rx_frame_errors); + if (can_compress) + printf(_(" compressed:%lu\n"), ptr->stats.rx_compressed); + printf(" "); + printf(_("TX packets:%Lu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n"), + ptr->stats.tx_packets, ptr->stats.tx_errors, + ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors, + ptr->stats.tx_carrier_errors); + printf(_(" collisions:%lu "), ptr->stats.collisions); + if (can_compress) + printf(_("compressed:%lu "), ptr->stats.tx_compressed); + if (ptr->tx_queue_len != -1) + printf(_("txqueuelen:%d "), ptr->tx_queue_len); + printf("\n R"); + print_bytes_scaled(ptr->stats.rx_bytes, " T"); + print_bytes_scaled(ptr->stats.tx_bytes, "\n"); + + } + + if ((ptr->map.irq || ptr->map.mem_start || ptr->map.dma || + ptr->map.base_addr)) { + printf(" "); + if (ptr->map.irq) + printf(_("Interrupt:%d "), ptr->map.irq); + if (ptr->map.base_addr >= 0x100) /* Only print devices using it for + I/O maps */ + printf(_("Base address:0x%lx "), (unsigned long)ptr->map.base_addr); + if (ptr->map.mem_start) { + printf(_("Memory:%lx-%lx "), ptr->map.mem_start, ptr->map.mem_end); + } + if (ptr->map.dma) + printf(_("DMA chan:%x "), ptr->map.dma); + printf("\n"); + } + printf("\n"); +} + + +static int do_if_print(struct interface *ife, void *cookie) +{ + int *opt_a = (int *) cookie; + int res; + + res = do_if_fetch(ife); + if (res >= 0) { + if ((ife->flags & IFF_UP) || *opt_a) + ife_print(ife); + } + return res; +} + +static struct interface *lookup_interface(char *name) +{ + struct interface *ife = NULL; + + if (if_readlist_proc(name) < 0) + return NULL; + ife = add_interface(name); + return ife; +} + +/* for ipv4 add/del modes */ +static int if_print(char *ifname) +{ + int res; + + if (!ifname) { + res = for_all_interfaces(do_if_print, &interface_opt_a); + } else { + struct interface *ife; + + ife = lookup_interface(ifname); + res = do_if_fetch(ife); + if (res >= 0) + ife_print(ife); + } + return res; +} + +int display_interfaces(char *ifname) +{ + int status; + + /* Create a channel to the NET kernel. */ + if ((skfd = sockets_open(0)) < 0) { + perror_msg_and_die("socket"); + } + + /* Do we have to show the current setup? */ + status = if_print(ifname); + close(skfd); + exit(status < 0); +} diff --git a/libbb/isdirectory.c b/libbb/isdirectory.c new file mode 100644 index 000000000..3dfe10522 --- /dev/null +++ b/libbb/isdirectory.c @@ -0,0 +1,66 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Based in part on code from sash, Copyright (c) 1999 by David I. Bell + * Permission has been granted to redistribute this code under the GPL. + * + * 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 "libbb.h" + +/* + * Return TRUE if a fileName is a directory. + * Nonexistant files return FALSE. + */ +int is_directory(const char *fileName, const int followLinks, struct stat *statBuf) +{ + int status; + int didMalloc = 0; + + if (statBuf == NULL) { + statBuf = (struct stat *)xmalloc(sizeof(struct stat)); + ++didMalloc; + } + + if (followLinks == TRUE) + status = stat(fileName, statBuf); + else + status = lstat(fileName, statBuf); + + if (status < 0 || !(S_ISDIR(statBuf->st_mode))) { + status = FALSE; + } + else status = TRUE; + + if (didMalloc) { + free(statBuf); + statBuf = NULL; + } + return status; +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/kernel_version.c b/libbb/kernel_version.c new file mode 100644 index 000000000..694af8e2c --- /dev/null +++ b/libbb/kernel_version.c @@ -0,0 +1,60 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include +#include /* for uname(2) */ + +#include "libbb.h" + +/* Returns kernel version encoded as major*65536 + minor*256 + patch, + * so, for example, to check if the kernel is greater than 2.2.11: + * if (get_kernel_revision() <= 2*65536+2*256+11) { } + */ +extern int get_kernel_revision(void) +{ + struct utsname name; + char *s; + int i, r; + + if (uname(&name) == -1) { + perror_msg("cannot get system information"); + return (0); + } + + s = name.release; + r = 0; + for (i=0 ; i<3 ; i++) { + r = r * 256 + atoi(strtok(s, ".")); + s = NULL; + } + return r; +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/last_char_is.c b/libbb/last_char_is.c new file mode 100644 index 000000000..4e2ee92ed --- /dev/null +++ b/libbb/last_char_is.c @@ -0,0 +1,40 @@ +/* + * busybox library eXtended function + * + * Copyright (C) 2001 Larry Doolittle, + * + * 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 "libbb.h" + +/* Find out if the last character of a string matches the one given Don't + * underrun the buffer if the string length is 0. Also avoids a possible + * space-hogging inline of strlen() per usage. + */ +char * last_char_is(const char *s, int c) +{ + char *sret; + if (!s) + return NULL; + sret = (char *)s+strlen(s)-1; + if (sret>=s && *sret == c) { + return sret; + } else { + return NULL; + } +} diff --git a/libbb/libbb.h b/libbb/libbb.h new file mode 100644 index 000000000..c3b353f2c --- /dev/null +++ b/libbb/libbb.h @@ -0,0 +1,340 @@ +/* vi: set sw=4 ts=4: */ +/* + * Busybox main internal header 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 + */ + +#ifndef __LIBBB_H__ +#define __LIBBB_H__ 1 + +#include +#include +#include +#include + +#include + +#ifndef _BB_INTERNAL_H_ +#include "../busybox.h" +#endif + +#ifdef DMALLOC +#include "dmalloc.h" +#endif + +#include + +#if (__GNU_LIBRARY__ < 5) && (!defined __dietlibc__) +/* libc5 doesn't define socklen_t */ +typedef unsigned int socklen_t; +/* libc5 doesn't implement BSD 4.4 daemon() */ +extern int daemon (int nochdir, int noclose); +/* libc5 doesn't implement strtok_r */ +char *strtok_r(char *s, const char *delim, char **ptrptr); +#endif + +/* Some useful definitions */ +#define FALSE ((int) 0) +#define TRUE ((int) 1) +#define SKIP ((int) 2) + +/* for mtab.c */ +#define MTAB_GETMOUNTPT '1' +#define MTAB_GETDEVICE '2' + +#define BUF_SIZE 8192 +#define EXPAND_ALLOC 1024 + +static inline int is_decimal(int ch) { return ((ch >= '0') && (ch <= '9')); } +static inline int is_octal(int ch) { return ((ch >= '0') && (ch <= '7')); } + +/* Macros for min/max. */ +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +#ifndef MAX +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + + + +extern void show_usage(void) __attribute__ ((noreturn)); +extern void error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))); +extern void error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))); +extern void perror_msg(const char *s, ...); +extern void perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn)); +extern void vherror_msg(const char *s, va_list p); +extern void herror_msg(const char *s, ...); +extern void herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn)); + +/* These two are used internally -- you shouldn't need to use them */ +extern void verror_msg(const char *s, va_list p); +extern void vperror_msg(const char *s, va_list p); + +const char *mode_string(int mode); +const char *time_string(time_t timeVal); +int is_directory(const char *name, int followLinks, struct stat *statBuf); +int isDevice(const char *name); + +int remove_file(const char *path, int flags); +int copy_file(const char *source, const char *dest, int flags); +int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long long chunksize); +char *buildName(const char *dirName, const char *fileName); +int makeString(int argc, const char **argv, char *buf, int bufLen); +char *getChunk(int size); +char *chunkstrdup(const char *str); +void freeChunks(void); +ssize_t safe_read(int fd, void *buf, size_t count); +ssize_t full_write(int fd, const void *buf, size_t len); +ssize_t full_read(int fd, void *buf, size_t len); +int recursive_action(const char *fileName, int recurse, int followLinks, int depthFirst, + int (*fileAction) (const char *fileName, struct stat* statbuf, void* userData), + int (*dirAction) (const char *fileName, struct stat* statbuf, void* userData), + void* userData); + +extern int parse_mode( const char* s, mode_t* theMode); + +extern int get_kernel_revision(void); + +extern int get_console_fd(void); +extern struct mntent *find_mount_point(const char *name, const char *table); +extern void write_mtab(char* blockDevice, char* directory, + char* filesystemType, long flags, char* string_flags); +extern void erase_mtab(const char * name); +extern long atoi_w_units (const char *cp); +extern long* find_pid_by_name( char* pidName); +extern char *find_real_root_device_name(const char* name); +extern char *get_line_from_file(FILE *file); +extern char *get_chomped_line_from_file(FILE *file); +extern void print_file(FILE *file); +extern int copyfd(int fd1, int fd2); +extern int print_file_by_name(char *filename); +extern char process_escape_sequence(const char **ptr); +extern char *get_last_path_component(char *path); +extern FILE *wfopen(const char *path, const char *mode); +extern FILE *xfopen(const char *path, const char *mode); +extern void chomp(char *s); +extern void trim(char *s); +extern struct BB_applet *find_applet_by_name(const char *name); +void run_applet_by_name(const char *name, int argc, char **argv); + +#ifndef DMALLOC +extern void *xmalloc (size_t size); +extern void *xrealloc(void *old, size_t size); +extern void *xcalloc(size_t nmemb, size_t size); +extern char *xstrdup (const char *s); +#endif +extern char *xstrndup (const char *s, int n); +extern char * safe_strncpy(char *dst, const char *src, size_t size); + +struct suffix_mult { + const char *suffix; + int mult; +}; + +extern unsigned long parse_number(const char *numstr, + const struct suffix_mult *suffixes); + + +/* These parse entries in /etc/passwd and /etc/group. This is desirable + * for BusyBox since we want to avoid using the glibc NSS stuff, which + * increases target size and is often not needed embedded systems. */ +extern long my_getpwnam(const char *name); +extern long my_getgrnam(const char *name); +extern void my_getpwuid(char *name, long uid); +extern void my_getgrgid(char *group, long gid); +extern long my_getpwnamegid(const char *name); + +extern int device_open(char *device, int mode); + +extern int del_loop(const char *device); +extern int set_loop(const char *device, const char *file, int offset, int *loopro); +extern char *find_unused_loop_device (void); + + +#if (__GLIBC__ < 2) +extern int vdprintf(int d, const char *format, va_list ap); +#endif + +int nfsmount(const char *spec, const char *node, int *flags, + char **extra_opts, char **mount_opts, int running_bg); + +void syslog_msg_with_name(const char *name, int facility, int pri, const char *msg); +void syslog_msg(int facility, int pri, const char *msg); + +/* Include our own copy of struct sysinfo to avoid binary compatability + * problems with Linux 2.4, which changed things. Grumble, grumble. */ +struct sysinfo { + long uptime; /* Seconds since boot */ + unsigned long loads[3]; /* 1, 5, and 15 minute load averages */ + unsigned long totalram; /* Total usable main memory size */ + unsigned long freeram; /* Available memory size */ + unsigned long sharedram; /* Amount of shared memory */ + unsigned long bufferram; /* Memory used by buffers */ + unsigned long totalswap; /* Total swap space size */ + unsigned long freeswap; /* swap space still available */ + unsigned short procs; /* Number of current processes */ + unsigned short pad; /* Padding needed for m68k */ + unsigned long totalhigh; /* Total high memory size */ + unsigned long freehigh; /* Available high memory size */ + unsigned int mem_unit; /* Memory unit size in bytes */ + char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */ +}; +extern int sysinfo (struct sysinfo* info); + +enum { + KILOBYTE = 1024, + MEGABYTE = (KILOBYTE*1024), + GIGABYTE = (MEGABYTE*1024) +}; +const char *make_human_readable_str(unsigned long size, unsigned long block_size, unsigned long display_unit); + +int ask_confirmation(void); +int klogctl(int type, char * b, int len); + +char *xgetcwd(char *cwd); +char *xreadlink(const char *path); +char *concat_path_file(const char *path, const char *filename); +char *last_char_is(const char *s, int c); + +extern long arith (const char *startbuf, int *errcode); + +typedef struct file_headers_s { + char *name; + char *link_name; + off_t size; + uid_t uid; + gid_t gid; + mode_t mode; + time_t mtime; + dev_t device; +} file_header_t; +file_header_t *get_header_ar(FILE *in_file); +file_header_t *get_header_cpio(FILE *src_stream); +file_header_t *get_header_tar(FILE *tar_stream); + +enum extract_functions_e { + extract_verbose_list = 1, + extract_list = 2, + extract_one_to_buffer = 4, + extract_to_stdout = 8, + extract_all_to_fs = 16, + extract_preserve_date = 32, + extract_data_tar_gz = 64, + extract_control_tar_gz = 128, + extract_unzip_only = 256, + extract_unconditional = 512, + extract_create_leading_dirs = 1024, + extract_quiet = 2048, + extract_exclude_list = 4096 +}; +char *unarchive(FILE *src_stream, FILE *out_stream, file_header_t *(*get_header)(FILE *), + const int extract_function, const char *prefix, char **extract_names); +char *deb_extract(const char *package_filename, FILE *out_stream, const int extract_function, + const char *prefix, const char *filename); +int read_package_field(const char *package_buffer, char **field_name, char **field_value); +char *fgets_str(FILE *file, const char *terminating_string); + +extern int unzip(FILE *l_in_file, FILE *l_out_file); +extern void gz_close(int gunzip_pid); +extern FILE *gz_open(FILE *compressed_file, int *pid); + +extern struct hostent *xgethostbyname(const char *name); +extern int create_icmp_socket(void); + +char *dirname (char *path); + +int make_directory (char *path, long mode, int flags); + +const char *u_signal_names(const char *str_sig, int *signo, int startnum); +char *simplify_path(const char *path); + +#define CT_AUTO 0 +#define CT_UNIX2DOS 1 +#define CT_DOS2UNIX 2 +/* extern int convert(char *fn, int ConvType); */ + +enum { + FILEUTILS_PRESERVE_STATUS = 1, + FILEUTILS_PRESERVE_SYMLINKS = 2, + FILEUTILS_RECUR = 4, + FILEUTILS_FORCE = 8, + FILEUTILS_INTERACTIVE = 16 +}; + +extern const char *applet_name; +extern const char * const full_version; +extern const char * const name_too_long; +extern const char * const omitting_directory; +extern const char * const not_a_directory; +extern const char * const memory_exhausted; +extern const char * const invalid_date; +extern const char * const invalid_option; +extern const char * const io_error; +extern const char * const dash_dash_help; +extern const char * const write_error; +extern const char * const too_few_args; +extern const char * const name_longer_than_foo; +extern const char * const unknown; +extern const char * const can_not_create_raw_socket; + +#ifdef BB_FEATURE_DEVFS +# define CURRENT_VC "/dev/vc/0" +# define VC_1 "/dev/vc/1" +# define VC_2 "/dev/vc/2" +# define VC_3 "/dev/vc/3" +# define VC_4 "/dev/vc/4" +# define VC_5 "/dev/vc/5" +# define SC_0 "/dev/tts/0" +# define SC_1 "/dev/tts/1" +# define VC_FORMAT "/dev/vc/%d" +# define SC_FORMAT "/dev/tts/%d" +# define LOOP_FORMAT "/dev/loop/%d" +#else +# define CURRENT_VC "/dev/tty0" +# define VC_1 "/dev/tty1" +# define VC_2 "/dev/tty2" +# define VC_3 "/dev/tty3" +# define VC_4 "/dev/tty4" +# define VC_5 "/dev/tty5" +# define SC_0 "/dev/ttyS0" +# define SC_1 "/dev/ttyS1" +# define VC_FORMAT "/dev/tty%d" +# define SC_FORMAT "/dev/ttyS%d" +# define LOOP_FORMAT "/dev/loop%d" +#endif + +/* The following devices are the same on devfs and non-devfs systems. */ +#define CURRENT_TTY "/dev/tty" +#define CONSOLE_DEV "/dev/console" + +int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name); +void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name); +void reset_ino_dev_hashtable(void); + + +/* Cope with mmu-less systems somewhat gracefully */ +#ifdef __uClinux__ +#undef fork +#define fork vfork +#endif + +/* Stupid gcc always includes its own builtin strlen()... */ +extern size_t xstrlen(const char *string); +#define strlen(x) xstrlen(x) + +#endif /* __LIBBB_H__ */ diff --git a/libbb/libc5.c b/libbb/libc5.c new file mode 100644 index 000000000..67ab16176 --- /dev/null +++ b/libbb/libc5.c @@ -0,0 +1,168 @@ +/* vi: set sw=4 ts=4: */ + + +#include +#include +#include +#include +#include +#include + + +#if ! defined __dietlibc__ && __GNU_LIBRARY__ < 5 + + +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library 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 Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* + * Modified by Manuel Novoa III Mar 1, 2001 + * + * Converted original strtok.c code of strtok to __strtok_r. + * Cleaned up logic and reduced code size. + */ + + +char *strtok_r(char *s, const char *delim, char **save_ptr) +{ + char *token; + + token = 0; /* Initialize to no token. */ + + if (s == 0) { /* If not first time called... */ + s = *save_ptr; /* restart from where we left off. */ + } + + if (s != 0) { /* If not finished... */ + *save_ptr = 0; + + s += strspn(s, delim); /* Skip past any leading delimiters. */ + if (*s != '\0') { /* We have a token. */ + token = s; + *save_ptr = strpbrk(token, delim); /* Find token's end. */ + if (*save_ptr != 0) { + /* Terminate the token and make SAVE_PTR point past it. */ + *(*save_ptr)++ = '\0'; + } + } + } + + return token; +} + +/* Basically getdelim() with the delimiter hard wired to '\n' */ +ssize_t getline(char **linebuf, size_t *n, FILE *file) +{ + return (getdelim (linebuf, n, '\n', file)); +} + + +#ifndef __uClinux__ +/* + * daemon implementation for uClibc + * + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Modified for uClibc by Erik Andersen + * + * The uClibc Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * The GNU C Library 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 Library General Public + * License along with the GNU C Library; see the file COPYING.LIB. 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. + */ + +int daemon( int nochdir, int noclose ) +{ + int fd; + + switch (fork()) { + case -1: + return(-1); + case 0: + break; + default: + _exit(0); + } + + if (setsid() == -1) + return(-1); + + if (!nochdir) + chdir("/"); + + if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > 2) + close(fd); + } + return(0); +} +#endif /* __uClinux__ */ + + +/*- + * Copyright (c) 1990, 1993 + * The 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. + */ + + +#endif + diff --git a/libbb/loop.c b/libbb/loop.c new file mode 100644 index 000000000..66e8921fa --- /dev/null +++ b/libbb/loop.c @@ -0,0 +1,123 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include +#include +#include +#include +#include "libbb.h" +#include "loop.h" /* Pull in loop device support */ + +extern int del_loop(const char *device) +{ + int fd; + + if ((fd = open(device, O_RDONLY)) < 0) { + perror_msg("%s", device); + return (FALSE); + } + if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { + close(fd); + perror_msg("ioctl: LOOP_CLR_FD"); + return (FALSE); + } + close(fd); + return (TRUE); +} + +extern int set_loop(const char *device, const char *file, int offset, + int *loopro) +{ + struct loop_info loopinfo; + int fd, ffd, mode; + + mode = *loopro ? O_RDONLY : O_RDWR; + if ((ffd = open(file, mode)) < 0 && !*loopro + && (errno != EROFS || (ffd = open(file, mode = O_RDONLY)) < 0)) { + perror_msg("%s", file); + return 1; + } + if ((fd = open(device, mode)) < 0) { + close(ffd); + perror_msg("%s", device); + return 1; + } + *loopro = (mode == O_RDONLY); + + memset(&loopinfo, 0, sizeof(loopinfo)); + safe_strncpy(loopinfo.lo_name, file, LO_NAME_SIZE); + + loopinfo.lo_offset = offset; + + loopinfo.lo_encrypt_key_size = 0; + if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { + perror_msg("ioctl: LOOP_SET_FD"); + close(fd); + close(ffd); + return 1; + } + if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) { + (void) ioctl(fd, LOOP_CLR_FD, 0); + perror_msg("ioctl: LOOP_SET_STATUS"); + close(fd); + close(ffd); + return 1; + } + close(fd); + close(ffd); + return 0; +} + +extern char *find_unused_loop_device(void) +{ + char dev[20]; + int i, fd; + struct stat statbuf; + struct loop_info loopinfo; + + for (i = 0; i <= 7; i++) { + sprintf(dev, LOOP_FORMAT, i); + if (stat(dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { + if ((fd = open(dev, O_RDONLY)) >= 0) { + if (ioctl(fd, LOOP_GET_STATUS, &loopinfo) != 0) { + if (errno == ENXIO) { /* probably free */ + close(fd); + return strdup(dev); + } + } + close(fd); + } + } + } + return NULL; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/make_directory.c b/libbb/make_directory.c new file mode 100644 index 000000000..a06a410d2 --- /dev/null +++ b/libbb/make_directory.c @@ -0,0 +1,71 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini make_directory implementation for busybox + * + * 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 + * + */ + +#include +#include +#include +#include +#include +#include + +#include "libbb.h" + +/* Create the directory PATH with mode MODE, or the default if MODE is -1. + * Also create parent directories as necessary if flags contains + * FILEUTILS_RECUR. */ + +int make_directory (char *path, long mode, int flags) +{ + if (!(flags & FILEUTILS_RECUR)) { + if (mkdir (path, 0777) < 0) { + perror_msg ("Cannot create directory `%s'", path); + return -1; + } + + if (mode != -1 && chmod (path, mode) < 0) { + perror_msg ("Cannot set permissions of directory `%s'", path); + return -1; + } + } else { + struct stat st; + + if (stat (path, &st) < 0 && errno == ENOENT) { + int status; + char *buf, *parent; + mode_t mask; + + mask = umask (0); + umask (mask); + + buf = xstrdup (path); + parent = dirname (buf); + status = make_directory (parent, (0777 & ~mask) | 0300, + FILEUTILS_RECUR); + free (buf); + + if (status < 0 || make_directory (path, mode, 0) < 0) + return -1; + } + } + + return 0; +} diff --git a/libbb/messages.c b/libbb/messages.c new file mode 100644 index 000000000..47b5526e3 --- /dev/null +++ b/libbb/messages.c @@ -0,0 +1,67 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include "libbb.h" + +#ifdef L_full_version + const char * const full_version = BB_BANNER " multi-call binary"; +#endif +#ifdef L_name_too_long + const char * const name_too_long = "file name too long"; +#endif + +#ifdef L_omitting_directory + const char * const omitting_directory = "%s: omitting directory"; +#endif +#ifdef L_not_a_directory + const char * const not_a_directory = "%s: not a directory"; +#endif +#ifdef L_memory_exhausted + const char * const memory_exhausted = "memory exhausted"; +#endif +#ifdef L_invalid_date + const char * const invalid_date = "invalid date `%s'"; +#endif +#ifdef L_invalid_option + const char * const invalid_option = "invalid option -- %c"; +#endif +#ifdef L_io_error + const char * const io_error = "%s: input/output error -- %s"; +#endif +#ifdef L_dash_dash_help + const char * const dash_dash_help = "--help"; +#endif +#ifdef L_write_error + const char * const write_error = "Write Error"; +#endif +#ifdef L_too_few_args + const char * const too_few_args = "too few arguments"; +#endif +#ifdef L_name_longer_than_foo + const char * const name_longer_than_foo = "Names longer than %d chars not supported."; +#endif +#ifdef L_unknown + const char * const unknown = "(unknown)"; +#endif + +#ifdef L_can_not_create_raw_socket + const char * const can_not_create_raw_socket = "can`t create raw socket"; +#endif diff --git a/libbb/mode_string.c b/libbb/mode_string.c new file mode 100644 index 000000000..12dc17966 --- /dev/null +++ b/libbb/mode_string.c @@ -0,0 +1,78 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 "libbb.h" + + + +#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f) +#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)]) + +/* The special bits. If set, display SMODE0/1 instead of MODE0/1 */ +static const mode_t SBIT[] = { + 0, 0, S_ISUID, + 0, 0, S_ISGID, + 0, 0, S_ISVTX +}; + +/* The 9 mode bits to test */ +static const mode_t MBIT[] = { + S_IRUSR, S_IWUSR, S_IXUSR, + S_IRGRP, S_IWGRP, S_IXGRP, + S_IROTH, S_IWOTH, S_IXOTH +}; + +static const char MODE1[] = "rwxrwxrwx"; +static const char MODE0[] = "---------"; +static const char SMODE1[] = "..s..s..t"; +static const char SMODE0[] = "..S..S..T"; + +/* + * Return the standard ls-like mode string from a file mode. + * This is static and so is overwritten on each call. + */ +const char *mode_string(int mode) +{ + static char buf[12]; + + int i; + + buf[0] = TYPECHAR(mode); + for (i = 0; i < 9; i++) { + if (mode & SBIT[i]) + buf[i + 1] = (mode & MBIT[i]) ? SMODE1[i] : SMODE0[i]; + else + buf[i + 1] = (mode & MBIT[i]) ? MODE1[i] : MODE0[i]; + } + return buf; +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/module_syscalls.c b/libbb/module_syscalls.c new file mode 100644 index 000000000..1320a6a25 --- /dev/null +++ b/libbb/module_syscalls.c @@ -0,0 +1,127 @@ +/* vi: set sw=4 ts=4: */ +/* + * some system calls possibly missing from libc + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include +/* Kernel headers before 2.1.mumble need this on the Alpha to get + _syscall* defined. */ +#define __LIBRARY__ +#include +#if __GNU_LIBRARY__ < 5 +/* This is needed for libc5 */ +#include +#endif +#include "libbb.h" + + +#if __GNU_LIBRARY__ < 5 || ((__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)) + +#if __GNU_LIBRARY__ < 5 +/* These syscalls are not included as part of libc5 */ +_syscall1(int, delete_module, const char *, name); +_syscall1(int, get_kernel_syms, __ptr_t, ks); + +/* This may have 5 arguments (for old 2.0 kernels) or 2 arguments + * (for 2.2 and 2.4 kernels). Use the greatest common denominator, + * and let the kernel cope with whatever it gets. Its good at that. */ +_syscall5(int, init_module, void *, first, void *, second, void *, third, + void *, fourth, void *, fifth); +#else +int delete_module(const char *name) +{ + return(syscall(__NR_delete_module, name)); +} +int get_kernel_syms(__ptr_t ks) +{ + return(syscall(__NR_get_kernel_syms, ks)); +} + +/* This may have 5 arguments (for old 2.0 kernels) or 2 arguments + * (for 2.2 and 2.4 kernels). Use the greatest common denominator, + * and let the kernel cope with whatever it gets. Its good at that. */ +int init_module(void *first, void *second, void *third, void *fourth, void *fifth) +{ + return(syscall(__NR_init_module, first, second, third, fourth, fifth)); +} +#endif + +#ifndef __NR_query_module +#warning This kernel does not support the query_module syscall +#warning -> The query_module system call is being stubbed out... +int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret) +{ + fprintf(stderr, "\n\nTo make this application work, you will need to recompile\n"); + fprintf(stderr, "with a kernel supporting the query_module system call. -Erik\n\n"); + errno=ENOSYS; + return -1; +} +#else +# if __GNU_LIBRARY__ < 5 +_syscall5(int, query_module, const char *, name, int, which, + void *, buf, size_t, bufsize, size_t*, ret); +# else + return(syscall(__NR_query_module, name, which, buf, bufsize, ret)); +# endif +#endif + +# if __GNU_LIBRARY__ < 5 +/* Jump through hoops to fixup error return codes */ +#define __NR___create_module __NR_create_module +static inline _syscall2(long, __create_module, const char *, name, size_t, size) +unsigned long create_module(const char *name, size_t size) +{ + long ret = __create_module(name, size); + + if (ret == -1 && errno > 125) { + ret = -errno; + errno = 0; + } + return ret; +} +#else +/* Jump through hoops to fixup error return codes */ +unsigned long create_module(const char *name, size_t size) +{ + long ret = syscall(__NR_create_module, name, size); + + if (ret == -1 && errno > 125) { + ret = -errno; + errno = 0; + } + return ret; +} +#endif + +#endif /* __GNU_LIBRARY__ < 5 */ + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ + diff --git a/libbb/mtab.c b/libbb/mtab.c new file mode 100644 index 000000000..c521b1e05 --- /dev/null +++ b/libbb/mtab.c @@ -0,0 +1,115 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include +#include +#include +#include +#include "libbb.h" + +extern const char mtab_file[]; /* Defined in utility.c */ +static const int MS_RDONLY = 1; /* Mount read-only. */ + +void erase_mtab(const char *name) +{ + struct mntent entries[20]; + int count = 0; + FILE *mountTable = setmntent(mtab_file, "r"); + struct mntent *m; + + /* Check if reading the mtab file failed */ + if (mountTable == 0 + /* Bummer. fall back on trying the /proc filesystem */ + && (mountTable = setmntent("/proc/mounts", "r")) == 0) { + perror_msg("%s", mtab_file); + return; + } + + while ((m = getmntent(mountTable)) != 0) { + entries[count].mnt_fsname = strdup(m->mnt_fsname); + entries[count].mnt_dir = strdup(m->mnt_dir); + entries[count].mnt_type = strdup(m->mnt_type); + entries[count].mnt_opts = strdup(m->mnt_opts); + entries[count].mnt_freq = m->mnt_freq; + entries[count].mnt_passno = m->mnt_passno; + count++; + } + endmntent(mountTable); + if ((mountTable = setmntent(mtab_file, "w"))) { + int i; + + for (i = 0; i < count; i++) { + int result = (strcmp(entries[i].mnt_fsname, name) == 0 + || strcmp(entries[i].mnt_dir, name) == 0); + + if (result) + continue; + else + addmntent(mountTable, &entries[i]); + } + endmntent(mountTable); + } else if (errno != EROFS) + perror_msg("%s", mtab_file); +} + +void write_mtab(char *blockDevice, char *directory, + char *filesystemType, long flags, char *string_flags) +{ + FILE *mountTable = setmntent(mtab_file, "a+"); + struct mntent m; + + if (mountTable == 0) { + perror_msg("%s", mtab_file); + return; + } + if (mountTable) { + int length = strlen(directory); + + if (length > 1 && directory[length - 1] == '/') + directory[length - 1] = '\0'; + + if (filesystemType == 0) { + struct mntent *p = find_mount_point(blockDevice, "/proc/mounts"); + + if (p && p->mnt_type) + filesystemType = p->mnt_type; + } + m.mnt_fsname = blockDevice; + m.mnt_dir = directory; + m.mnt_type = filesystemType ? filesystemType : "default"; + + if (*string_flags) { + m.mnt_opts = string_flags; + } else { + if ((flags | MS_RDONLY) == flags) + m.mnt_opts = "ro"; + else + m.mnt_opts = "rw"; + } + + m.mnt_freq = 0; + m.mnt_passno = 0; + addmntent(mountTable, &m); + endmntent(mountTable); + } +} diff --git a/libbb/mtab_file.c b/libbb/mtab_file.c new file mode 100644 index 000000000..e6ccd09eb --- /dev/null +++ b/libbb/mtab_file.c @@ -0,0 +1,46 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include "libbb.h" + + +/* Busybox mount uses either /proc/mounts or /dev/mtab to + * get the list of currently mounted filesystems */ +#if defined BB_FEATURE_MTAB_SUPPORT +const char mtab_file[] = "/etc/mtab"; +#else +# if defined BB_FEATURE_USE_DEVPS_PATCH + const char mtab_file[] = "/dev/mtab"; +# else + const char mtab_file[] = "/proc/mounts"; +# endif +#endif + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/my_getgrgid.c b/libbb/my_getgrgid.c new file mode 100644 index 000000000..78f800158 --- /dev/null +++ b/libbb/my_getgrgid.c @@ -0,0 +1,49 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include "../pwd_grp/pwd.h" +#include "../pwd_grp/grp.h" +#include "libbb.h" + + +/* gets a groupname given a gid */ +void my_getgrgid(char *group, long gid) +{ + struct group *mygroup; + + mygroup = getgrgid(gid); + if (mygroup==NULL) + sprintf(group, "%-8ld ", (long)gid); + else + strcpy(group, mygroup->gr_name); +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/my_getgrnam.c b/libbb/my_getgrnam.c new file mode 100644 index 000000000..bea4ce062 --- /dev/null +++ b/libbb/my_getgrnam.c @@ -0,0 +1,50 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include "../pwd_grp/pwd.h" +#include "../pwd_grp/grp.h" +#include "libbb.h" + + + +/* returns a gid given a group name */ +long my_getgrnam(const char *name) +{ + struct group *mygroup; + + mygroup = getgrnam(name); + if (mygroup==NULL) + error_msg_and_die("unknown group name: %s", name); + + return (mygroup->gr_gid); +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/my_getpwnam.c b/libbb/my_getpwnam.c new file mode 100644 index 000000000..2fc010137 --- /dev/null +++ b/libbb/my_getpwnam.c @@ -0,0 +1,50 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include "../pwd_grp/pwd.h" +#include "../pwd_grp/grp.h" +#include "libbb.h" + + + +/* returns a uid given a username */ +long my_getpwnam(const char *name) +{ + struct passwd *myuser; + + myuser = getpwnam(name); + if (myuser==NULL) + error_msg_and_die("unknown user name: %s", name); + + return myuser->pw_uid; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/my_getpwnamegid.c b/libbb/my_getpwnamegid.c new file mode 100644 index 000000000..687c52c7e --- /dev/null +++ b/libbb/my_getpwnamegid.c @@ -0,0 +1,55 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include "../pwd_grp/pwd.h" +#include "../pwd_grp/grp.h" +#include "libbb.h" + + + +/* gets a gid given a user name */ +long my_getpwnamegid(const char *name) +{ + struct group *mygroup; + struct passwd *myuser; + + myuser=getpwnam(name); + if (myuser==NULL) + error_msg_and_die("unknown user name: %s", name); + + mygroup = getgrgid(myuser->pw_gid); + if (mygroup==NULL) + error_msg_and_die("unknown gid %ld", (long)myuser->pw_gid); + + return mygroup->gr_gid; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/my_getpwuid.c b/libbb/my_getpwuid.c new file mode 100644 index 000000000..8dd828881 --- /dev/null +++ b/libbb/my_getpwuid.c @@ -0,0 +1,49 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include "../pwd_grp/pwd.h" +#include "../pwd_grp/grp.h" +#include "libbb.h" + + + +/* gets a username given a uid */ +void my_getpwuid(char *name, long uid) +{ + struct passwd *myuser; + + myuser = getpwuid(uid); + if (myuser==NULL) + sprintf(name, "%-8ld ", (long)uid); + else + strcpy(name, myuser->pw_name); +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/parse_mode.c b/libbb/parse_mode.c new file mode 100644 index 000000000..ba34ea929 --- /dev/null +++ b/libbb/parse_mode.c @@ -0,0 +1,134 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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" + + +/* This function parses the sort of string you might pass + * to chmod (i.e., [ugoa]{+|-|=}[rwxst] ) and returns the + * correct mode described by the string. */ +extern int parse_mode(const char *s, mode_t * theMode) +{ + static const mode_t group_set[] = { + S_ISUID | S_IRWXU, /* u */ + S_ISGID | S_IRWXG, /* g */ + S_IRWXO, /* o */ + S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO /* a */ + }; + + static const mode_t mode_set[] = { + S_IRUSR | S_IRGRP | S_IROTH, /* r */ + S_IWUSR | S_IWGRP | S_IWOTH, /* w */ + S_IXUSR | S_IXGRP | S_IXOTH, /* x */ + S_ISUID | S_ISGID, /* s */ + S_ISVTX /* t */ + }; + + static const char group_chars[] = "ugoa"; + static const char mode_chars[] = "rwxst"; + + const char *p; + + mode_t andMode = + S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO; + mode_t orMode = 0; + mode_t mode; + mode_t groups; + char type; + char c; + + if (s==NULL) { + return (FALSE); + } + + do { + mode = 0; + groups = 0; + NEXT_GROUP: + if ((c = *s++) == '\0') { + return -1; + } + for (p=group_chars ; *p ; p++) { + if (*p == c) { + groups |= group_set[(int)(p-group_chars)]; + goto NEXT_GROUP; + } + } + switch (c) { + case '=': + case '+': + case '-': + type = c; + if (groups == 0) { /* The default is "all" */ + groups |= S_ISUID | S_ISGID | S_ISVTX + | S_IRWXU | S_IRWXG | S_IRWXO; + } + break; + default: + if ((c < '0') || (c > '7') || (mode | groups)) { + return (FALSE); + } else { + *theMode = strtol(--s, NULL, 8); + return (TRUE); + } + } + + NEXT_MODE: + if (((c = *s++) != '\0') && (c != ',')) { + for (p=mode_chars ; *p ; p++) { + if (*p == c) { + mode |= mode_set[(int)(p-mode_chars)]; + goto NEXT_MODE; + } + } + break; /* We're done so break out of loop.*/ + } + switch (type) { + case '=': + andMode &= ~(groups); /* Now fall through. */ + case '+': + orMode |= mode & groups; + break; + case '-': + andMode &= ~(mode & groups); + orMode &= ~(mode & groups); + break; + } + } while (c == ','); + + *theMode &= andMode; + *theMode |= orMode; + + return TRUE; +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/parse_number.c b/libbb/parse_number.c new file mode 100644 index 000000000..755a357ad --- /dev/null +++ b/libbb/parse_number.c @@ -0,0 +1,70 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 "libbb.h" + + +unsigned long parse_number(const char *numstr, + const struct suffix_mult *suffixes) +{ + const struct suffix_mult *sm; + unsigned long int ret; + int len; + char *end; + + ret = strtoul(numstr, &end, 10); + if (numstr == end) + error_msg_and_die("invalid number `%s'", numstr); + while (end[0] != '\0') { + sm = suffixes; + while ( sm != 0 ) { + if(sm->suffix) { + len = strlen(sm->suffix); + if (strncmp(sm->suffix, end, len) == 0) { + ret *= sm->mult; + end += len; + break; + } + sm++; + + } else + sm = 0; + } + if (sm == 0) + error_msg_and_die("invalid number `%s'", numstr); + } + return ret; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/perror_msg.c b/libbb/perror_msg.c new file mode 100644 index 000000000..8c57b0d16 --- /dev/null +++ b/libbb/perror_msg.c @@ -0,0 +1,45 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include +#include +#include "libbb.h" + +extern void perror_msg(const char *s, ...) +{ + va_list p; + + va_start(p, s); + vperror_msg(s, p); + va_end(p); +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/perror_msg_and_die.c b/libbb/perror_msg_and_die.c new file mode 100644 index 000000000..9004925cc --- /dev/null +++ b/libbb/perror_msg_and_die.c @@ -0,0 +1,46 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include +#include +#include "libbb.h" + +extern void perror_msg_and_die(const char *s, ...) +{ + va_list p; + + va_start(p, s); + vperror_msg(s, p); + va_end(p); + exit(EXIT_FAILURE); +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/print_file.c b/libbb/print_file.c new file mode 100644 index 000000000..bfedc5eff --- /dev/null +++ b/libbb/print_file.c @@ -0,0 +1,61 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999-2001 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 "libbb.h" + + +extern void print_file(FILE *file) +{ + fflush(stdout); + copyfd(fileno(file), fileno(stdout)); + fclose(file); +} + +extern int print_file_by_name(char *filename) +{ + struct stat statBuf; + int status = TRUE; + + if(is_directory(filename, TRUE, &statBuf)==TRUE) { + error_msg("%s: Is directory", filename); + status = FALSE; + } else { + FILE *f = wfopen(filename, "r"); + if(f!=NULL) + print_file(f); + else + status = FALSE; + } + + return status; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/process_escape_sequence.c b/libbb/process_escape_sequence.c new file mode 100644 index 000000000..67b0490ce --- /dev/null +++ b/libbb/process_escape_sequence.c @@ -0,0 +1,80 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) Manuel Nova III + * and Vladimir Oleynik + * + * 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" + + + +char process_escape_sequence(const char **ptr) +{ + static const char charmap[] = { + 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', 0, + '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' }; + + const char *p; + const char *q; + int num_digits; + unsigned int n; + + n = 0; + q = *ptr; + + for ( num_digits = 0 ; num_digits < 3 ; ++num_digits) { + if ((*q < '0') || (*q > '7')) { /* not a digit? */ + break; + } + n = n * 8 + (*q++ - '0'); + } + + if (num_digits == 0) { /* mnemonic escape sequence? */ + for (p=charmap ; *p ; p++) { + if (*p == *q) { + q++; + break; + } + } + n = *(p+(sizeof(charmap)/2)); + } + + /* doesn't hurt to fall through to here from mnemonic case */ + if (n > UCHAR_MAX) { /* is octal code too big for a char? */ + n /= 8; /* adjust value and */ + --q; /* back up one char */ + } + + *ptr = q; + return (char) n; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/read_package_field.c b/libbb/read_package_field.c new file mode 100644 index 000000000..ac5f80167 --- /dev/null +++ b/libbb/read_package_field.c @@ -0,0 +1,114 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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" + +/* + * Gets the next package field from package_buffer, seperated into the field name + * and field value, it returns the int offset to the first character of the next field + */ +int read_package_field(const char *package_buffer, char **field_name, char **field_value) +{ + int offset_name_start = 0; + int offset_name_end = 0; + int offset_value_start = 0; + int offset_value_end = 0; + int offset = 0; + int next_offset; + int name_length; + int value_length; + int exit_flag = FALSE; + + if (package_buffer == NULL) { + *field_name = NULL; + *field_value = NULL; + return(-1); + } + while (1) { + next_offset = offset + 1; + switch (package_buffer[offset]) { + case('\0'): + exit_flag = TRUE; + break; + case(':'): + if (offset_name_end == 0) { + offset_name_end = offset; + offset_value_start = next_offset; + } + /* TODO: Name might still have trailing spaces if ':' isnt + * immediately after name */ + break; + case('\n'): + /* TODO: The char next_offset may be out of bounds */ + if (package_buffer[next_offset] != ' ') { + exit_flag = TRUE; + break; + } + case('\t'): + case(' '): + /* increment the value start point if its a just filler */ + if (offset_name_start == offset) { + offset_name_start++; + } + if (offset_value_start == offset) { + offset_value_start++; + } + break; + } + if (exit_flag == TRUE) { + /* Check that the names are valid */ + offset_value_end = offset; + name_length = offset_name_end - offset_name_start; + value_length = offset_value_end - offset_value_start; + if (name_length == 0) { + break; + } + if ((name_length > 0) && (value_length > 0)) { + break; + } + + /* If not valid, start fresh with next field */ + exit_flag = FALSE; + offset_name_start = offset + 1; + offset_name_end = 0; + offset_value_start = offset + 1; + offset_value_end = offset + 1; + offset++; + } + offset++; + } + if (name_length == 0) { + *field_name = NULL; + } else { + *field_name = xstrndup(&package_buffer[offset_name_start], name_length); + } + if (value_length > 0) { + *field_value = xstrndup(&package_buffer[offset_value_start], value_length); + } else { + *field_value = NULL; + } + return(next_offset); +} + diff --git a/libbb/real_loop.h b/libbb/real_loop.h new file mode 100644 index 000000000..1bd7fa87a --- /dev/null +++ b/libbb/real_loop.h @@ -0,0 +1,37 @@ +/* + * include/linux/loop.h + * + * Written by Theodore Ts'o, 3/29/93. + * + * Copyright 1993 by Theodore Ts'o. Redistribution of this file is + * permitted under the GNU Public License. + */ + +#define LO_NAME_SIZE 64 +#define LO_KEY_SIZE 32 + +struct loop_info { + int lo_number; /* ioctl r/o */ + dev_t lo_device; /* ioctl r/o */ + unsigned long lo_inode; /* ioctl r/o */ + dev_t lo_rdevice; /* ioctl r/o */ + int lo_offset; + int lo_encrypt_type; + int lo_encrypt_key_size; /* ioctl w/o */ + int lo_flags; /* ioctl r/o */ + char lo_name[LO_NAME_SIZE]; + unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ + unsigned long lo_init[2]; + char reserved[4]; +}; + +#define LO_CRYPT_NONE 0 +#define LO_CRYPT_XOR 1 +#define LO_CRYPT_DES 2 +#define LO_CRYPT_IDEA 3 +#define MAX_LO_CRYPT 4 + +#define LOOP_SET_FD 0x4C00 +#define LOOP_CLR_FD 0x4C01 +#define LOOP_SET_STATUS 0x4C02 +#define LOOP_GET_STATUS 0x4C03 diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c new file mode 100644 index 000000000..e87ab9860 --- /dev/null +++ b/libbb/recursive_action.c @@ -0,0 +1,144 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include +#include +#include /* free() */ +#include "libbb.h" + +#undef DEBUG_RECURS_ACTION + + +/* + * Walk down all the directories under the specified + * location, and do something (something specified + * by the fileAction and dirAction function pointers). + * + * Unfortunately, while nftw(3) could replace this and reduce + * code size a bit, nftw() wasn't supported before GNU libc 2.1, + * and so isn't sufficiently portable to take over since glibc2.1 + * is so stinking huge. + */ +int recursive_action(const char *fileName, + int recurse, int followLinks, int depthFirst, + int (*fileAction) (const char *fileName, + struct stat * statbuf, + void* userData), + int (*dirAction) (const char *fileName, + struct stat * statbuf, + void* userData), + void* userData) +{ + int status; + struct stat statbuf; + struct dirent *next; + + if (followLinks == TRUE) + status = stat(fileName, &statbuf); + else + status = lstat(fileName, &statbuf); + + if (status < 0) { +#ifdef DEBUG_RECURS_ACTION + fprintf(stderr, + "status=%d followLinks=%d TRUE=%d\n", + status, followLinks, TRUE); +#endif + perror_msg("%s", fileName); + return FALSE; + } + + if ((followLinks == FALSE) && (S_ISLNK(statbuf.st_mode))) { + if (fileAction == NULL) + return TRUE; + else + return fileAction(fileName, &statbuf, userData); + } + + if (recurse == FALSE) { + if (S_ISDIR(statbuf.st_mode)) { + if (dirAction != NULL) + return (dirAction(fileName, &statbuf, userData)); + else + return TRUE; + } + } + + if (S_ISDIR(statbuf.st_mode)) { + DIR *dir; + + if (dirAction != NULL && depthFirst == FALSE) { + status = dirAction(fileName, &statbuf, userData); + if (status == FALSE) { + perror_msg("%s", fileName); + return FALSE; + } else if (status == SKIP) + return TRUE; + } + dir = opendir(fileName); + if (!dir) { + perror_msg("%s", fileName); + return FALSE; + } + status = TRUE; + while ((next = readdir(dir)) != NULL) { + char *nextFile; + + if ((strcmp(next->d_name, "..") == 0) + || (strcmp(next->d_name, ".") == 0)) { + continue; + } + nextFile = concat_path_file(fileName, next->d_name); + if (recursive_action(nextFile, TRUE, followLinks, depthFirst, + fileAction, dirAction, userData) == FALSE) { + status = FALSE; + } + free(nextFile); + } + closedir(dir); + if (dirAction != NULL && depthFirst == TRUE) { + if (dirAction(fileName, &statbuf, userData) == FALSE) { + perror_msg("%s", fileName); + return FALSE; + } + } + if (status == FALSE) + return FALSE; + } else { + if (fileAction == NULL) + return TRUE; + else + return fileAction(fileName, &statbuf, userData); + } + return TRUE; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/remove_file.c b/libbb/remove_file.c new file mode 100644 index 000000000..988b09124 --- /dev/null +++ b/libbb/remove_file.c @@ -0,0 +1,126 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini remove_file implementation for busybox + * + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libbb.h" + +extern int remove_file(const char *path, int flags) +{ + struct stat path_stat; + int path_exists = 1; + + if (lstat(path, &path_stat) < 0) { + if (errno != ENOENT) { + perror_msg("unable to stat `%s'", path); + return -1; + } + + path_exists = 0; + } + + if (!path_exists) { + if (!(flags & FILEUTILS_FORCE)) { + perror_msg("cannot remove `%s'", path); + return -1; + } + return 0; + } + + if (S_ISDIR(path_stat.st_mode)) { + DIR *dp; + struct dirent *d; + int status = 0; + + if (!(flags & FILEUTILS_RECUR)) { + error_msg("%s: is a directory", path); + return -1; + } + + if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 && + isatty(0)) || + (flags & FILEUTILS_INTERACTIVE)) { + fprintf(stderr, "%s: descend into directory `%s'? ", applet_name, + path); + if (!ask_confirmation()) + return 0; + } + + if ((dp = opendir(path)) == NULL) { + perror_msg("unable to open `%s'", path); + return -1; + } + + while ((d = readdir(dp)) != NULL) { + char *new_path; + + if (strcmp(d->d_name, ".") == 0 || + strcmp(d->d_name, "..") == 0) + continue; + + new_path = concat_path_file(path, d->d_name); + if (remove_file(new_path, flags) < 0) + status = -1; + free(new_path); + } + + if (closedir(dp) < 0) { + perror_msg("unable to close `%s'", path); + return -1; + } + + if (flags & FILEUTILS_INTERACTIVE) { + fprintf(stderr, "%s: remove directory `%s'? ", applet_name, path); + if (!ask_confirmation()) + return status; + } + + if (rmdir(path) < 0) { + perror_msg("unable to remove `%s'", path); + return -1; + } + + return status; + } else { + if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 && + !S_ISLNK(path_stat.st_mode) && + isatty(0)) || + (flags & FILEUTILS_INTERACTIVE)) { + fprintf(stderr, "%s: remove `%s'? ", applet_name, path); + if (!ask_confirmation()) + return 0; + } + + if (unlink(path) < 0) { + perror_msg("unable to remove `%s'", path); + return -1; + } + + return 0; + } +} diff --git a/libbb/safe_read.c b/libbb/safe_read.c new file mode 100644 index 000000000..67f3268c5 --- /dev/null +++ b/libbb/safe_read.c @@ -0,0 +1,48 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * 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 + */ + +#include +#include +#include +#include "libbb.h" + + + +ssize_t safe_read(int fd, void *buf, size_t count) +{ + ssize_t n; + + do { + n = read(fd, buf, count); + } while (n < 0 && errno == EINTR); + + return n; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/safe_strncpy.c b/libbb/safe_strncpy.c new file mode 100644 index 000000000..0c5cf12ef --- /dev/null +++ b/libbb/safe_strncpy.c @@ -0,0 +1,42 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include "libbb.h" + + + +/* Like strncpy but make sure the resulting string is always 0 terminated. */ +extern char * safe_strncpy(char *dst, const char *src, size_t size) +{ + dst[size-1] = '\0'; + return strncpy(dst, src, size-1); +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/safe_write.c b/libbb/safe_write.c new file mode 100644 index 000000000..0ac6c2d96 --- /dev/null +++ b/libbb/safe_write.c @@ -0,0 +1,48 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * 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 + */ + +#include +#include +#include +#include "libbb.h" + + + +ssize_t safe_write(int fd, const void *buf, size_t count) +{ + ssize_t n; + + do { + n = write(fd, buf, count); + } while (n < 0 && errno == EINTR); + + return n; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/simplify_path.c b/libbb/simplify_path.c new file mode 100644 index 000000000..7b2a1ca51 --- /dev/null +++ b/libbb/simplify_path.c @@ -0,0 +1,65 @@ +/* vi: set sw=4 ts=4: */ +/* + * simplify_path implementation for busybox + * + * Copyright (C) 2001 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 "libbb.h" + +char *simplify_path(const char *path) +{ + char *s, *start, *p; + + if (path[0] == '/') + start = xstrdup(path); + else { + s = xgetcwd(NULL); + start = concat_path_file(s, path); + free(s); + } + p = s = start; + + do { + if (*p == '/') { + if (*s == '/') { /* skip duplicate (or initial) slash */ + continue; + } else if (*s == '.') { + if (s[1] == '/' || s[1] == 0) { /* remove extra '.' */ + continue; + } else if ((s[1] == '.') && (s[2] == '/' || s[2] == 0)) { + ++s; + if (p > start) { + while (*--p != '/'); /* omit previous dir */ + } + continue; + } + } + } + *++p = *s; + } while (*++s); + + if ((p == start) || (*p != '/')) { /* not a trailing slash */ + ++p; /* so keep last character */ + } + *p = 0; + + return start; +} diff --git a/libbb/syscalls.c b/libbb/syscalls.c new file mode 100644 index 000000000..765868840 --- /dev/null +++ b/libbb/syscalls.c @@ -0,0 +1,135 @@ +/* vi: set sw=4 ts=4: */ +/* + * some system calls possibly missing from libc + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include +/* Kernel headers before 2.1.mumble need this on the Alpha to get + _syscall* defined. */ +#define __LIBRARY__ +#include +#if __GNU_LIBRARY__ < 5 +/* This is needed for libc5 */ +#include +#endif +#include "libbb.h" + +#if __GNU_LIBRARY__ < 5 +_syscall3(int, sysfs, int, option, unsigned int, fs_index, char *, buf); +#else +int sysfs( int option, unsigned int fs_index, char * buf) +{ + return(syscall(__NR_sysfs, option, fs_index, buf)); +} +#endif + +#ifndef __NR_pivot_root +#warning This kernel does not support the pivot_root syscall +#warning -> The pivot_root system call is being stubbed out... +int pivot_root(const char * new_root,const char * put_old) +{ + /* BusyBox was compiled against a kernel that did not support + * the pivot_root system call. To make this application work, + * you will need to recompile with a kernel supporting the + * pivot_root system call. + */ + fprintf(stderr, "\n\nTo make this application work, you will need to recompile\n"); + fprintf(stderr, "with a kernel supporting the pivot_root system call. -Erik\n\n"); + errno=ENOSYS; + return -1; +} +#else +# if __GNU_LIBRARY__ < 5 + _syscall2(int,pivot_root,const char *,new_root,const char *,put_old); +# else + int pivot_root(const char * new_root,const char * put_old) + { + return(syscall(__NR_pivot_root, new_root, put_old)); + } +# endif +#endif + + + +/* These syscalls are not included in ancient glibc versions */ +#if __GNU_LIBRARY__ < 5 || ((__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)) + + +#if __GNU_LIBRARY__ < 5 +/* These syscalls are not included as part of libc5 */ +_syscall2(int, bdflush, int, func, int, data); +#else +int bdflush(int func, int data) +{ + return(syscall(__NR_bdflush, func, data)); +} +#endif + +#ifndef __alpha__ +#if __GNU_LIBRARY__ < 5 +# define __NR_klogctl __NR_syslog +_syscall3(int, klogctl, int, type, char *, b, int, len); +#else +int klogctl(int type, char *b, int len) +{ + return(syscall(__NR_klogctl, type, b, len)); +} +#endif +#endif + + +int umount2(const char * special_file, int flags) +{ +#ifndef __NR_pivot_root +#warning This kernel does not support the umount2 syscall +#warning -> The umount2 system call is being stubbed out... + /* BusyBox was compiled against a kernel that did not support + * the umount2 system call. To make this application work, + * you will need to recompile with a kernel supporting the + * umount2 system call. + */ + bb_error_msg("\n\nTo make this application work, you will need to recompile\n" + "BusyBox with a kernel supporting the umount2 system call.\n"); + errno=ENOSYS; + return -1; +#else +# if __GNU_LIBRARY__ < 5 + _syscall2(int, umount2, const char *, special_file, int, flags); +# else + return(syscall(__NR_umount2, special_file, flags)); +# endif +#endif +} + + +#endif /* __GNU_LIBRARY__ < 5 || ((__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)) */ + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/syslog_msg_with_name.c b/libbb/syslog_msg_with_name.c new file mode 100644 index 000000000..6474da459 --- /dev/null +++ b/libbb/syslog_msg_with_name.c @@ -0,0 +1,45 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include "libbb.h" + +void syslog_msg_with_name(const char *name, int facility, int pri, const char *msg) +{ + openlog(name, 0, facility); + syslog(pri, "%s", msg); + closelog(); +} + +void syslog_msg(int facility, int pri, const char *msg) +{ + syslog_msg_with_name(applet_name, facility, pri, msg); +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/time_string.c b/libbb/time_string.c new file mode 100644 index 000000000..d103a02f8 --- /dev/null +++ b/libbb/time_string.c @@ -0,0 +1,62 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include +#include +#include "libbb.h" + + +/* + * Return the standard ls-like time string from a time_t + * This is static and so is overwritten on each call. + */ +const char *time_string(time_t timeVal) +{ + time_t now; + char *str; + static char buf[26]; + + time(&now); + + str = ctime(&timeVal); + + strcpy(buf, &str[4]); + buf[12] = '\0'; + + if ((timeVal > now) || (timeVal < now - 365 * 24 * 60 * 60L)) { + strcpy(&buf[7], &str[20]); + buf[11] = '\0'; + } + + return buf; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/trim.c b/libbb/trim.c new file mode 100644 index 000000000..cb673cac3 --- /dev/null +++ b/libbb/trim.c @@ -0,0 +1,49 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 "libbb.h" + + +void trim(char *s) +{ + int len = strlen(s); + + /* trim trailing whitespace */ + while ( len > 0 && isspace(s[len-1])) + s[--len]='\0'; + + /* trim leading whitespace */ + memmove(s, &s[strspn(s, " \n\r\t\v")], len); +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/u_signal_names.c b/libbb/u_signal_names.c new file mode 100644 index 000000000..aee1db07c --- /dev/null +++ b/libbb/u_signal_names.c @@ -0,0 +1,189 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 + +struct signal_name { + const char *name; + int number; +}; + +static const struct signal_name signames[] = { + /* POSIX signals */ + { "EXIT", 0 }, /* 0 */ + { "HUP", SIGHUP }, /* 1 */ + { "INT", SIGINT }, /* 2 */ + { "QUIT", SIGQUIT }, /* 3 */ + { "ILL", SIGILL }, /* 4 */ + { "ABRT", SIGABRT }, /* 6 */ + { "FPE", SIGFPE }, /* 8 */ + { "KILL", SIGKILL }, /* 9 */ + { "SEGV", SIGSEGV }, /* 11 */ + { "PIPE", SIGPIPE }, /* 13 */ + { "ALRM", SIGALRM }, /* 14 */ + { "TERM", SIGTERM }, /* 15 */ + { "USR1", SIGUSR1 }, /* 10 (arm,i386,m68k,ppc), 30 (alpha,sparc*), 16 (mips) */ + { "USR2", SIGUSR2 }, /* 12 (arm,i386,m68k,ppc), 31 (alpha,sparc*), 17 (mips) */ + { "CHLD", SIGCHLD }, /* 17 (arm,i386,m68k,ppc), 20 (alpha,sparc*), 18 (mips) */ + { "CONT", SIGCONT }, /* 18 (arm,i386,m68k,ppc), 19 (alpha,sparc*), 25 (mips) */ + { "STOP", SIGSTOP }, /* 19 (arm,i386,m68k,ppc), 17 (alpha,sparc*), 23 (mips) */ + { "TSTP", SIGTSTP }, /* 20 (arm,i386,m68k,ppc), 18 (alpha,sparc*), 24 (mips) */ + { "TTIN", SIGTTIN }, /* 21 (arm,i386,m68k,ppc,alpha,sparc*), 26 (mips) */ + { "TTOU", SIGTTOU }, /* 22 (arm,i386,m68k,ppc,alpha,sparc*), 27 (mips) */ + /* Miscellaneous other signals */ +#ifdef SIGTRAP + { "TRAP", SIGTRAP }, /* 5 */ +#endif +#ifdef SIGIOT + { "IOT", SIGIOT }, /* 6, same as SIGABRT */ +#endif +#ifdef SIGEMT + { "EMT", SIGEMT }, /* 7 (mips,alpha,sparc*) */ +#endif +#ifdef SIGBUS + { "BUS", SIGBUS }, /* 7 (arm,i386,m68k,ppc), 10 (mips,alpha,sparc*) */ +#endif +#ifdef SIGSYS + { "SYS", SIGSYS }, /* 12 (mips,alpha,sparc*) */ +#endif +#ifdef SIGSTKFLT + { "STKFLT", SIGSTKFLT }, /* 16 (arm,i386,m68k,ppc) */ +#endif +#ifdef SIGURG + { "URG", SIGURG }, /* 23 (arm,i386,m68k,ppc), 16 (alpha,sparc*), 21 (mips) */ +#endif +#ifdef SIGIO + { "IO", SIGIO }, /* 29 (arm,i386,m68k,ppc), 23 (alpha,sparc*), 22 (mips) */ +#endif +#ifdef SIGPOLL + { "POLL", SIGPOLL }, /* same as SIGIO */ +#endif +#ifdef SIGCLD + { "CLD", SIGCLD }, /* same as SIGCHLD (mips) */ +#endif +#ifdef SIGXCPU + { "XCPU", SIGXCPU }, /* 24 (arm,i386,m68k,ppc,alpha,sparc*), 30 (mips) */ +#endif +#ifdef SIGXFSZ + { "XFSZ", SIGXFSZ }, /* 25 (arm,i386,m68k,ppc,alpha,sparc*), 31 (mips) */ +#endif +#ifdef SIGVTALRM + { "VTALRM", SIGVTALRM }, /* 26 (arm,i386,m68k,ppc,alpha,sparc*), 28 (mips) */ +#endif +#ifdef SIGPROF + { "PROF", SIGPROF }, /* 27 (arm,i386,m68k,ppc,alpha,sparc*), 29 (mips) */ +#endif +#ifdef SIGPWR + { "PWR", SIGPWR }, /* 30 (arm,i386,m68k,ppc), 29 (alpha,sparc*), 19 (mips) */ +#endif +#ifdef SIGINFO + { "INFO", SIGINFO }, /* 29 (alpha) */ +#endif +#ifdef SIGLOST + { "LOST", SIGLOST }, /* 29 (arm,i386,m68k,ppc,sparc*) */ +#endif +#ifdef SIGWINCH + { "WINCH", SIGWINCH }, /* 28 (arm,i386,m68k,ppc,alpha,sparc*), 20 (mips) */ +#endif +#ifdef SIGUNUSED + { "UNUSED", SIGUNUSED }, /* 31 (arm,i386,m68k,ppc) */ +#endif + {0, 0} +}; + +/* + if str_sig == NULL returned signal name [*signo], + if str_sig != NULL - set *signo from signal_name, + findings with digit number or with or without SIG-prefix name + + if startnum=0 flag for support finding zero signal, + but str_sig="0" always found, (hmm - standart or realize?) + if startnum<0 returned reverse signal_number <-> signal_name + if found error - returned NULL + +*/ + +const char * +u_signal_names(const char *str_sig, int *signo, int startnum) +{ + static char retstr[16]; + const struct signal_name *s = signames; + static const char prefix[] = "SIG"; + const char *sptr; + + if(startnum) + s++; + if(str_sig==NULL) { + while (s->name != 0) { + if(s->number == *signo) + break; + s++; + } + } else { + if (isdigit(((unsigned char)*str_sig))) { + char *endp; + long int sn = strtol(str_sig, &endp, 10); + /* test correct and overflow */ + if(*endp == 0 && sn >= 0 && sn < NSIG) { + *signo = (int)sn; + /* test for unnamed */ + sptr = u_signal_names(0, signo, 0); + if(sptr==NULL) + return NULL; + if(sn!=0) + sptr += 3; + return sptr; + } + } else { + sptr = str_sig; + while (s->name != 0) { + if (strcasecmp(s->name, sptr) == 0) { + *signo = s->number; + if(startnum<0) { + sprintf(retstr, "%d", *signo); + return retstr; + } + break; + } + if(s!=signames && sptr == str_sig && + strncasecmp(sptr, prefix, 3) == 0) { + sptr += 3; /* strlen(prefix) */ + continue; + } + sptr = str_sig; + s++; + } + } + } + if(s->name==0) + return NULL; + if(s!=signames) + strcpy(retstr, prefix); + else + retstr[0] = 0; + return strcat(retstr, s->name); +} diff --git a/libbb/unarchive.c b/libbb/unarchive.c new file mode 100644 index 000000000..cb35bc4d3 --- /dev/null +++ b/libbb/unarchive.c @@ -0,0 +1,617 @@ +/* + * Copyright (C) 2000 by Glenn McGrath + * Copyright (C) 2001 by Laurence Anderson + * + * Based on previous work by busybox developers and others. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include "libbb.h" + +extern void seek_sub_file(FILE *src_stream, const int count); +extern char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *file_entry, + const int function, const char *prefix); + + +#ifdef L_archive_offset +off_t archive_offset; +#else +extern off_t archive_offset; +#endif + +#ifdef L_seek_sub_file +void seek_sub_file(FILE *src_stream, const int count) +{ + int i; + /* Try to fseek as faster */ + archive_offset += count; + if (fseek(src_stream, count, SEEK_CUR) != 0 && errno == ESPIPE) { + for (i = 0; i < count; i++) { + fgetc(src_stream); + } + } + return; +} +#endif + + + +#ifdef L_extract_archive +/* Extract the data postioned at src_stream to either filesystem, stdout or + * buffer depending on the value of 'function' which is defined in libbb.h + * + * prefix doesnt have to be just a directory, it may prefix the filename as well. + * + * e.g. '/var/lib/dpkg/info/dpkg.' will extract all files to the base bath + * '/var/lib/dpkg/info/' and all files/dirs created in that dir will have + * 'dpkg.' as their prefix + * + * For this reason if prefix does point to a dir then it must end with a + * trailing '/' or else the last dir will be assumed to be the file prefix + */ +char *extract_archive(FILE *src_stream, FILE *out_stream, const file_header_t *file_entry, + const int function, const char *prefix) +{ + FILE *dst_stream = NULL; + char *full_name = NULL; + char *buffer = NULL; + struct utimbuf t; + + /* prefix doesnt have to be a proper path it may prepend + * the filename as well */ + if (prefix != NULL) { + /* strip leading '/' in filename to extract as prefix may not be dir */ + /* Cant use concat_path_file here as prefix might not be a directory */ + char *path = file_entry->name; + if (strncmp("./", path, 2) == 0) { + path += 2; + if (strlen(path) == 0) { + return(NULL); + } + } + full_name = xmalloc(strlen(prefix) + strlen(path) + 1); + strcpy(full_name, prefix); + strcat(full_name, path); + } else { + full_name = file_entry->name; + } + if (function & extract_to_stdout) { + if (S_ISREG(file_entry->mode)) { + copy_file_chunk(src_stream, out_stream, file_entry->size); + archive_offset += file_entry->size; + } + } + else if (function & extract_one_to_buffer) { + if (S_ISREG(file_entry->mode)) { + buffer = (char *) xmalloc(file_entry->size + 1); + fread(buffer, 1, file_entry->size, src_stream); + buffer[file_entry->size] = '\0'; + archive_offset += file_entry->size; + return(buffer); + } + } + else if (function & extract_all_to_fs) { + struct stat oldfile; + int stat_res; + stat_res = lstat (full_name, &oldfile); + if (stat_res == 0) { /* The file already exists */ + if ((function & extract_unconditional) || (oldfile.st_mtime < file_entry->mtime)) { + if (!S_ISDIR(oldfile.st_mode)) { + unlink(full_name); /* Directories might not be empty etc */ + } + } else { + if ((function & extract_quiet) != extract_quiet) { + error_msg("%s not created: newer or same age file exists", file_entry->name); + } + seek_sub_file(src_stream, file_entry->size); + return (NULL); + } + } + if (function & extract_create_leading_dirs) { /* Create leading directories with default umask */ + char *buf, *parent; + buf = xstrdup(full_name); + parent = dirname(buf); + if (make_directory (parent, -1, FILEUTILS_RECUR) != 0) { + if ((function & extract_quiet) != extract_quiet) { + error_msg("couldn't create leading directories"); + } + } + free (buf); + } + switch(file_entry->mode & S_IFMT) { + case S_IFREG: + if (file_entry->link_name) { /* Found a cpio hard link */ + if (link(file_entry->link_name, full_name) != 0) { + if ((function & extract_quiet) != extract_quiet) { + perror_msg("Cannot link from %s to '%s'", + file_entry->name, file_entry->link_name); + } + } + } else { + if ((dst_stream = wfopen(full_name, "w")) == NULL) { + seek_sub_file(src_stream, file_entry->size); + return NULL; + } + archive_offset += file_entry->size; + copy_file_chunk(src_stream, dst_stream, file_entry->size); + fclose(dst_stream); + } + break; + case S_IFDIR: + if (stat_res != 0) { + if (mkdir(full_name, file_entry->mode) < 0) { + if ((function & extract_quiet) != extract_quiet) { + perror_msg("extract_archive: %s", full_name); + } + } + } + break; + case S_IFLNK: + if (symlink(file_entry->link_name, full_name) < 0) { + if ((function & extract_quiet) != extract_quiet) { + perror_msg("Cannot create symlink from %s to '%s'", file_entry->name, file_entry->link_name); + } + return NULL; + } + break; + case S_IFSOCK: + case S_IFBLK: + case S_IFCHR: + case S_IFIFO: + if (mknod(full_name, file_entry->mode, file_entry->device) == -1) { + if ((function & extract_quiet) != extract_quiet) { + perror_msg("Cannot create node %s", file_entry->name); + } + return NULL; + } + break; + } + + /* Changing a symlink's properties normally changes the properties of the + * file pointed to, so dont try and change the date or mode, lchown does + * does the right thing, but isnt available in older versions of libc */ + if (S_ISLNK(file_entry->mode)) { +#if (__GLIBC__ > 2) && (__GLIBC_MINOR__ > 1) + lchown(full_name, file_entry->uid, file_entry->gid); +#endif + } else { + if (function & extract_preserve_date) { + t.actime = file_entry->mtime; + t.modtime = file_entry->mtime; + utime(full_name, &t); + } + chmod(full_name, file_entry->mode); + chown(full_name, file_entry->uid, file_entry->gid); + } + } else { + /* If we arent extracting data we have to skip it, + * if data size is 0 then then just do it anyway + * (saves testing for it) */ + seek_sub_file(src_stream, file_entry->size); + } + + /* extract_list and extract_verbose_list can be used in conjunction + * with one of the above four extraction functions, so do this seperately */ + if (function & extract_verbose_list) { + fprintf(out_stream, "%s %d/%d %8d %s ", mode_string(file_entry->mode), + file_entry->uid, file_entry->gid, + (int) file_entry->size, time_string(file_entry->mtime)); + } + if ((function & extract_list) || (function & extract_verbose_list)){ + /* fputs doesnt add a trailing \n, so use fprintf */ + fprintf(out_stream, "%s\n", file_entry->name); + } + + free(full_name); + + return(NULL); /* Maybe we should say if failed */ +} +#endif + +#ifdef L_unarchive +char *unarchive(FILE *src_stream, FILE *out_stream, file_header_t *(*get_headers)(FILE *), + const int extract_function, const char *prefix, char **extract_names) +{ + file_header_t *file_entry; + int extract_flag; + int i; + char *buffer = NULL; + + archive_offset = 0; + while ((file_entry = get_headers(src_stream)) != NULL) { + extract_flag = TRUE; + if (extract_names != NULL) { + int found_flag = FALSE; + for(i = 0; extract_names[i] != 0; i++) { + if (strcmp(extract_names[i], file_entry->name) == 0) { + found_flag = TRUE; + break; + } + } + if (extract_function & extract_exclude_list) { + if (found_flag == TRUE) { + extract_flag = FALSE; + } + } else { + /* If its not found in the include list dont extract it */ + if (found_flag == FALSE) { + extract_flag = FALSE; + } + } + + } + + if (extract_flag == TRUE) { + buffer = extract_archive(src_stream, out_stream, file_entry, extract_function, prefix); + } else { + /* seek past the data entry */ + seek_sub_file(src_stream, file_entry->size); + } + free(file_entry->name); /* may be null, but doesn't matter */ + free(file_entry->link_name); + free(file_entry); + } + return(buffer); +} +#endif + +#ifdef L_get_header_ar +file_header_t *get_header_ar(FILE *src_stream) +{ + file_header_t *typed; + union { + char raw[60]; + struct { + char name[16]; + char date[12]; + char uid[6]; + char gid[6]; + char mode[8]; + char size[10]; + char magic[2]; + } formated; + } ar; + static char *ar_long_names; + + if (fread(ar.raw, 1, 60, src_stream) != 60) { + return(NULL); + } + archive_offset += 60; + /* align the headers based on the header magic */ + if ((ar.formated.magic[0] != '`') || (ar.formated.magic[1] != '\n')) { + /* some version of ar, have an extra '\n' after each data entry, + * this puts the next header out by 1 */ + if (ar.formated.magic[1] != '`') { + error_msg("Invalid magic"); + return(NULL); + } + /* read the next char out of what would be the data section, + * if its a '\n' then it is a valid header offset by 1*/ + archive_offset++; + if (fgetc(src_stream) != '\n') { + error_msg("Invalid magic"); + return(NULL); + } + /* fix up the header, we started reading 1 byte too early */ + /* raw_header[60] wont be '\n' as it should, but it doesnt matter */ + memmove(ar.raw, &ar.raw[1], 59); + } + + typed = (file_header_t *) xcalloc(1, sizeof(file_header_t)); + + typed->size = (size_t) atoi(ar.formated.size); + /* long filenames have '/' as the first character */ + if (ar.formated.name[0] == '/') { + if (ar.formated.name[1] == '/') { + /* If the second char is a '/' then this entries data section + * stores long filename for multiple entries, they are stored + * in static variable long_names for use in future entries */ + ar_long_names = (char *) xrealloc(ar_long_names, typed->size); + fread(ar_long_names, 1, typed->size, src_stream); + archive_offset += typed->size; + /* This ar entries data section only contained filenames for other records + * they are stored in the static ar_long_names for future reference */ + return (get_header_ar(src_stream)); /* Return next header */ + } else if (ar.formated.name[1] == ' ') { + /* This is the index of symbols in the file for compilers */ + seek_sub_file(src_stream, typed->size); + return (get_header_ar(src_stream)); /* Return next header */ + } else { + /* The number after the '/' indicates the offset in the ar data section + (saved in variable long_name) that conatains the real filename */ + if (!ar_long_names) { + error_msg("Cannot resolve long file name"); + return (NULL); + } + typed->name = xstrdup(ar_long_names + atoi(&ar.formated.name[1])); + } + } else { + /* short filenames */ + typed->name = xcalloc(1, 16); + strncpy(typed->name, ar.formated.name, 16); + } + typed->name[strcspn(typed->name, " /")]='\0'; + + /* convert the rest of the now valid char header to its typed struct */ + parse_mode(ar.formated.mode, &typed->mode); + typed->mtime = atoi(ar.formated.date); + typed->uid = atoi(ar.formated.uid); + typed->gid = atoi(ar.formated.gid); + + return(typed); +} +#endif + +#ifdef L_get_header_cpio +struct hardlinks { + file_header_t *entry; + int inode; + struct hardlinks *next; +}; + +file_header_t *get_header_cpio(FILE *src_stream) +{ + file_header_t *cpio_entry = NULL; + char cpio_header[110]; + int namesize; + char dummy[16]; + int major, minor, nlink, inode; + static struct hardlinks *saved_hardlinks = NULL; + static int pending_hardlinks = 0; + + if (pending_hardlinks) { /* Deal with any pending hardlinks */ + struct hardlinks *tmp = saved_hardlinks, *oldtmp = NULL; + while (tmp) { + if (tmp->entry->link_name) { /* Found a hardlink ready to be extracted */ + cpio_entry = tmp->entry; + if (oldtmp) oldtmp->next = tmp->next; /* Remove item from linked list */ + else saved_hardlinks = tmp->next; + free(tmp); + return (cpio_entry); + } + oldtmp = tmp; + tmp = tmp->next; + } + pending_hardlinks = 0; /* No more pending hardlinks, read next file entry */ + } + + /* There can be padding before archive header */ + seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4); + if (fread(cpio_header, 1, 110, src_stream) == 110) { + archive_offset += 110; + if (strncmp(cpio_header, "07070", 5) != 0) { + error_msg("Unsupported format or invalid magic"); + return(NULL); + } + switch (cpio_header[5]) { + case '2': /* "crc" header format */ + /* Doesnt do the crc check yet */ + case '1': /* "newc" header format */ + cpio_entry = (file_header_t *) xcalloc(1, sizeof(file_header_t)); + sscanf(cpio_header, "%6c%8x%8x%8x%8x%8x%8lx%8lx%16c%8x%8x%8x%8c", + dummy, &inode, (unsigned int*)&cpio_entry->mode, + (unsigned int*)&cpio_entry->uid, (unsigned int*)&cpio_entry->gid, + &nlink, &cpio_entry->mtime, (unsigned long*)&cpio_entry->size, + dummy, &major, &minor, &namesize, dummy); + + cpio_entry->name = (char *) xcalloc(1, namesize); + fread(cpio_entry->name, 1, namesize, src_stream); /* Read in filename */ + archive_offset += namesize; + /* Skip padding before file contents */ + seek_sub_file(src_stream, (4 - (archive_offset % 4)) % 4); + if (strcmp(cpio_entry->name, "TRAILER!!!") == 0) { + printf("%d blocks\n", (int) (archive_offset % 512 ? (archive_offset / 512) + 1 : archive_offset / 512)); /* Always round up */ + if (saved_hardlinks) { /* Bummer - we still have unresolved hardlinks */ + struct hardlinks *tmp = saved_hardlinks, *oldtmp = NULL; + while (tmp) { + error_msg("%s not created: cannot resolve hardlink", tmp->entry->name); + oldtmp = tmp; + tmp = tmp->next; + free (oldtmp->entry->name); + free (oldtmp->entry); + free (oldtmp); + } + saved_hardlinks = NULL; + pending_hardlinks = 0; + } + return(NULL); + } + + if (S_ISLNK(cpio_entry->mode)) { + cpio_entry->link_name = (char *) xcalloc(1, cpio_entry->size + 1); + fread(cpio_entry->link_name, 1, cpio_entry->size, src_stream); + archive_offset += cpio_entry->size; + cpio_entry->size = 0; /* Stop possiable seeks in future */ + } + if (nlink > 1 && !S_ISDIR(cpio_entry->mode)) { + if (cpio_entry->size == 0) { /* Put file on a linked list for later */ + struct hardlinks *new = xmalloc(sizeof(struct hardlinks)); + new->next = saved_hardlinks; + new->inode = inode; + new->entry = cpio_entry; + saved_hardlinks = new; + return(get_header_cpio(src_stream)); /* Recurse to next file */ + } else { /* Found the file with data in */ + struct hardlinks *tmp = saved_hardlinks; + pending_hardlinks = 1; + while (tmp) { + if (tmp->inode == inode) { + tmp->entry->link_name = xstrdup(cpio_entry->name); + nlink--; + } + tmp = tmp->next; + } + if (nlink > 1) error_msg("error resolving hardlink: did you create the archive with GNU cpio 2.0-2.2?"); + } + } + cpio_entry->device = (major << 8) | minor; + break; + default: + error_msg("Unsupported format"); + return(NULL); + } + if (ferror(src_stream) || feof(src_stream)) { + perror_msg("Stream error"); + return(NULL); + } + } + return(cpio_entry); +} +#endif + +#ifdef L_get_header_tar +file_header_t *get_header_tar(FILE *tar_stream) +{ + union { + unsigned char raw[512]; + struct { + char name[100]; /* 0-99 */ + char mode[8]; /* 100-107 */ + char uid[8]; /* 108-115 */ + char gid[8]; /* 116-123 */ + char size[12]; /* 124-135 */ + char mtime[12]; /* 136-147 */ + char chksum[8]; /* 148-155 */ + char typeflag; /* 156-156 */ + char linkname[100]; /* 157-256 */ + char magic[6]; /* 257-262 */ + char version[2]; /* 263-264 */ + char uname[32]; /* 265-296 */ + char gname[32]; /* 297-328 */ + char devmajor[8]; /* 329-336 */ + char devminor[8]; /* 337-344 */ + char prefix[155]; /* 345-499 */ + char padding[12]; /* 500-512 */ + } formated; + } tar; + file_header_t *tar_entry = NULL; + long i; + long sum = 0; + + if (archive_offset % 512 != 0) { + seek_sub_file(tar_stream, 512 - (archive_offset % 512)); + } + + if (fread(tar.raw, 1, 512, tar_stream) != 512) { + /* Unfortunatly its common for tar files to have all sorts of + * trailing garbage, fail silently */ +// error_msg("Couldnt read header"); + return(NULL); + } + archive_offset += 512; + + /* Check header has valid magic, unfortunately some tar files + * have empty (0'ed) tar entries at the end, which will + * cause this to fail, so fail silently for now + */ + if (strncmp(tar.formated.magic, "ustar", 5) != 0) { + return(NULL); + } + + /* Do checksum on headers */ + for (i = 0; i < 148 ; i++) { + sum += tar.raw[i]; + } + sum += ' ' * 8; + for (i = 156; i < 512 ; i++) { + sum += tar.raw[i]; + } + if (sum != strtol(tar.formated.chksum, NULL, 8)) { + error_msg("Invalid tar header checksum"); + return(NULL); + } + + /* convert to type'ed variables */ + tar_entry = xcalloc(1, sizeof(file_header_t)); + tar_entry->name = xstrdup(tar.formated.name); + + parse_mode(tar.formated.mode, &tar_entry->mode); + tar_entry->uid = strtol(tar.formated.uid, NULL, 8); + tar_entry->gid = strtol(tar.formated.gid, NULL, 8); + tar_entry->size = strtol(tar.formated.size, NULL, 8); + tar_entry->mtime = strtol(tar.formated.mtime, NULL, 8); + tar_entry->link_name = strlen(tar.formated.linkname) ? + xstrdup(tar.formated.linkname) : NULL; + tar_entry->device = (strtol(tar.formated.devmajor, NULL, 8) << 8) + + strtol(tar.formated.devminor, NULL, 8); + + return(tar_entry); +} +#endif + +#ifdef L_deb_extract +char *deb_extract(const char *package_filename, FILE *out_stream, + const int extract_function, const char *prefix, const char *filename) +{ + FILE *deb_stream; + FILE *uncompressed_stream = NULL; + file_header_t *ar_header = NULL; + char **file_list = NULL; + char *output_buffer = NULL; + char *ared_file = NULL; + char ar_magic[8]; + int gunzip_pid; + + if (filename != NULL) { + file_list = xmalloc(sizeof(char *) * 2); + file_list[0] = xstrdup(filename); + file_list[1] = NULL; + } + + if (extract_function & extract_control_tar_gz) { + ared_file = xstrdup("control.tar.gz"); + } + else if (extract_function & extract_data_tar_gz) { + ared_file = xstrdup("data.tar.gz"); + } + + /* open the debian package to be worked on */ + deb_stream = wfopen(package_filename, "r"); + if (deb_stream == NULL) { + return(NULL); + } + /* set the buffer size */ + setvbuf(deb_stream, NULL, _IOFBF, 0x8000); + + /* check ar magic */ + fread(ar_magic, 1, 8, deb_stream); + if (strncmp(ar_magic,"!",7) != 0) { + error_msg_and_die("invalid magic"); + } + archive_offset = 8; + + while ((ar_header = get_header_ar(deb_stream)) != NULL) { + if (strcmp(ared_file, ar_header->name) == 0) { + /* open a stream of decompressed data */ + uncompressed_stream = gz_open(deb_stream, &gunzip_pid); + archive_offset = 0; + output_buffer = unarchive(uncompressed_stream, out_stream, get_header_tar, extract_function, prefix, file_list); + } + seek_sub_file(deb_stream, ar_header->size); + } + gz_close(gunzip_pid); + fclose(deb_stream); + fclose(uncompressed_stream); + free(ared_file); + return(output_buffer); +} +#endif diff --git a/libbb/unzip.c b/libbb/unzip.c new file mode 100644 index 000000000..74624821d --- /dev/null +++ b/libbb/unzip.c @@ -0,0 +1,1081 @@ +/* vi: set sw=4 ts=4: */ +/* + * gunzip implementation for busybox + * + * Based on GNU gzip v1.2.4 Copyright (C) 1992-1993 Jean-loup Gailly. + * + * Originally adjusted for busybox by Sven Rudolph + * based on gzip sources + * + * Adjusted further by Erik Andersen to support + * files as well as stdin/stdout, and to generally behave itself wrt + * command line handling. + * + * General cleanup to better adhere to the style guide and make use of + * standard busybox functions by 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 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 + * + * + * gzip (GNU zip) -- compress files with zip algorithm and 'compress' interface + * Copyright (C) 1992-1993 Jean-loup Gailly + * The unzip code was written and put in the public domain by Mark Adler. + * Portions of the lzw code are derived from the public domain 'compress' + * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, + * Ken Turkowski, Dave Mack and Peter Jannesen. + * + * See the license_msg below and the file COPYING for the software license. + * See the file algorithm.doc for the compression algorithms and file formats. + */ + +#if 0 +static char *license_msg[] = { + " Copyright (C) 1992-1993 Jean-loup Gailly", + " 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., 675 Mass Ave, Cambridge, MA 02139, USA.", + 0 +}; +#endif + +#include +#include +#include +#include +#include +#include "libbb.h" + +static FILE *in_file, *out_file; + +/* these are freed by gz_close */ +static unsigned char *window; +static unsigned long *crc_table; + +static unsigned long crc; /* shift register contents */ + +/* Return codes from gzip */ +static const int ERROR = 1; + +/* + * window size--must be a power of two, and + * at least 32K for zip's deflate method + */ +static const int WSIZE = 0x8000; + +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ +static const int BMAX = 16; /* maximum bit length of any code (16 for explode) */ +static const int N_MAX = 288; /* maximum number of codes in any set */ + +static long bytes_out; /* number of output bytes */ +static unsigned long outcnt; /* bytes in output buffer */ + +static unsigned hufts; /* track memory usage */ +static unsigned long bb; /* bit buffer */ +static unsigned bk; /* bits in bit buffer */ + +typedef struct huft_s { + unsigned char e; /* number of extra bits or operation */ + unsigned char b; /* number of bits in this code or subcode */ + union { + unsigned short n; /* literal, length base, or distance base */ + struct huft_s *t; /* pointer to next level of table */ + } v; +} huft_t; + +static const unsigned short mask_bits[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +//static int error_number = 0; +/* ======================================================================== + * Signal and error handler. + */ + +static void abort_gzip() +{ + error_msg("gzip aborted\n"); + exit(ERROR); +} + +static void make_crc_table() +{ + unsigned long table_entry; /* crc shift register */ + unsigned long poly = 0; /* polynomial exclusive-or pattern */ + int i; /* counter for all possible eight bit values */ + int k; /* byte being shifted into crc apparatus */ + + /* terms of polynomial defining this crc (except x^32): */ + static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* initial shift register value */ + crc = 0xffffffffL; + crc_table = (unsigned long *) malloc(256 * sizeof(unsigned long)); + + /* Make exclusive-or pattern from polynomial (0xedb88320) */ + for (i = 0; i < sizeof(p)/sizeof(int); i++) + poly |= 1L << (31 - p[i]); + + /* Compute and print table of CRC's, five per line */ + for (i = 0; i < 256; i++) { + table_entry = i; + /* The idea to initialize the register with the byte instead of + * zero was stolen from Haruhiko Okumura's ar002 + */ + for (k = 8; k; k--) { + table_entry = table_entry & 1 ? (table_entry >> 1) ^ poly : table_entry >> 1; + } + crc_table[i]=table_entry; + } +} + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +static void flush_window(void) +{ + int n; + + if (outcnt == 0) + return; + + for (n = 0; n < outcnt; n++) { + crc = crc_table[((int) crc ^ (window[n])) & 0xff] ^ (crc >> 8); + } + + if (fwrite(window, 1, outcnt, out_file) != outcnt) { + error_msg_and_die("Couldnt write"); + } + bytes_out += (unsigned long) outcnt; + outcnt = 0; +} + +/* + * Free the malloc'ed tables built by huft_build(), which makes a linked + * list of the tables it made, with the links in a dummy first entry of + * each table. + * t: table to free + */ +static int huft_free(huft_t *t) +{ + huft_t *p, *q; + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != (huft_t *) NULL) { + q = (--p)->v.t; + free((char *) p); + p = q; + } + return 0; +} + +/* Given a list of code lengths and a maximum table size, make a set of + * tables to decode that set of codes. Return zero on success, one if + * the given code set is incomplete (the tables are still built in this + * case), two if the input is invalid (all zero length codes or an + * oversubscribed set of lengths), and three if not enough memory. + * + * b: code lengths in bits (all assumed <= BMAX) + * n: number of codes (assumed <= N_MAX) + * s: number of simple-valued codes (0..s-1) + * d: list of base values for non-simple codes + * e: list of extra bits for non-simple codes + * t: result: starting table + * m: maximum lookup bits, returns actual + */ +static int huft_build(unsigned int *b, const unsigned int n, const unsigned int s, + const unsigned short *d, const unsigned short *e, huft_t **t, int *m) +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX + 1]; /* bit length count table */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register unsigned i; /* counter, current code */ + register unsigned j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register unsigned *p; /* pointer into c[], b[], or v[] */ + register huft_t *q; /* points to current table */ + huft_t r; /* table entry for structure assignment */ + huft_t *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + unsigned x[BMAX + 1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + + /* Generate counts for each bit length */ + memset ((void *)(c), 0, sizeof(c)); + p = b; + i = n; + do { + c[*p]++; /* assume all entries <= BMAX */ + p++; /* Can't combine with above line (Solaris bug) */ + } while (--i); + if (c[0] == n) { /* null input--all zero length codes */ + *t = (huft_t *) NULL; + *m = 0; + return 0; + } + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((unsigned) l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((unsigned) l > i) + l = i; + *m = l; + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= c[i]) < 0) + return 2; + c[i] += y; + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; + xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + /* Make a table of values in order of bit lengths */ + p = b; + i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (huft_t *) NULL; /* just to keep compilers happy */ + q = (huft_t *) NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) { + a = c[k]; + while (a--) { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = (z = g - w) > (unsigned) l ? l : z; /* upper limit on table size */ + if ((f = 1 << (j = k - w)) > a + 1) { /* try a k-w bit table *//* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) { /* try smaller tables up to z bits */ + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + if ((q = (huft_t *) xmalloc((z + 1) * sizeof(huft_t))) == NULL) { + if (h) { + huft_free(u[0]); + } + return 3; /* not enough memory */ + } + hufts += z + 1; /* track memory usage */ + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->v.t)) = NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) { + x[h] = i; /* save pattern for backing up */ + r.b = (unsigned char) l; /* bits to dump before this table */ + r.e = (unsigned char) (16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h - 1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (unsigned char) (k - w); + if (p >= v + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) { + r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = (unsigned short) (*p); /* simple code is just the value */ + p++; /* one compiler does not like *p++ */ + } else { + r.e = (unsigned char) e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) { + h--; /* don't need to update q */ + w -= l; + } + } + } + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + +/* + * inflate (decompress) the codes in a deflated (compressed) block. + * Return an error code or zero if it all goes ok. + * + * tl, td: literal/length and distance decoder tables + * bl, bd: number of bits decoded by tl[] and td[] + */ +static int inflate_codes(huft_t *tl, huft_t *td, int bl, int bd) +{ + register unsigned long e; /* table entry flag/number of extra bits */ + unsigned long n, d; /* length and index for copy */ + unsigned long w; /* current window position */ + huft_t *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + register unsigned long b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + register int input_char; + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + w = outcnt; /* initialize window position */ + + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; + for (;;) { /* do until end of block */ + while (k < (unsigned) bl) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b |= ((unsigned long)input_char) << k; + k += 8; + } + if ((e = (t = tl + ((unsigned) b & ml))->e) > 16) + do { + if (e == 99) { + return 1; + } + b >>= t->b; + k -= t->b; + e -= 16; + while (k < e) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b |= ((unsigned long)input_char) << k; + k += 8; + } + } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); + b >>= t->b; + k -= t->b; + if (e == 16) { /* then it's a literal */ + window[w++] = (unsigned char) t->v.n; + if (w == WSIZE) { + outcnt=(w), + flush_window(); + w = 0; + } + } else { /* it's an EOB or a length */ + + /* exit if end of block */ + if (e == 15) { + break; + } + + /* get length of block to copy */ + while (k < e) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b |= ((unsigned long)input_char) << k; + k += 8; + } + n = t->v.n + ((unsigned) b & mask_bits[e]); + b >>= e; + k -= e; + + /* decode distance of block to copy */ + while (k < (unsigned) bd) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b |= ((unsigned long)input_char) << k; + k += 8; + } + + if ((e = (t = td + ((unsigned) b & md))->e) > 16) + do { + if (e == 99) + return 1; + b >>= t->b; + k -= t->b; + e -= 16; + while (k < e) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b |= ((unsigned long)input_char) << k; + k += 8; + } + } while ((e = (t = t->v.t + ((unsigned) b & mask_bits[e]))->e) > 16); + b >>= t->b; + k -= t->b; + while (k < e) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b |= ((unsigned long)input_char) << k; + k += 8; + } + d = w - t->v.n - ((unsigned) b & mask_bits[e]); + b >>= e; + k -= e; + + /* do the copy */ + do { + n -= (e = (e = WSIZE - ((d &= WSIZE - 1) > w ? d : w)) > n ? n : e); +#if !defined(NOMEMCPY) && !defined(DEBUG) + if (w - d >= e) { /* (this test assumes unsigned comparison) */ + memcpy(window + w, window + d, e); + w += e; + d += e; + } else /* do it slow to avoid memcpy() overlap */ +#endif /* !NOMEMCPY */ + do { + window[w++] = window[d++]; + } while (--e); + if (w == WSIZE) { + outcnt=(w), + flush_window(); + w = 0; + } + } while (n); + } + } + + /* restore the globals from the locals */ + outcnt = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + + /* done */ + return 0; +} + +/* + * decompress an inflated block + * e: last block flag + * + * GLOBAL VARIABLES: bb, kk, + */ +static int inflate_block(int *e) +{ + unsigned t; /* block type */ + register unsigned long b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + static unsigned short cplens[] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 + }; + /* note: see note #13 above about the 258 in this list. */ + static unsigned short cplext[] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 + }; /* 99==invalid */ + static unsigned short cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577 + }; + static unsigned short cpdext[] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13 + }; + int input_char; + + /* make local bit buffer */ + b = bb; + k = bk; + + /* read in last block bit */ + while (k < 1) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b |= ((unsigned long)input_char) << k; + k += 8; + } + *e = (int) b & 1; + b >>= 1; + k -= 1; + + /* read in block type */ + while (k < 2) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b |= ((unsigned long)input_char) << k; + k += 8; + } + t = (unsigned) b & 3; + b >>= 2; + k -= 2; + + /* restore the global bit buffer */ + bb = b; + bk = k; + + /* inflate that block type */ + switch (t) { + case 0: /* Inflate stored */ + { + unsigned long n; /* number of bytes in block */ + unsigned long w; /* current window position */ + register unsigned long b_stored; /* bit buffer */ + register unsigned long k_stored; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b_stored = bb; /* initialize bit buffer */ + k_stored = bk; + w = outcnt; /* initialize window position */ + + /* go to byte boundary */ + n = k_stored & 7; + b_stored >>= n; + k_stored -= n; + + /* get the length and its complement */ + while (k_stored < 16) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b_stored |= ((unsigned long)input_char) << k_stored; + k_stored += 8; + } + n = ((unsigned) b_stored & 0xffff); + b_stored >>= 16; + k_stored -= 16; + while (k_stored < 16) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b_stored |= ((unsigned long)input_char) << k_stored; + k_stored += 8; + } + if (n != (unsigned) ((~b_stored) & 0xffff)) { + return 1; /* error in compressed data */ + } + b_stored >>= 16; + k_stored -= 16; + + /* read and output the compressed data */ + while (n--) { + while (k_stored < 8) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b_stored |= ((unsigned long)input_char) << k_stored; + k_stored += 8; + } + window[w++] = (unsigned char) b_stored; + if (w == (unsigned long)WSIZE) { + outcnt=(w), + flush_window(); + w = 0; + } + b_stored >>= 8; + k_stored -= 8; + } + + /* restore the globals from the locals */ + outcnt = w; /* restore global window pointer */ + bb = b_stored; /* restore global bit buffer */ + bk = k_stored; + return 0; + } + case 1: /* Inflate fixed + * decompress an inflated type 1 (fixed Huffman codes) block. We should + * either replace this with a custom decoder, or at least precompute the + * Huffman tables. + */ + { + int i; /* temporary variable */ + huft_t *tl; /* literal/length code table */ + huft_t *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned int l[288]; /* length list for huft_build */ + + /* set up literal table */ + for (i = 0; i < 144; i++) { + l[i] = 8; + } + for (; i < 256; i++) { + l[i] = 9; + } + for (; i < 280; i++) { + l[i] = 7; + } + for (; i < 288; i++) { /* make a complete, but wrong code set */ + l[i] = 8; + } + bl = 7; + if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) { + return i; + } + + /* set up distance table */ + for (i = 0; i < 30; i++) { /* make an incomplete code set */ + l[i] = 5; + } + bd = 5; + if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1) { + huft_free(tl); + return i; + } + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) + return 1; + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; + } + case 2: /* Inflate dynamic */ + { + /* Tables for deflate from PKZIP's appnote.txt. */ + static unsigned border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + }; + int dbits = 6; /* bits in base distance lookup table */ + int lbits = 9; /* bits in base literal/length lookup table */ + + int i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + huft_t *tl; /* literal/length code table */ + huft_t *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ + + unsigned ll[286 + 30]; /* literal/length and distance code lengths */ + register unsigned long b_dynamic; /* bit buffer */ + register unsigned k_dynamic; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b_dynamic = bb; + k_dynamic = bk; + + /* read in table lengths */ + while (k_dynamic < 5) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b_dynamic |= ((unsigned long)input_char) << k_dynamic; + k_dynamic += 8; + } + nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ + b_dynamic >>= 5; + k_dynamic -= 5; + while (k_dynamic < 5) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b_dynamic |= ((unsigned long)input_char) << k_dynamic; + k_dynamic += 8; + } + nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ + b_dynamic >>= 5; + k_dynamic -= 5; + while (k_dynamic < 4) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b_dynamic |= ((unsigned long)input_char) << k_dynamic; + k_dynamic += 8; + } + nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ + b_dynamic >>= 4; + k_dynamic -= 4; + if (nl > 286 || nd > 30) { + return 1; /* bad lengths */ + } + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) { + while (k_dynamic < 3) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b_dynamic |= ((unsigned long)input_char) << k_dynamic; + k_dynamic += 8; + } + ll[border[j]] = (unsigned) b_dynamic & 7; + b_dynamic >>= 3; + k_dynamic -= 3; + } + for (; j < 19; j++) { + ll[border[j]] = 0; + } + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) { + if (i == 1) { + huft_free(tl); + } + return i; /* incomplete code set */ + } + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned) i < n) { + while (k_dynamic < (unsigned) bl) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b_dynamic |= ((unsigned long)input_char) << k_dynamic; + k_dynamic += 8; + } + j = (td = tl + ((unsigned) b_dynamic & m))->b; + b_dynamic >>= j; + k_dynamic -= j; + j = td->v.n; + if (j < 16) { /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + } + else if (j == 16) { /* repeat last length 3 to 6 times */ + while (k_dynamic < 2) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b_dynamic |= ((unsigned long)input_char) << k_dynamic; + k_dynamic += 8; + } + j = 3 + ((unsigned) b_dynamic & 3); + b_dynamic >>= 2; + k_dynamic -= 2; + if ((unsigned) i + j > n) { + return 1; + } + while (j--) { + ll[i++] = l; + } + } else if (j == 17) { /* 3 to 10 zero length codes */ + while (k_dynamic < 3) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b_dynamic |= ((unsigned long)input_char) << k_dynamic; + k_dynamic += 8; + } + j = 3 + ((unsigned) b_dynamic & 7); + b_dynamic >>= 3; + k_dynamic -= 3; + if ((unsigned) i + j > n) { + return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } else { /* j == 18: 11 to 138 zero length codes */ + while (k_dynamic < 7) { + input_char = fgetc(in_file); + if (input_char == EOF) return 1; + b_dynamic |= ((unsigned long)input_char) << k_dynamic; + k_dynamic += 8; + } + j = 11 + ((unsigned) b_dynamic & 0x7f); + b_dynamic >>= 7; + k_dynamic -= 7; + if ((unsigned) i + j > n) { + return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } + } + + /* free decoding table for trees */ + huft_free(tl); + + /* restore the global bit buffer */ + bb = b_dynamic; + bk = k_dynamic; + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) { + if (i == 1) { + error_msg("Incomplete literal tree"); + huft_free(tl); + } + return i; /* incomplete code set */ + } + bd = dbits; + if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) { + if (i == 1) { + error_msg("incomplete distance tree"); + huft_free(td); + } + huft_free(tl); + return i; /* incomplete code set */ + } + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) + return 1; + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; + } + default: + /* bad block type */ + return 2; + } +} + +/* + * decompress an inflated entry + * + * GLOBAL VARIABLES: outcnt, bk, bb, hufts, inptr + */ +static int inflate() +{ + int e; /* last block flag */ + int r; /* result code */ + unsigned h = 0; /* maximum struct huft's malloc'ed */ + + /* initialize window, bit buffer */ + outcnt = 0; + bk = 0; + bb = 0; + + /* decompress until the last block */ + do { + hufts = 0; + if ((r = inflate_block(&e)) != 0) { + return r; + } + if (hufts > h) { + h = hufts; + } + } while (!e); + + /* Undo too much lookahead. The next read will be byte aligned so we + * can discard unused bits in the last meaningful byte. */ + while (bk >= 8) { + bk -= 8; + ungetc((bb << bk), in_file); + } + + /* flush out window */ + flush_window(); + + /* return success */ + return 0; +} + +/* =========================================================================== + * Unzip in to out. This routine works on both gzip and pkzip files. + * + * IN assertions: the buffer inbuf contains already the beginning of + * the compressed data, from offsets inptr to insize-1 included. + * The magic header has already been checked. The output buffer is cleared. + * in, out: input and output file descriptors + */ +extern int unzip(FILE *l_in_file, FILE *l_out_file) +{ + const int extra_field = 0x04; /* bit 2 set: extra field present */ + const int orig_name = 0x08; /* bit 3 set: original file name present */ + const int comment = 0x10; /* bit 4 set: file comment present */ + unsigned char buf[8]; /* extended local header */ + unsigned char flags; /* compression flags */ + char magic[2]; /* magic header */ + int method; + typedef void (*sig_type) (int); + int exit_code=0; /* program exit code */ + int i; + + in_file = l_in_file; + out_file = l_out_file; + + if (signal(SIGINT, SIG_IGN) != SIG_IGN) { + (void) signal(SIGINT, (sig_type) abort_gzip); + } +#ifdef SIGTERM +// if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { +// (void) signal(SIGTERM, (sig_type) abort_gzip); +// } +#endif +#ifdef SIGHUP + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { + (void) signal(SIGHUP, (sig_type) abort_gzip); + } +#endif + + /* Allocate all global buffers (for DYN_ALLOC option) */ + window = xmalloc((size_t)(((2L*WSIZE)+1L)*sizeof(unsigned char))); + outcnt = 0; + bytes_out = 0L; + + magic[0] = fgetc(in_file); + magic[1] = fgetc(in_file); + + /* Magic header for gzip files, 1F 8B = \037\213 */ + if (memcmp(magic, "\037\213", 2) != 0) { + error_msg("Invalid gzip magic"); + return EXIT_FAILURE; + } + + method = (int) fgetc(in_file); + if (method != 8) { /* also catches EOF */ + error_msg("unknown method %d -- get newer version of gzip", method); + exit_code = 1; + return -1; + } + + flags = (unsigned char) fgetc(in_file); + + /* Ignore time stamp(4), extra flags(1), OS type(1) */ + for (i = 0; i < 6; i++) + fgetc(in_file); + + if ((flags & extra_field) != 0) { + size_t extra; + extra = fgetc(in_file); + extra += fgetc(in_file) << 8; + if (feof(in_file)) return 1; + + for (i = 0; i < extra; i++) + fgetc(in_file); + } + + /* Discard original name if any */ + if ((flags & orig_name) != 0) { + while (fgetc(in_file) != 0 && !feof(in_file)); /* null */ + } + + /* Discard file comment if any */ + if ((flags & comment) != 0) { + while (fgetc(in_file) != 0 && !feof(in_file)); /* null */ + } + + if (method < 0) { + printf("it failed\n"); + return(exit_code); /* error message already emitted */ + } + + make_crc_table(); + + /* Decompress */ + if (method == 8) { + + int res = inflate(); + + if (res == 3) { + error_msg(memory_exhausted); + exit_code = 1; + } else if (res != 0) { + error_msg("invalid compressed data--format violated"); + exit_code = 1; + } + + } else { + error_msg("internal error, invalid method"); + exit_code = 1; + } + + /* Get the crc and original length + * crc32 (see algorithm.doc) + * uncompressed input size modulo 2^32 + */ + fread(buf, 1, 8, in_file); + + /* Validate decompression - crc */ + if (!exit_code && (unsigned int)((buf[0] | (buf[1] << 8)) |((buf[2] | (buf[3] << 8)) << 16)) != (crc ^ 0xffffffffL)) { + error_msg("invalid compressed data--crc error"); + exit_code = 1; + } + /* Validate decompression - size */ + if (!exit_code && ((buf[4] | (buf[5] << 8)) |((buf[6] | (buf[7] << 8)) << 16)) != (unsigned long) bytes_out) { + error_msg("invalid compressed data--length error"); + exit_code = 1; + } + + free(window); + free(crc_table); + + return exit_code; +} + +/* + * This needs access to global variables wondow and crc_table, so its not in its own file. + */ +extern void gz_close(int gunzip_pid) +{ + if (kill(gunzip_pid, SIGTERM) == -1) { + error_msg_and_die("*** Couldnt kill old gunzip process *** aborting"); + } + + if (waitpid(gunzip_pid, NULL, 0) == -1) { + printf("Couldnt wait ?"); + } + free(window); + free(crc_table); +} diff --git a/libbb/vdprintf.c b/libbb/vdprintf.c new file mode 100644 index 000000000..f3c1ed7a9 --- /dev/null +++ b/libbb/vdprintf.c @@ -0,0 +1,47 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include "libbb.h" + + + +#if (__GLIBC__ < 2) +extern int vdprintf(int d, const char *format, va_list ap) +{ + char buf[BUF_SIZE]; + int len; + + len = vsnprintf(buf, sizeof(buf), format, ap); + return write(d, buf, len); +} +#endif + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/verror_msg.c b/libbb/verror_msg.c new file mode 100644 index 000000000..21cde2047 --- /dev/null +++ b/libbb/verror_msg.c @@ -0,0 +1,43 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include +#include +#include "libbb.h" + +extern void verror_msg(const char *s, va_list p) +{ + fflush(stdout); + fprintf(stderr, "%s: ", applet_name); + vfprintf(stderr, s, p); +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/vherror_msg.c b/libbb/vherror_msg.c new file mode 100644 index 000000000..8a7ada9ec --- /dev/null +++ b/libbb/vherror_msg.c @@ -0,0 +1,38 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +extern int h_errno; +#include + +#include "libbb.h" + + +extern void vherror_msg(const char *s, va_list p) +{ + if(s == 0) + s = ""; + verror_msg(s, p); + if (*s) + fputs(": ", stderr); + herror(""); +} diff --git a/libbb/vperror_msg.c b/libbb/vperror_msg.c new file mode 100644 index 000000000..7da5bae0a --- /dev/null +++ b/libbb/vperror_msg.c @@ -0,0 +1,45 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include +#include +#include "libbb.h" + +extern void vperror_msg(const char *s, va_list p) +{ + int err=errno; + if(s == 0) s = ""; + verror_msg(s, p); + if (*s) s = ": "; + fprintf(stderr, "%s%s\n", s, strerror(err)); +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/wfopen.c b/libbb/wfopen.c new file mode 100644 index 000000000..f58ec90c0 --- /dev/null +++ b/libbb/wfopen.c @@ -0,0 +1,44 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include "libbb.h" + +FILE *wfopen(const char *path, const char *mode) +{ + FILE *fp; + if ((fp = fopen(path, mode)) == NULL) { + perror_msg("%s", path); + errno = 0; + } + return fp; +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c new file mode 100644 index 000000000..ee90e60a6 --- /dev/null +++ b/libbb/xfuncs.c @@ -0,0 +1,102 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 1999,2000,2001 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 + */ + +#include +#include +#include +#include +#include "libbb.h" + + +#ifndef DMALLOC +extern void *xmalloc(size_t size) +{ + void *ptr = malloc(size); + if (ptr == NULL && size != 0) + error_msg_and_die(memory_exhausted); + return ptr; +} + +extern void *xrealloc(void *ptr, size_t size) +{ + ptr = realloc(ptr, size); + if (ptr == NULL && size != 0) + error_msg_and_die(memory_exhausted); + return ptr; +} + +extern void *xcalloc(size_t nmemb, size_t size) +{ + void *ptr = calloc(nmemb, size); + if (ptr == NULL && nmemb != 0 && size != 0) + error_msg_and_die(memory_exhausted); + return ptr; +} + +extern char * xstrdup (const char *s) { + char *t; + + if (s == NULL) + return NULL; + + t = strdup (s); + + if (t == NULL) + error_msg_and_die(memory_exhausted); + + return t; +} +#endif + +extern char * xstrndup (const char *s, int n) { + char *t; + + if (s == NULL) + error_msg_and_die("xstrndup bug"); + + t = xmalloc(++n); + + return safe_strncpy(t,s,n); +} + +FILE *xfopen(const char *path, const char *mode) +{ + FILE *fp; + if ((fp = fopen(path, mode)) == NULL) + perror_msg_and_die("%s", path); + return fp; +} + +/* Stupid gcc always includes its own builtin strlen()... */ +#undef strlen +size_t xstrlen(const char *string) +{ + return(strlen(string)); +} + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/libbb/xgetcwd.c b/libbb/xgetcwd.c new file mode 100644 index 000000000..4f7748123 --- /dev/null +++ b/libbb/xgetcwd.c @@ -0,0 +1,53 @@ +/* + * xgetcwd.c -- return current directory with unlimited length + * Copyright (C) 1992, 1996 Free Software Foundation, Inc. + * Written by David MacKenzie . + * + * Special function for busybox written by Vladimir Oleynik +*/ + +#include +#include +#include +#include +#include +#include "libbb.h" + +/* Amount to increase buffer size by in each try. */ +#define PATH_INCR 32 + +/* Return the current directory, newly allocated, arbitrarily long. + Return NULL and set errno on error. + If argument is not NULL (previous usage allocate memory), call free() +*/ + +char * +xgetcwd (char *cwd) +{ + char *ret; + unsigned path_max; + + errno = 0; + path_max = (unsigned) PATH_MAX; + path_max += 2; /* The getcwd docs say to do this. */ + + if(cwd==0) + cwd = xmalloc (path_max); + + errno = 0; + while ((ret = getcwd (cwd, path_max)) == NULL && errno == ERANGE) { + path_max += PATH_INCR; + cwd = xrealloc (cwd, path_max); + errno = 0; + } + + if (ret == NULL) { + int save_errno = errno; + free (cwd); + errno = save_errno; + perror_msg("getcwd()"); + return NULL; + } + + return cwd; +} diff --git a/libbb/xgethostbyname.c b/libbb/xgethostbyname.c new file mode 100644 index 000000000..f859a44af --- /dev/null +++ b/libbb/xgethostbyname.c @@ -0,0 +1,36 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini xgethostbyname implementation. + * + * 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 + * + */ + +#include +extern int h_errno; +#include "libbb.h" + + +struct hostent *xgethostbyname(const char *name) +{ + struct hostent *retval; + + if ((retval = gethostbyname(name)) == NULL) + herror_msg_and_die("%s", name); + + return retval; +} diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c new file mode 100644 index 000000000..932e487a5 --- /dev/null +++ b/libbb/xreadlink.c @@ -0,0 +1,37 @@ +/* + * xreadlink.c - safe implementation of readlink. + * Returns a NULL on failure... + */ + +#include + +/* + * NOTE: This function returns a malloced char* that you will have to free + * yourself. You have been warned. + */ + +#include +#include "libbb.h" + +extern char *xreadlink(const char *path) +{ + static const int GROWBY = 80; /* how large we will grow strings by */ + + char *buf = NULL; + int bufsize = 0, readsize = 0; + + do { + buf = xrealloc(buf, bufsize += GROWBY); + readsize = readlink(path, buf, bufsize); /* 1st try */ + if (readsize == -1) { + perror_msg("%s:%s", applet_name, path); + return NULL; + } + } + while (bufsize < readsize + 1); + + buf[readsize] = '\0'; + + return buf; +} + diff --git a/libbb/xregcomp.c b/libbb/xregcomp.c new file mode 100644 index 000000000..07cf779d1 --- /dev/null +++ b/libbb/xregcomp.c @@ -0,0 +1,49 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) many different people. If you wrote this, please + * acknowledge your work. + * + * 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 "libbb.h" +#include + + + +void xregcomp(regex_t *preg, const char *regex, int cflags) +{ + int ret; + if ((ret = regcomp(preg, regex, cflags)) != 0) { + int errmsgsz = regerror(ret, preg, NULL, 0); + char *errmsg = xmalloc(errmsgsz); + regerror(ret, preg, errmsg, errmsgsz); + error_msg_and_die("xregcomp: %s", errmsg); + } +} + + +/* END CODE */ +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/ln.c b/ln.c new file mode 100644 index 000000000..213db9b72 --- /dev/null +++ b/ln.c @@ -0,0 +1,131 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini ln implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include "busybox.h" + + +static const int LN_SYMLINK = 1; +static const int LN_FORCE = 2; +static const int LN_NODEREFERENCE = 4; + +/* + * linkDestName is where the link points to, + * linkSrcName is the name of the link to be created. + */ +static int fs_link(const char *link_destname, const char *link_srcname, + const int flag) +{ + int status; + int src_is_dir; + char *src_name; + + if (link_destname==NULL) + return(FALSE); + + src_name = (char *) xmalloc(strlen(link_srcname)+strlen(link_destname)+1); + + if (link_srcname==NULL) + strcpy(src_name, link_destname); + else + strcpy(src_name, link_srcname); + + if (flag&LN_NODEREFERENCE) + src_is_dir = is_directory(src_name, TRUE, NULL); + else + src_is_dir = is_directory(src_name, FALSE, NULL); + + if ((src_is_dir==TRUE)&&((flag&LN_NODEREFERENCE)==0)) { + char* srcdir_name; + + srcdir_name = xstrdup(link_destname); + strcat(src_name, "/"); + strcat(src_name, get_last_path_component(srcdir_name)); + free(srcdir_name); + } + + if (flag&LN_FORCE) + unlink(src_name); + + if (flag&LN_SYMLINK) + status = symlink(link_destname, src_name); + else + status = link(link_destname, src_name); + + if (status != 0) { + perror_msg(src_name); + return(FALSE); + } + return(TRUE); +} + +extern int ln_main(int argc, char **argv) +{ + int status = EXIT_SUCCESS; + int flag = 0; + int opt; + + /* Parse any options */ + while ((opt=getopt(argc, argv, "sfn")) != -1) { + switch(opt) { + case 's': + flag |= LN_SYMLINK; + break; + case 'f': + flag |= LN_FORCE; + break; + case 'n': + flag |= LN_NODEREFERENCE; + break; + default: + show_usage(); + } + } + if (optind > (argc-1)) { + show_usage(); + } + if (optind == (argc-1)) { + if (fs_link(argv[optind], + get_last_path_component(argv[optind]), flag)==FALSE) + status = EXIT_FAILURE; + } + while(optind<(argc-1)) { + if (fs_link(argv[optind], argv[argc-1], flag)==FALSE) + status = EXIT_FAILURE; + optind++; + } + exit(status); +} + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/loadacm.c b/loadacm.c new file mode 100644 index 000000000..3fb4e7665 --- /dev/null +++ b/loadacm.c @@ -0,0 +1,357 @@ +/* vi: set sw=4 ts=4: */ +/* + * Derived from + * mapscrn.c - version 0.92 + * + * Was taken from console-tools and adapted by + * Peter Novodvorsky + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +typedef unsigned short unicode; + +static long int ctoi(unsigned char *s, int *is_unicode); +static int old_screen_map_read_ascii(FILE * fp, unsigned char buf[]); +static int uni_screen_map_read_ascii(FILE * fp, unicode buf[], int *is_unicode); +static unicode utf8_to_ucs2(char *buf); +static int screen_map_load(int fd, FILE * fp); + +int loadacm_main(int argc, char **argv) +{ + int fd; + + if (argc>=2 && *argv[1]=='-') { + show_usage(); + } + + fd = open(CURRENT_VC, O_RDWR); + if (fd < 0) { + perror_msg_and_die("Error opening " CURRENT_VC); + } + + if (screen_map_load(fd, stdin)) { + perror_msg_and_die("Error loading acm"); + } + + write(fd, "\033(K", 3); + + return EXIT_SUCCESS; +} + +static int screen_map_load(int fd, FILE * fp) +{ + struct stat stbuf; + unicode wbuf[E_TABSZ]; + unsigned char buf[E_TABSZ]; + int parse_failed = 0; + int is_unicode; + + if (fstat(fileno(fp), &stbuf)) + perror_msg_and_die("Cannot stat map file"); + + /* first try a UTF screen-map: either ASCII (no restriction) or binary (regular file) */ + if (! + (parse_failed = + (-1 == uni_screen_map_read_ascii(fp, wbuf, &is_unicode))) +|| (S_ISREG(stbuf.st_mode) && (stbuf.st_size == (sizeof(unicode) * E_TABSZ)))) { /* test for binary UTF map by size */ + if (parse_failed) { + if (-1 == fseek(fp, 0, SEEK_SET)) { + if (errno == ESPIPE) + error_msg_and_die("16bit screen-map MUST be a regular file."); + else + perror_msg_and_die("fseek failed reading binary 16bit screen-map"); + } + + if (fread(wbuf, sizeof(unicode) * E_TABSZ, 1, fp) != 1) + perror_msg_and_die("Cannot read [new] map from file"); +#if 0 + else + error_msg("Input screen-map is binary."); +#endif + } + + /* if it was effectively a 16-bit ASCII, OK, else try to read as 8-bit map */ + /* same if it was binary, ie. if parse_failed */ + if (parse_failed || is_unicode) { + if (ioctl(fd, PIO_UNISCRNMAP, wbuf)) + perror_msg_and_die("PIO_UNISCRNMAP ioctl"); + else + return 0; + } + } + + /* rewind... */ + if (-1 == fseek(fp, 0, SEEK_SET)) { + if (errno == ESPIPE) + error_msg("Assuming 8bit screen-map - MUST be a regular file."), + exit(1); + else + perror_msg_and_die("fseek failed assuming 8bit screen-map"); + } + + /* ... and try an old 8-bit screen-map */ + if (!(parse_failed = (-1 == old_screen_map_read_ascii(fp, buf))) || + (S_ISREG(stbuf.st_mode) && (stbuf.st_size == E_TABSZ))) { /* test for binary old 8-bit map by size */ + if (parse_failed) { + if (-1 == fseek(fp, 0, SEEK_SET)) { + if (errno == ESPIPE) + /* should not - it succedeed above */ + error_msg_and_die("fseek() returned ESPIPE !"); + else + perror_msg_and_die("fseek for binary 8bit screen-map"); + } + + if (fread(buf, E_TABSZ, 1, fp) != 1) + perror_msg_and_die("Cannot read [old] map from file"); +#if 0 + else + error_msg("Input screen-map is binary."); +#endif + } + + if (ioctl(fd, PIO_SCRNMAP, buf)) + perror_msg_and_die("PIO_SCRNMAP ioctl"); + else + return 0; + } + error_msg("Error parsing symbolic map"); + return(1); +} + + +/* + * - reads `fp' as a 16-bit ASCII SFM file. + * - returns -1 on error. + * - returns it in `unicode' in an E_TABSZ-elements array. + * - sets `*is_unicode' flagiff there were any non-8-bit + * (ie. real 16-bit) mapping. + * + * FIXME: ignores everything after second word + */ +static int uni_screen_map_read_ascii(FILE * fp, unicode buf[], int *is_unicode) +{ + char buffer[256]; /* line buffer reading file */ + char *p, *q; /* 1st + 2nd words in line */ + int in, on; /* the same, as numbers */ + int tmp_is_unicode; /* tmp for is_unicode calculation */ + int i; /* loop index - result holder */ + int ret_code = 0; /* return code */ + sigset_t acmsigset, old_sigset; + + assert(is_unicode); + + *is_unicode = 0; + + /* first 128 codes defaults to ASCII */ + for (i = 0; i < 128; i++) + buf[i] = i; + /* remaining defaults to replacement char (usually E_TABSZ = 256) */ + for (; i < E_TABSZ; i++) + buf[i] = 0xfffd; + + /* block SIGCHLD */ + sigemptyset(&acmsigset); + sigaddset(&acmsigset, SIGCHLD); + sigprocmask(SIG_BLOCK, &acmsigset, &old_sigset); + + do { + if (NULL == fgets(buffer, sizeof(buffer), fp)) { + if (feof(fp)) + break; + else + perror_msg_and_die("uni_screen_map_read_ascii() can't read line"); + } + + /* get "charset-relative charcode", stripping leading spaces */ + p = strtok(buffer, " \t\n"); + + /* skip empty lines and comments */ + if (!p || *p == '#') + continue; + + /* get unicode mapping */ + q = strtok(NULL, " \t\n"); + if (q) { + in = ctoi(p, NULL); + if (in < 0 || in > 255) { + ret_code = -1; + break; + } + + on = ctoi(q, &tmp_is_unicode); + if (in < 0 && on > 65535) { + ret_code = -1; + break; + } + + *is_unicode |= tmp_is_unicode; + buf[in] = on; + } else { + ret_code = -1; + break; + } + } + while (1); /* terminated by break on feof() */ + + /* restore sig mask */ + sigprocmask(SIG_SETMASK, &old_sigset, NULL); + + return ret_code; +} + + +static int old_screen_map_read_ascii(FILE * fp, unsigned char buf[]) +{ + char buffer[256]; + int in, on; + char *p, *q; + + for (in = 0; in < 256; in++) + buf[in] = in; + + while (fgets(buffer, sizeof(buffer) - 1, fp)) { + p = strtok(buffer, " \t\n"); + + if (!p || *p == '#') + continue; + + q = strtok(NULL, " \t\n#"); + if (q) { + in = ctoi(p, NULL); + if (in < 0 || in > 255) + return -1; + + on = ctoi(q, NULL); + if (in < 0 && on > 255) + return -1; + + buf[in] = on; + } else + return -1; + } + + return (0); +} + + +/* + * - converts a string into an int. + * - supports dec and hex bytes, hex UCS2, single-quoted byte and UTF8 chars. + * - returns the converted value + * - if `is_unicode != NULL', use it to tell whether it was unicode + * + * CAVEAT: will report valid UTF mappings using only 1 byte as 8-bit ones. + */ +static long int ctoi(unsigned char *s, int *is_unicode) +{ + int i; + size_t ls; + + ls = strlen(s); + if (is_unicode) + *is_unicode = 0; + + /* hex-specified UCS2 */ + if ((strncmp(s, "U+", 2) == 0) && + (strspn(s + 2, "0123456789abcdefABCDEF") == ls - 2)) { + sscanf(s + 2, "%x", &i); + if (is_unicode) + *is_unicode = 1; + } + + /* hex-specified byte */ + else if ((ls <= 4) && (strncmp(s, "0x", 2) == 0) && + (strspn(s + 2, "0123456789abcdefABCDEF") == ls - 2)) + sscanf(s + 2, "%x", &i); + + /* oct-specified number (byte) */ + else if ((*s == '0') && (strspn(s, "01234567") == ls)) + sscanf(s, "%o", &i); + + /* dec-specified number (byte) */ + else if (strspn(s, "0123456789") == ls) + sscanf(s, "%d", &i); + + /* single-byte quoted char */ + else if ((strlen(s) == 3) && (s[0] == '\'') && (s[2] == '\'')) + i = s[1]; + + /* multi-byte UTF8 quoted char */ + else if ((s[0] == '\'') && (s[ls - 1] == '\'')) { + s[ls - 1] = 0; /* ensure we'll not "parse UTF too far" */ + i = utf8_to_ucs2(s + 1); + if (is_unicode) + *is_unicode = 1; + } else + return (-1); + + return (i); +} + + +static unicode utf8_to_ucs2(char *buf) +{ + int utf_count = 0; + long utf_char = 0; + unicode tc = 0; + unsigned char c; + + do { + c = *buf; + buf++; + + /* if byte should be part of multi-byte sequence */ + if (c & 0x80) { + /* if we have already started to parse a UTF8 sequence */ + if (utf_count > 0 && (c & 0xc0) == 0x80) { + utf_char = (utf_char << 6) | (c & 0x3f); + utf_count--; + if (utf_count == 0) + tc = utf_char; + else + continue; + } else { /* Possibly 1st char of a UTF8 sequence */ + + if ((c & 0xe0) == 0xc0) { + utf_count = 1; + utf_char = (c & 0x1f); + } else if ((c & 0xf0) == 0xe0) { + utf_count = 2; + utf_char = (c & 0x0f); + } else if ((c & 0xf8) == 0xf0) { + utf_count = 3; + utf_char = (c & 0x07); + } else if ((c & 0xfc) == 0xf8) { + utf_count = 4; + utf_char = (c & 0x03); + } else if ((c & 0xfe) == 0xfc) { + utf_count = 5; + utf_char = (c & 0x01); + } else + utf_count = 0; + continue; + } + } else { /* not part of multi-byte sequence - treat as ASCII + * this makes incomplete sequences to be ignored + */ + tc = c; + utf_count = 0; + } + } + while (utf_count); + + return tc; +} diff --git a/loadfont.c b/loadfont.c new file mode 100644 index 000000000..d66500195 --- /dev/null +++ b/loadfont.c @@ -0,0 +1,209 @@ +/* vi: set sw=4 ts=4: */ +/* + * loadfont.c - Eugene Crosser & Andries Brouwer + * + * Version 0.96bb + * + * Loads the console font, and possibly the corresponding screen map(s). + * (Adapted for busybox by Matej Vela.) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +static const int PSF_MAGIC1 = 0x36; +static const int PSF_MAGIC2 = 0x04; + +static const int PSF_MODE512 = 0x01; +static const int PSF_MODEHASTAB = 0x02; +static const int PSF_MAXMODE = 0x03; +static const int PSF_SEPARATOR = 0xFFFF; + +struct psf_header { + unsigned char magic1, magic2; /* Magic number */ + unsigned char mode; /* PSF font mode */ + unsigned char charsize; /* Character size */ +}; + +#define PSF_MAGIC_OK(x) ((x).magic1 == PSF_MAGIC1 && (x).magic2 == PSF_MAGIC2) + +static void loadnewfont(int fd); + +extern int loadfont_main(int argc, char **argv) +{ + int fd; + + if (argc != 1) + show_usage(); + + fd = open(CURRENT_VC, O_RDWR); + if (fd < 0) + perror_msg_and_die("Error opening " CURRENT_VC); + loadnewfont(fd); + + return EXIT_SUCCESS; +} + +static void do_loadfont(int fd, char *inbuf, int unit, int fontsize) +{ + char buf[16384]; + int i; + + memset(buf, 0, sizeof(buf)); + + if (unit < 1 || unit > 32) + error_msg_and_die("Bad character size %d", unit); + + for (i = 0; i < fontsize; i++) + memcpy(buf + (32 * i), inbuf + (unit * i), unit); + +#if defined( PIO_FONTX ) && !defined( __sparc__ ) + { + struct consolefontdesc cfd; + + cfd.charcount = fontsize; + cfd.charheight = unit; + cfd.chardata = buf; + + if (ioctl(fd, PIO_FONTX, &cfd) == 0) + return; /* success */ + perror_msg("PIO_FONTX ioctl error (trying PIO_FONT)"); + } +#endif + if (ioctl(fd, PIO_FONT, buf)) + perror_msg_and_die("PIO_FONT ioctl error"); +} + +static void +do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize) +{ + struct unimapinit advice; + struct unimapdesc ud; + struct unipair *up; + int ct = 0, maxct; + int glyph; + u_short unicode; + + maxct = tailsz; /* more than enough */ + up = (struct unipair *) xmalloc(maxct * sizeof(struct unipair)); + + for (glyph = 0; glyph < fontsize; glyph++) { + while (tailsz >= 2) { + unicode = (((u_short) inbuf[1]) << 8) + inbuf[0]; + tailsz -= 2; + inbuf += 2; + if (unicode == PSF_SEPARATOR) + break; + up[ct].unicode = unicode; + up[ct].fontpos = glyph; + ct++; + } + } + + /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP + this printf did not work on many kernels */ + + advice.advised_hashsize = 0; + advice.advised_hashstep = 0; + advice.advised_hashlevel = 0; + if (ioctl(fd, PIO_UNIMAPCLR, &advice)) { +#ifdef ENOIOCTLCMD + if (errno == ENOIOCTLCMD) { + error_msg("It seems this kernel is older than 1.1.92"); + error_msg_and_die("No Unicode mapping table loaded."); + } else +#endif + perror_msg_and_die("PIO_UNIMAPCLR"); + } + ud.entry_ct = ct; + ud.entries = up; + if (ioctl(fd, PIO_UNIMAP, &ud)) { +#if 0 + if (errno == ENOMEM) { + /* change advice parameters */ + } +#endif + perror_msg_and_die("PIO_UNIMAP"); + } +} + +static void loadnewfont(int fd) +{ + int unit; + char inbuf[32768]; /* primitive */ + unsigned int inputlth, offset; + + /* + * We used to look at the length of the input file + * with stat(); now that we accept compressed files, + * just read the entire file. + */ + inputlth = fread(inbuf, 1, sizeof(inbuf), stdin); + if (ferror(stdin)) + perror_msg_and_die("Error reading input font"); + /* use malloc/realloc in case of giant files; + maybe these do not occur: 16kB for the font, + and 16kB for the map leaves 32 unicode values + for each font position */ + if (!feof(stdin)) + perror_msg_and_die("Font too large"); + + /* test for psf first */ + { + struct psf_header psfhdr; + int fontsize; + int hastable; + unsigned int head0, head; + + if (inputlth < sizeof(struct psf_header)) + goto no_psf; + + psfhdr = *(struct psf_header *) &inbuf[0]; + + if (!PSF_MAGIC_OK(psfhdr)) + goto no_psf; + + if (psfhdr.mode > PSF_MAXMODE) + error_msg_and_die("Unsupported psf file mode"); + fontsize = ((psfhdr.mode & PSF_MODE512) ? 512 : 256); +#if !defined( PIO_FONTX ) || defined( __sparc__ ) + if (fontsize != 256) + error_msg_and_die("Only fontsize 256 supported"); +#endif + hastable = (psfhdr.mode & PSF_MODEHASTAB); + unit = psfhdr.charsize; + head0 = sizeof(struct psf_header); + + head = head0 + fontsize * unit; + if (head > inputlth || (!hastable && head != inputlth)) + error_msg_and_die("Input file: bad length"); + do_loadfont(fd, inbuf + head0, unit, fontsize); + if (hastable) + do_loadtable(fd, inbuf + head, inputlth - head, fontsize); + return; + } + no_psf: + + /* file with three code pages? */ + if (inputlth == 9780) { + offset = 40; + unit = 16; + } else { + /* bare font */ + if (inputlth & 0377) + error_msg_and_die("Bad input file size"); + offset = 0; + unit = inputlth / 256; + } + do_loadfont(fd, inbuf + offset, unit, 256); +} diff --git a/loadkmap.c b/loadkmap.c new file mode 100644 index 000000000..4f217d630 --- /dev/null +++ b/loadkmap.c @@ -0,0 +1,89 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini loadkmap implementation for busybox + * + * Copyright (C) 1998 Enrique Zanardi + * + * 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 "busybox.h" + +#define BINARY_KEYMAP_MAGIC "bkeymap" + +/* From */ +struct kbentry { + unsigned char kb_table; + unsigned char kb_index; + unsigned short kb_value; +}; +static const int KDSKBENT = 0x4B47; /* sets one entry in translation table */ + +/* From */ +static const int NR_KEYS = 128; +static const int MAX_NR_KEYMAPS = 256; + +int loadkmap_main(int argc, char **argv) +{ + struct kbentry ke; + u_short *ibuff; + int i, j, fd, readsz, pos, ibuffsz = NR_KEYS * sizeof(u_short); + char flags[MAX_NR_KEYMAPS], buff[7]; + + if (argc != 1) + show_usage(); + + fd = open(CURRENT_VC, O_RDWR); + if (fd < 0) + perror_msg_and_die("Error opening " CURRENT_VC); + + read(0, buff, 7); + if (0 != strncmp(buff, BINARY_KEYMAP_MAGIC, 7)) + error_msg_and_die("This is not a valid binary keymap."); + + if (MAX_NR_KEYMAPS != read(0, flags, MAX_NR_KEYMAPS)) + perror_msg_and_die("Error reading keymap flags"); + + ibuff = (u_short *) xmalloc(ibuffsz); + + for (i = 0; i < MAX_NR_KEYMAPS; i++) { + if (flags[i] == 1) { + pos = 0; + while (pos < ibuffsz) { + if ((readsz = read(0, (char *) ibuff + pos, ibuffsz - pos)) < 0) + perror_msg_and_die("Error reading keymap"); + pos += readsz; + } + for (j = 0; j < NR_KEYS; j++) { + ke.kb_index = j; + ke.kb_table = i; + ke.kb_value = ibuff[j]; + ioctl(fd, KDSKBENT, &ke); + } + } + } + /* Don't bother to close files. Exit does that + * automagically, so we can save a few bytes */ + /* close(fd); */ + return EXIT_SUCCESS; +} diff --git a/logger.c b/logger.c new file mode 100644 index 000000000..37155c933 --- /dev/null +++ b/logger.c @@ -0,0 +1,200 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini logger implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "busybox.h" +#if !defined BB_SYSLOGD + +#define SYSLOG_NAMES +#include + +#else +#include +# ifndef __dietlibc__ + /* We have to do this since the header file defines static + * structures. Argh.... bad libc, bad, bad... + */ + typedef struct _code { + char *c_name; + int c_val; + } CODE; + extern CODE prioritynames[]; + extern CODE facilitynames[]; +# endif +#endif + +/* Decode a symbolic name to a numeric value + * this function is based on code + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Original copyright notice is retained at the end of this file. + */ +static int decode(char *name, CODE * codetab) +{ + CODE *c; + + if (isdigit(*name)) + return (atoi(name)); + for (c = codetab; c->c_name; c++) { + if (!strcasecmp(name, c->c_name)) { + return (c->c_val); + } + } + + return (-1); +} + +/* Decode a symbolic name to a numeric value + * this function is based on code + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Original copyright notice is retained at the end of this file. + */ +static int pencode(char *s) +{ + char *save; + int lev, fac = LOG_USER; + + for (save = s; *s && *s != '.'; ++s); + if (*s) { + *s = '\0'; + fac = decode(save, facilitynames); + if (fac < 0) + error_msg_and_die("unknown facility name: %s", save); + *s++ = '.'; + } else { + s = save; + } + lev = decode(s, prioritynames); + if (lev < 0) + error_msg_and_die("unknown priority name: %s", save); + return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK)); +} + + +extern int logger_main(int argc, char **argv) +{ + int pri = LOG_USER | LOG_NOTICE; + int option = 0; + int c, i, len, opt; + char *message=NULL, buf[1024], name[128]; + + /* Fill out the name string early (may be overwritten later) */ + my_getpwuid(name, geteuid()); + + /* Parse any options */ + while ((opt = getopt(argc, argv, "p:st:")) > 0) { + switch (opt) { + case 's': + option |= LOG_PERROR; + break; + case 'p': + pri = pencode(optarg); + break; + case 't': + strncpy(name, optarg, sizeof(name)); + break; + default: + show_usage(); + } + } + + openlog(name, option, (pri | LOG_FACMASK)); + if (optind == argc) { + do { + /* read from stdin */ + i = 0; + while ((c = getc(stdin)) != EOF && c != '\n' && + i < (sizeof(buf)-1)) { + buf[i++] = c; + } + if (i > 0) { + buf[i++] = '\0'; + syslog(pri, "%s", buf); + } + } while (c != EOF); + } else { + len = 1; /* for the '\0' */ + message=xcalloc(1, 1); + for (i = optind; i < argc; i++) { + len += strlen(argv[i]); + len += 1; /* for the space between the args */ + message = xrealloc(message, len); + strcat(message, argv[i]); + strcat(message, " "); + } + message[strlen(message)-1] = '\0'; + syslog(pri, "%s", message); + } + + closelog(); + return EXIT_SUCCESS; +} + + +/*- + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * This is the original license statement for the decode and pencode functions. + * + * 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. + */ + + + diff --git a/logname.c b/logname.c new file mode 100644 index 000000000..0924b2471 --- /dev/null +++ b/logname.c @@ -0,0 +1,41 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini logname implementation for busybox + * + * 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 + * + */ + +#include +#include +#include +#include "busybox.h" + +extern int logname_main(int argc, char **argv) +{ + char user[9]; + + if (argc > 1) + show_usage(); + + my_getpwuid(user, geteuid()); + if (*user) { + puts(user); + return EXIT_SUCCESS; + } + error_msg_and_die("no login name"); +} diff --git a/logread.c b/logread.c new file mode 100644 index 000000000..d3349625c --- /dev/null +++ b/logread.c @@ -0,0 +1,144 @@ +/* vi: set sw=4 ts=4: */ +/* + * circular buffer syslog implementation for busybox + * + * Copyright (C) 2000 by Gennady Feldman + * + * Maintainer: Gennady Feldman as of Mar 12, 2001 + * + * 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" + +#if __GNU_LIBRARY__ < 5 +#error Sorry. Looks like you are using libc5. +#error libc5 shm support isnt good enough. +#error Please disable BB_FEATURE_IPC_SYSLOG +#endif + + +static const long KEY_ID = 0x414e4547; /*"GENA"*/ + +static struct shbuf_ds { + int size; // size of data written + int head; // start of message list + int tail; // end of message list + char data[1]; // data/messages +} *buf = NULL; // shared memory pointer + + +// Semaphore operation structures +static struct sembuf SMrup[1] = {{0, -1, IPC_NOWAIT | SEM_UNDO}}; // set SMrup +static struct sembuf SMrdn[2] = {{1, 0}, {0, +1, SEM_UNDO}}; // set SMrdn + +static int log_shmid = -1; // ipc shared memory id +static int log_semid = -1; // ipc semaphore id +static jmp_buf jmp_env; + +static void error_exit(const char *str); +static void interrupted(int sig); + +/* + * sem_up - up()'s a semaphore. + */ +static inline void sem_up(int semid) +{ + if ( semop(semid, SMrup, 1) == -1 ) + error_exit("semop[SMrup]"); +} + +/* + * sem_down - down()'s a semaphore + */ +static inline void sem_down(int semid) +{ + if ( semop(semid, SMrdn, 2) == -1 ) + error_exit("semop[SMrdn]"); +} + +extern int logread_main(int argc, char **argv) +{ + int i; + + /* no options, no getopt */ + if (argc > 1) + show_usage(); + + // handle intrrupt signal + if (setjmp(jmp_env)) goto output_end; + + // attempt to redefine ^C signal + signal(SIGINT, interrupted); + + if ( (log_shmid = shmget(KEY_ID, 0, 0)) == -1) + error_exit("Can't find circular buffer"); + + // Attach shared memory to our char* + if ( (buf = shmat(log_shmid, NULL, SHM_RDONLY)) == NULL) + error_exit("Can't get access to circular buffer from syslogd"); + + if ( (log_semid = semget(KEY_ID, 0, 0)) == -1) + error_exit("Can't get access to semaphone(s) for circular buffer from syslogd"); + + sem_down(log_semid); + // Read Memory + i=buf->head; + + //printf("head: %i tail: %i size: %i\n",buf->head,buf->tail,buf->size); + if (buf->head == buf->tail) { + printf("\n"); + } + + while ( i != buf->tail) { + printf("%s", buf->data+i); + i+= strlen(buf->data+i) + 1; + if (i >= buf->size ) + i=0; + } + sem_up(log_semid); + +output_end: + if (log_shmid != -1) + shmdt(buf); + + return EXIT_SUCCESS; +} + +static void interrupted(int sig){ + signal(SIGINT, SIG_IGN); + longjmp(jmp_env, 1); +} + +static void error_exit(const char *str){ + perror(str); + //release all acquired resources + if (log_shmid != -1) + shmdt(buf); + + exit(1); +} diff --git a/losetup.c b/losetup.c new file mode 100644 index 000000000..bfeb6b274 --- /dev/null +++ b/losetup.c @@ -0,0 +1,58 @@ +/* + * Mini losetup implementation for busybox + * + * Copyright (C) 2002 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 + * + */ + +#include +#include + +#include "busybox.h" + +int +losetup_main (int argc, char **argv) +{ + int delete = 0; + int offset = 0; + int opt; + + while ((opt = getopt (argc, argv, "do:")) != -1) + switch (opt) + { + case 'd': + delete = 1; + break; + + case 'o': + offset = parse_number (optarg, NULL); + break; + + default: + show_usage (); + } + + if ((delete && (offset || optind + 1 != argc)) + || (!delete && optind + 2 != argc)) + show_usage (); + + if (delete) + return del_loop (argv[optind]) ? EXIT_SUCCESS : EXIT_FAILURE; + else + return set_loop (argv[optind], argv[optind + 1], offset, &opt) + ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/ls.c b/ls.c new file mode 100644 index 000000000..360b95c06 --- /dev/null +++ b/ls.c @@ -0,0 +1,1001 @@ +/* vi: set sw=4 ts=4: */ +/* + * 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. + */ + +/* + * 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 + * linking in substantial chunks of libc can be disabled. + * + * Although I don't really want to add new features to this program to + * keep it small, I *am* interested to receive bug fixes and ways to make + * it more portable. + * + * 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 + * + * NON-OPTIMAL BEHAVIOUR: + * 1. autowidth reads directories twice + * 2. if you do a short directory listing without filetype characters + * appended, there's no need to stat each one + * PORTABILITY: + * 1. requires lstat (BSD) - how do you do it without? + */ + +enum { + TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */ + COLUMN_WIDTH = 14, /* default if AUTOWIDTH not defined */ + COLUMN_GAP = 2, /* includes the file type char */ +}; + + +/************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +#ifdef BB_FEATURE_LS_TIMESTAMPS +#include +#endif + +#ifndef MAJOR +#define MAJOR(dev) (((dev)>>8)&0xff) +#define MINOR(dev) ((dev)&0xff) +#endif + +/* what is the overall style of the listing */ +enum { +STYLE_AUTO = 0, +STYLE_LONG = 1, /* one record per line, extended info */ +STYLE_SINGLE = 2, /* one record per line */ +STYLE_COLUMNS = 3 /* fill columns */ +}; + +/* 51306 lrwxrwxrwx 1 root root 2 May 11 01:43 /bin/view -> vi* */ +/* what file information will be listed */ +#define LIST_INO (1<<0) +#define LIST_BLOCKS (1<<1) +#define LIST_MODEBITS (1<<2) +#define LIST_NLINKS (1<<3) +#define LIST_ID_NAME (1<<4) +#define LIST_ID_NUMERIC (1<<5) +#define LIST_SIZE (1<<6) +#define LIST_DEV (1<<7) +#define LIST_DATE_TIME (1<<8) +#define LIST_FULLTIME (1<<9) +#define LIST_FILENAME (1<<10) +#define LIST_SYMLINK (1<<11) +#define LIST_FILETYPE (1<<12) +#define LIST_EXEC (1<<13) + +/* what files will be displayed */ +#define DISP_NORMAL (0) /* show normal filenames */ +#define DISP_DIRNAME (1<<0) /* 2 or more items? label directories */ +#define DISP_HIDDEN (1<<1) /* show filenames starting with . */ +#define DISP_DOT (1<<2) /* show . and .. */ +#define DISP_NOLIST (1<<3) /* show directory as itself, not contents */ +#define DISP_RECURSIVE (1<<4) /* show directory and everything below it */ +#define DISP_ROWS (1<<5) /* print across rows */ + +#ifdef BB_FEATURE_LS_SORTFILES +/* how will the files be sorted */ +static const int SORT_FORWARD = 0; /* sort in reverse order */ +static const int SORT_REVERSE = 1; /* sort in reverse order */ +static const int SORT_NAME = 2; /* sort by file name */ +static const int SORT_SIZE = 3; /* sort by file size */ +static const int SORT_ATIME = 4; /* sort by last access time */ +static const int SORT_CTIME = 5; /* sort by last change time */ +static const int SORT_MTIME = 6; /* sort by last modification time */ +static const int SORT_VERSION = 7; /* sort by version */ +static const int SORT_EXT = 8; /* sort by file name extension */ +static const int SORT_DIR = 9; /* sort by file or directory */ +#endif + +#ifdef BB_FEATURE_LS_TIMESTAMPS +/* which of the three times will be used */ +static const int TIME_MOD = 0; +static const int TIME_CHANGE = 1; +static const int TIME_ACCESS = 2; +#endif + +#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) + +static const int SPLIT_DIR = 0; +static const int SPLIT_FILE = 1; +static const int SPLIT_SUBDIR = 2; + +#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f) +#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)]) +#if defined(BB_FEATURE_LS_FILETYPES) || defined(BB_FEATURE_LS_COLOR) +#define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)]) +#endif +/* colored LS support by JaWi, janwillem.janssen@lxtreme.nl */ +#ifdef BB_FEATURE_LS_COLOR +static int show_color = 0; +#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)]) +#endif + +/* + * 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 */ + struct dnode *next; /* point at the next node */ +}; +typedef struct dnode dnode_t; + +static struct dnode **list_dir(char *); +static struct dnode **dnalloc(int); +static int list_single(struct dnode *); + +static unsigned int disp_opts; +static unsigned int style_fmt; +static unsigned int list_fmt; +#ifdef BB_FEATURE_LS_SORTFILES +static unsigned int sort_opts; +static unsigned int sort_order; +#endif +#ifdef BB_FEATURE_LS_TIMESTAMPS +static unsigned int time_fmt; +#endif +#ifdef BB_FEATURE_LS_FOLLOWLINKS +static unsigned int follow_links=FALSE; +#endif + +static unsigned short column = 0; +#ifdef BB_FEATURE_AUTOWIDTH +static unsigned short terminal_width = TERMINAL_WIDTH; +static unsigned short column_width = COLUMN_WIDTH; +static unsigned short tabstops = COLUMN_GAP; +#else +static unsigned short column_width = COLUMN_WIDTH; +#endif + +static int status = EXIT_SUCCESS; + +#ifdef BB_FEATURE_HUMAN_READABLE +static unsigned long ls_disp_hr = 0; +#endif + +static int my_stat(struct dnode *cur) +{ +#ifdef BB_FEATURE_LS_FOLLOWLINKS + if (follow_links == TRUE) { + if (stat(cur->fullname, &cur->dstat)) { + perror_msg("%s", cur->fullname); + status = EXIT_FAILURE; + free(cur->fullname); + free(cur); + return -1; + } + } else +#endif + if (lstat(cur->fullname, &cur->dstat)) { + perror_msg("%s", cur->fullname); + status = EXIT_FAILURE; + free(cur->fullname); + free(cur); + return -1; + } + return 0; +} + +static void newline(void) +{ + if (column > 0) { + putchar('\n'); + column = 0; + } +} + +/*----------------------------------------------------------------------*/ +#ifdef BB_FEATURE_LS_COLOR +static char fgcolor(mode_t mode) +{ + /* Check if the file is missing */ + if ( errno == ENOENT ) { + errno = 0; + /* Color it red! */ + return '\037'; + } + if ( LIST_EXEC && 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) +{ + if ( LIST_EXEC && S_ISREG( mode ) + && ( mode & ( S_IXUSR | S_IXGRP | S_IXOTH ) ) ) + return ATTR(0xF000); /* File is executable ... */ + return ATTR(mode); +} +#endif + +/*----------------------------------------------------------------------*/ +#if defined(BB_FEATURE_LS_FILETYPES) || defined(BB_FEATURE_LS_COLOR) +static char append_char(mode_t mode) +{ + if ( !(list_fmt & LIST_FILETYPE)) + return '\0'; + if ((list_fmt & LIST_EXEC) && S_ISREG(mode) + && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return '*'; + return APPCHAR(mode); +} +#endif + +/*----------------------------------------------------------------------*/ +static void nexttabstop( void ) +{ + static short nexttab= 0; + int n=0; + + if (column > 0) { + n= nexttab - column; + if (n < 1) n= 1; + while (n--) { + putchar(' '); + column++; + } + } + nexttab= column + column_width + COLUMN_GAP; +} + +/*----------------------------------------------------------------------*/ +static int is_subdir(struct dnode *dn) +{ + return (S_ISDIR(dn->dstat.st_mode) && strcmp(dn->name, ".") != 0 && + strcmp(dn->name, "..") != 0); +} + +static int countdirs(struct dnode **dn, int nfiles) +{ + int i, dirs; + + if (dn==NULL || nfiles < 1) return(0); + dirs= 0; + for (i=0; idstat.st_mode)) dirs++; + } + return(dirs); +} + +static int countsubdirs(struct dnode **dn, int nfiles) +{ + int i, subdirs; + + if (dn == NULL || nfiles < 1) return 0; + subdirs = 0; + for (i = 0; i < nfiles; i++) + if (is_subdir(dn[i])) + subdirs++; + return subdirs; +} + +static int countfiles(struct dnode **dnp) +{ + int nfiles; + struct dnode *cur; + + if (dnp == NULL) return(0); + nfiles= 0; + for (cur= dnp[0]; cur->next != NULL ; cur= cur->next) nfiles++; + 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); + + p= (struct dnode **)xcalloc((size_t)num, (size_t)(sizeof(struct dnode *))); + return(p); +} + +#ifdef BB_FEATURE_LS_RECURSIVE +static void dfree(struct dnode **dnp) +{ + struct dnode *cur, *next; + + if(dnp == NULL) return; + + cur=dnp[0]; + while (cur != NULL) { + if (cur->fullname != NULL) free(cur->fullname); /* free the filename */ + next= cur->next; + free(cur); /* free the dnode */ + cur= next; + } + free(dnp); /* free the array holding the dnode pointers */ +} +#endif + +static struct dnode **splitdnarray(struct dnode **dn, int nfiles, int which) +{ + int dncnt, i, d; + struct dnode **dnp; + + if (dn==NULL || nfiles < 1) return(NULL); + + /* count how many dirs and regular files there are */ + if (which == SPLIT_SUBDIR) + dncnt = countsubdirs(dn, nfiles); + else { + dncnt= countdirs(dn, nfiles); /* assume we are looking for dirs */ + if (which == SPLIT_FILE) + dncnt= nfiles - dncnt; /* looking for files */ + } + + /* allocate a file array and a dir array */ + dnp= dnalloc(dncnt); + + /* copy the entrys into the file or dir array */ + for (d= i=0; idstat.st_mode)) { + dnp[d++]= dn[i]; + } /* else skip the file */ + } else if (which == SPLIT_SUBDIR) { + if (is_subdir(dn[i])) { + dnp[d++]= dn[i]; + } /* else skip the file or dir */ + } else { + if (!(S_ISDIR(dn[i]->dstat.st_mode))) { + dnp[d++]= dn[i]; + } /* else skip the dir */ + } + } + return(dnp); +} + +/*----------------------------------------------------------------------*/ +#ifdef BB_FEATURE_LS_SORTFILES +static int sortcmp(struct dnode *d1, struct dnode *d2) +{ + int cmp, dif; + + cmp= 0; + if (sort_opts == SORT_SIZE) { + dif= (int)(d1->dstat.st_size - d2->dstat.st_size); + } else if (sort_opts == SORT_ATIME) { + dif= (int)(d1->dstat.st_atime - d2->dstat.st_atime); + } else if (sort_opts == SORT_CTIME) { + dif= (int)(d1->dstat.st_ctime - d2->dstat.st_ctime); + } else if (sort_opts == SORT_MTIME) { + dif= (int)(d1->dstat.st_mtime - d2->dstat.st_mtime); + } else if (sort_opts == SORT_DIR) { + dif= S_ISDIR(d1->dstat.st_mode) - S_ISDIR(d2->dstat.st_mode); + /* } else if (sort_opts == SORT_VERSION) { */ + /* } else if (sort_opts == SORT_EXT) { */ + } else { /* assume SORT_NAME */ + dif= 0; + } + + if (dif > 0) cmp= -1; + if (dif < 0) cmp= 1; + if (dif == 0) { + /* sort by name- may be a tie_breaker for time or size cmp */ + dif= strcmp(d1->name, d2->name); + if (dif > 0) cmp= 1; + if (dif < 0) cmp= -1; + } + + if (sort_order == SORT_REVERSE) { + cmp= -1 * cmp; + } + return(cmp); +} + +/*----------------------------------------------------------------------*/ +static void shellsort(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=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; + } + } + } +} +#endif + +/*----------------------------------------------------------------------*/ +static void showfiles(struct dnode **dn, int nfiles) +{ + int i, ncols, nrows, row, nc; +#ifdef BB_FEATURE_AUTOWIDTH + int len; +#endif + + if(dn==NULL || nfiles < 1) return; + +#ifdef BB_FEATURE_AUTOWIDTH + /* find the longest file name- use that as the column width */ + column_width= 0; + for (i=0; iname) + + ((list_fmt & LIST_INO) ? 8 : 0) + + ((list_fmt & LIST_BLOCKS) ? 5 : 0) + ; + if (column_width < len) + column_width= len; + } + if (column_width >= 1) + ncols = (int)(terminal_width / (column_width + COLUMN_GAP)); + else { + ncols = 1; + column_width = COLUMN_WIDTH; + } +#else + ncols= TERMINAL_WIDTH; +#endif + switch (style_fmt) { + case STYLE_LONG: /* one record per line, extended info */ + case STYLE_SINGLE: /* one record per line */ + ncols= 1; + break; + } + + if (ncols > 1) { + nrows = nfiles / ncols; + } else { + nrows = nfiles; + ncols = 1; + } + if ((nrows * ncols) < nfiles) nrows++; /* round up fractionals */ + + if (nrows > nfiles) nrows= nfiles; + for (row=0; rowfullname); + } + subdnp= list_dir(dn[i]->fullname); + nfiles= countfiles(subdnp); + if (nfiles > 0) { + /* list all files at this level */ +#ifdef BB_FEATURE_LS_SORTFILES + shellsort(subdnp, nfiles); +#endif + showfiles(subdnp, nfiles); +#ifdef BB_FEATURE_LS_RECURSIVE + if (disp_opts & DISP_RECURSIVE) { + /* recursive- list the sub-dirs */ + dnd= splitdnarray(subdnp, nfiles, SPLIT_SUBDIR); + dndirs= countsubdirs(subdnp, nfiles); + if (dndirs > 0) { +#ifdef BB_FEATURE_LS_SORTFILES + shellsort(dnd, dndirs); +#endif + showdirs(dnd, dndirs); + free(dnd); /* free the array of dnode pointers to the dirs */ + } + } + dfree(subdnp); /* free the dnodes and the fullname mem */ +#endif + } + } +} + +/*----------------------------------------------------------------------*/ +static struct dnode **list_dir(char *path) +{ + struct dnode *dn, *cur, **dnp; + struct dirent *entry; + DIR *dir; + int i, nfiles; + + if (path==NULL) return(NULL); + + dn= NULL; + nfiles= 0; + dir = opendir(path); + if (dir == NULL) { + perror_msg("%s", path); + status = EXIT_FAILURE; + return(NULL); /* could not open the dir */ + } + while ((entry = readdir(dir)) != NULL) { + /* are we going to list the file- it may be . or .. or a hidden file */ + if ((strcmp(entry->d_name, ".")==0) && !(disp_opts & DISP_DOT)) + continue; + if ((strcmp(entry->d_name, "..")==0) && !(disp_opts & DISP_DOT)) + continue; + if ((entry->d_name[0] == '.') && !(disp_opts & DISP_HIDDEN)) + continue; + cur= (struct dnode *)xmalloc(sizeof(struct dnode)); + cur->fullname = concat_path_file(path, entry->d_name); + cur->name = cur->fullname + + (strlen(cur->fullname) - strlen(entry->d_name)); + if (my_stat(cur)) + continue; + cur->next= dn; + dn= cur; + nfiles++; + } + closedir(dir); + + /* now that we know how many files there are + ** allocate memory for an array to hold dnode pointers + */ + if (nfiles < 1) return(NULL); + dnp= dnalloc(nfiles); + for (i=0, cur=dn; inext; + } + + return(dnp); +} + +/*----------------------------------------------------------------------*/ +static int list_single(struct dnode *dn) +{ + int i; +#ifdef BB_FEATURE_LS_USERNAME + char scratch[BUFSIZ + 1]; +#endif +#ifdef BB_FEATURE_LS_TIMESTAMPS + char *filetime; + time_t ttime, age; +#endif +#if defined (BB_FEATURE_LS_FILETYPES) || defined (BB_FEATURE_LS_COLOR) + struct stat info; + char append; +#endif + + if (dn==NULL || dn->fullname==NULL) return(0); + +#ifdef BB_FEATURE_LS_TIMESTAMPS + ttime= dn->dstat.st_mtime; /* the default time */ + if (time_fmt & TIME_ACCESS) ttime= dn->dstat.st_atime; + if (time_fmt & TIME_CHANGE) ttime= dn->dstat.st_ctime; + filetime= ctime(&ttime); +#endif +#ifdef BB_FEATURE_LS_FILETYPES + append = append_char(dn->dstat.st_mode); +#endif + + for (i=0; i<=31; i++) { + switch (list_fmt & (1<dstat.st_ino); + column += 8; + break; + case LIST_BLOCKS: +#ifdef BB_FEATURE_HUMAN_READABLE + fprintf(stdout, "%6s ", make_human_readable_str(dn->dstat.st_blocks>>1, + KILOBYTE, (ls_disp_hr==TRUE)? 0: KILOBYTE)); +#else +#if _FILE_OFFSET_BITS == 64 + printf("%4lld ", dn->dstat.st_blocks>>1); +#else + printf("%4ld ", dn->dstat.st_blocks>>1); +#endif +#endif + column += 5; + break; + case LIST_MODEBITS: + printf("%-10s ", (char *)mode_string(dn->dstat.st_mode)); + column += 10; + break; + case LIST_NLINKS: + printf("%4ld ", (long)dn->dstat.st_nlink); + column += 10; + break; + case LIST_ID_NAME: +#ifdef BB_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; +#endif + case LIST_ID_NUMERIC: + printf("%-8ld %-8ld", (long)dn->dstat.st_uid, (long)dn->dstat.st_gid); + column += 17; + break; + case LIST_SIZE: + case LIST_DEV: + if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) { + printf("%4d, %3d ", (int)MAJOR(dn->dstat.st_rdev), (int)MINOR(dn->dstat.st_rdev)); + } else { +#ifdef BB_FEATURE_HUMAN_READABLE + if (ls_disp_hr==TRUE) { + fprintf(stdout, "%8s ", make_human_readable_str(dn->dstat.st_size, 1, 0)); + } else +#endif + { +#if _FILE_OFFSET_BITS == 64 + printf("%9lld ", (long long)dn->dstat.st_size); +#else + printf("%9ld ", dn->dstat.st_size); +#endif + } + } + column += 10; + break; +#ifdef BB_FEATURE_LS_TIMESTAMPS + case LIST_FULLTIME: + case LIST_DATE_TIME: + if (list_fmt & LIST_FULLTIME) { + printf("%24.24s ", filetime); + column += 25; + break; + } + age = time(NULL) - ttime; + printf("%6.6s ", filetime+4); + if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) { + /* hh:mm if less than 6 months old */ + printf("%5.5s ", filetime+11); + } else { + printf(" %4.4s ", filetime+20); + } + column += 13; + break; +#endif + case LIST_FILENAME: +#ifdef BB_FEATURE_LS_COLOR + errno = 0; + if (show_color && !lstat(dn->fullname, &info)) { + printf( "\033[%d;%dm", bgcolor(info.st_mode), + fgcolor(info.st_mode) ); + } +#endif + printf("%s", dn->name); +#ifdef BB_FEATURE_LS_COLOR + if (show_color) { + printf( "\033[0m" ); + } +#endif + column += strlen(dn->name); + break; + case LIST_SYMLINK: + if (S_ISLNK(dn->dstat.st_mode)) { + char *lpath = xreadlink(dn->fullname); + if (lpath) { + printf(" -> "); +#if defined(BB_FEATURE_LS_FILETYPES) || defined(BB_FEATURE_LS_COLOR) + if (!stat(dn->fullname, &info)) { + append = append_char(info.st_mode); + } +#endif +#ifdef BB_FEATURE_LS_COLOR + if (show_color) { + errno = 0; + printf( "\033[%d;%dm", bgcolor(info.st_mode), + fgcolor(info.st_mode) ); + } +#endif + printf("%s", lpath); +#ifdef BB_FEATURE_LS_COLOR + if (show_color) { + printf( "\033[0m" ); + } +#endif + column += strlen(lpath) + 4; + free(lpath); + } + } + break; +#ifdef BB_FEATURE_LS_FILETYPES + case LIST_FILETYPE: + if (append != '\0') { + printf("%1c", append); + column++; + } + break; +#endif + } + } + + return(0); +} + +/*----------------------------------------------------------------------*/ +extern int ls_main(int argc, 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 BB_FEATURE_AUTOWIDTH + struct winsize win = { 0, 0, 0, 0 }; +#endif + + disp_opts= DISP_NORMAL; + style_fmt= STYLE_AUTO; + list_fmt= LIST_SHORT; +#ifdef BB_FEATURE_LS_SORTFILES + sort_opts= SORT_NAME; + sort_order= SORT_FORWARD; +#endif +#ifdef BB_FEATURE_LS_TIMESTAMPS + time_fmt= TIME_MOD; +#endif +#ifdef BB_FEATURE_AUTOWIDTH + ioctl(fileno(stdout), TIOCGWINSZ, &win); + if (win.ws_row > 4) + column_width = win.ws_row - 2; + if (win.ws_col > 0) + terminal_width = win.ws_col - 1; +#endif + nfiles=0; + +#ifdef BB_FEATURE_LS_COLOR + if (isatty(fileno(stdout))) + show_color = 1; +#endif + + /* process options */ + while ((opt = getopt(argc, argv, "1AaCdgilnsx" +#ifdef BB_FEATURE_AUTOWIDTH +"T:w:" +#endif +#ifdef BB_FEATURE_LS_FILETYPES +"Fp" +#endif +#ifdef BB_FEATURE_LS_RECURSIVE +"R" +#endif +#ifdef BB_FEATURE_LS_SORTFILES +"rSvX" +#endif +#ifdef BB_FEATURE_LS_TIMESTAMPS +"cetu" +#endif +#ifdef BB_FEATURE_LS_FOLLOWLINKS +"L" +#endif +#ifdef BB_FEATURE_HUMAN_READABLE +"h" +#endif +"k")) > 0) { + switch (opt) { + case '1': style_fmt = STYLE_SINGLE; break; + case 'A': disp_opts |= DISP_HIDDEN; break; + case 'a': disp_opts |= DISP_HIDDEN | DISP_DOT; break; + case 'C': style_fmt = STYLE_COLUMNS; break; + case 'd': disp_opts |= DISP_NOLIST; break; + case 'g': /* ignore -- for ftp servers */ break; + case 'i': list_fmt |= LIST_INO; break; + case 'l': + style_fmt = STYLE_LONG; + list_fmt |= LIST_LONG; +#ifdef BB_FEATURE_HUMAN_READABLE + ls_disp_hr = FALSE; +#endif + break; + case 'n': list_fmt |= LIST_ID_NUMERIC; break; + case 's': list_fmt |= LIST_BLOCKS; break; + case 'x': disp_opts = DISP_ROWS; break; +#ifdef BB_FEATURE_LS_FILETYPES + case 'F': list_fmt |= LIST_FILETYPE | LIST_EXEC; break; + case 'p': list_fmt |= LIST_FILETYPE; break; +#endif +#ifdef BB_FEATURE_LS_RECURSIVE + case 'R': disp_opts |= DISP_RECURSIVE; break; +#endif +#ifdef BB_FEATURE_LS_SORTFILES + case 'r': sort_order |= SORT_REVERSE; break; + case 'S': sort_opts= SORT_SIZE; break; + case 'v': sort_opts= SORT_VERSION; break; + case 'X': sort_opts= SORT_EXT; break; +#endif +#ifdef BB_FEATURE_LS_TIMESTAMPS + case 'e': list_fmt |= LIST_FULLTIME; break; + case 'c': + time_fmt = TIME_CHANGE; +#ifdef BB_FEATURE_LS_SORTFILES + sort_opts= SORT_CTIME; +#endif + break; + case 'u': + time_fmt = TIME_ACCESS; +#ifdef BB_FEATURE_LS_SORTFILES + sort_opts= SORT_ATIME; +#endif + break; + case 't': +#ifdef BB_FEATURE_LS_SORTFILES + sort_opts= SORT_MTIME; +#endif + break; +#endif +#ifdef BB_FEATURE_LS_FOLLOWLINKS + case 'L': follow_links= TRUE; break; +#endif +#ifdef BB_FEATURE_AUTOWIDTH + case 'T': tabstops= atoi(optarg); break; + case 'w': terminal_width= atoi(optarg); break; +#endif +#ifdef BB_FEATURE_HUMAN_READABLE + case 'h': ls_disp_hr = TRUE; break; +#endif + case 'k': break; + default: + goto print_usage_message; + } + } + + /* sort out which command line options take precedence */ +#ifdef BB_FEATURE_LS_RECURSIVE + if (disp_opts & DISP_NOLIST) + disp_opts &= ~DISP_RECURSIVE; /* no recurse if listing only dir */ +#endif +#if defined (BB_FEATURE_LS_TIMESTAMPS) && defined (BB_FEATURE_LS_SORTFILES) + if (time_fmt & TIME_CHANGE) sort_opts= SORT_CTIME; + if (time_fmt & TIME_ACCESS) sort_opts= SORT_ATIME; +#endif + if (style_fmt != STYLE_LONG) + list_fmt &= ~LIST_ID_NUMERIC; /* numeric uid only for long list */ +#ifdef BB_FEATURE_LS_USERNAME + if (style_fmt == STYLE_LONG && (list_fmt & LIST_ID_NUMERIC)) + list_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */ +#endif + + /* choose a display format */ + if (style_fmt == STYLE_AUTO) + style_fmt = isatty(fileno(stdout)) ? 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]= 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 */ + } + } + + /* now, everything is in the av array */ + if (ac > 1) + disp_opts |= DISP_DIRNAME; /* 2 or more items? label directories */ + + /* stuff the command line file names into an dnode array */ + dn=NULL; + for (oi=0 ; oi < ac; oi++) { + cur= (struct dnode *)xmalloc(sizeof(struct dnode)); + cur->fullname= xstrdup(av[oi]); + cur->name= cur->fullname; + if (my_stat(cur)) + continue; + cur->next= dn; + dn= cur; + nfiles++; + } + + /* now that we know how many files there are + ** allocate memory for an array to hold dnode pointers + */ + dnp= dnalloc(nfiles); + for (i=0, cur=dn; inext; + } + + + if (disp_opts & DISP_NOLIST) { +#ifdef BB_FEATURE_LS_SORTFILES + shellsort(dnp, nfiles); +#endif + if (nfiles > 0) showfiles(dnp, nfiles); + } else { + dnd= splitdnarray(dnp, nfiles, SPLIT_DIR); + dnf= splitdnarray(dnp, nfiles, SPLIT_FILE); + dndirs= countdirs(dnp, nfiles); + dnfiles= nfiles - dndirs; + if (dnfiles > 0) { +#ifdef BB_FEATURE_LS_SORTFILES + shellsort(dnf, dnfiles); +#endif + showfiles(dnf, dnfiles); + } + if (dndirs > 0) { +#ifdef BB_FEATURE_LS_SORTFILES + shellsort(dnd, dndirs); +#endif + showdirs(dnd, dndirs); + } + } + return(status); + + print_usage_message: + show_usage(); +} diff --git a/lsmod.c b/lsmod.c new file mode 100644 index 000000000..a7da1c938 --- /dev/null +++ b/lsmod.c @@ -0,0 +1,195 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini lsmod implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen + * + * Modified by Alcove, Julien Gaulmin and + * Nicolas Ferre to support pre 2.1 kernels + * (which lack the query_module() interface). + * + * 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 +#include +#include +#include "busybox.h" + + +#define TAINT_FILENAME "/proc/sys/kernel/tainted" +#define TAINT_PROPRIETORY_MODULE (1<<0) +#define TAINT_FORCED_MODULE (1<<1) +#define TAINT_UNSAFE_SMP (1<<2) + +void check_tainted(void) +{ + int tainted; + FILE *f; + + tainted = 0; + if ((f = fopen(TAINT_FILENAME, "r"))) { + fscanf(f, "%d", &tainted); + fclose(f); + } + if (f && tainted) { + printf(" Tainted: %c%c%c\n", + tainted & TAINT_PROPRIETORY_MODULE ? 'P' : 'G', + tainted & TAINT_FORCED_MODULE ? 'F' : ' ', + tainted & TAINT_UNSAFE_SMP ? 'S' : ' '); + } + else { + printf(" Not tainted\n"); + } +} + + +#ifdef BB_FEATURE_NEW_MODULE_INTERFACE + +struct module_info +{ + unsigned long addr; + unsigned long size; + unsigned long flags; + long usecount; +}; + + +int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret); + +/* Values for query_module's which. */ +static const int QM_MODULES = 1; +static const int QM_DEPS = 2; +static const int QM_REFS = 3; +static const int QM_SYMBOLS = 4; +static const int QM_INFO = 5; + +/* Bits of module.flags. */ +static const int NEW_MOD_RUNNING = 1; +static const int NEW_MOD_DELETED = 2; +static const int NEW_MOD_AUTOCLEAN = 4; +static const int NEW_MOD_VISITED = 8; +static const int NEW_MOD_USED_ONCE = 16; +static const int NEW_MOD_INITIALIZING = 64; + +static int my_query_module(const char *name, int which, void **buf, + size_t *bufsize, size_t *ret) +{ + int my_ret; + + my_ret = query_module(name, which, *buf, *bufsize, ret); + + if (my_ret == -1 && errno == ENOSPC) { + *buf = xrealloc(*buf, *ret); + *bufsize = *ret; + + my_ret = query_module(name, which, *buf, *bufsize, ret); + } + + return my_ret; +} + +extern int lsmod_main(int argc, char **argv) +{ + struct module_info info; + char *module_names, *mn, *deps, *dn; + size_t bufsize, depsize, nmod, count, i, j; + + module_names = xmalloc(bufsize = 256); + if (my_query_module(NULL, QM_MODULES, (void **)&module_names, &bufsize, + &nmod)) { + perror_msg_and_die("QM_MODULES"); + } + + deps = xmalloc(depsize = 256); + printf("Module Size Used by"); + check_tainted(); + + for (i = 0, mn = module_names; i < nmod; mn += strlen(mn) + 1, i++) { + if (query_module(mn, QM_INFO, &info, sizeof(info), &count)) { + if (errno == ENOENT) { + /* The module was removed out from underneath us. */ + continue; + } + /* else choke */ + perror_msg_and_die("module %s: QM_INFO", mn); + } + if (my_query_module(mn, QM_REFS, (void **)&deps, &depsize, &count)) { + if (errno == ENOENT) { + /* The module was removed out from underneath us. */ + continue; + } + perror_msg_and_die("module %s: QM_REFS", mn); + } + printf("%-20s%8lu%4ld", mn, info.size, info.usecount); + if (info.flags & NEW_MOD_DELETED) + printf(" (deleted)"); + else if (info.flags & NEW_MOD_INITIALIZING) + printf(" (initializing)"); + else if (!(info.flags & NEW_MOD_RUNNING)) + printf(" (uninitialized)"); + else { + if (info.flags & NEW_MOD_AUTOCLEAN) + printf(" (autoclean) "); + if (!(info.flags & NEW_MOD_USED_ONCE)) + printf(" (unused)"); + } + if (count) printf(" ["); + for (j = 0, dn = deps; j < count; dn += strlen(dn) + 1, j++) { + printf("%s%s", dn, (j==count-1)? "":" "); + } + if (count) printf("]"); + + printf("\n"); + } + + + return( 0); +} + +#else /*BB_FEATURE_OLD_MODULE_INTERFACE*/ + +extern int lsmod_main(int argc, char **argv) +{ + int fd, i; + char line[128]; + + printf("Module Size Used by"); + check_tainted(); + fflush(stdout); + + if ((fd = open("/proc/modules", O_RDONLY)) >= 0 ) { + while ((i = read(fd, line, sizeof(line))) > 0) { + write(fileno(stdout), line, i); + } + close(fd); + return 0; + } + perror_msg_and_die("/proc/modules"); + return 1; +} + +#endif /*BB_FEATURE_OLD_MODULE_INTERFACE*/ diff --git a/makedevs.c b/makedevs.c new file mode 100644 index 000000000..67b28b534 --- /dev/null +++ b/makedevs.c @@ -0,0 +1,92 @@ +/* vi: set sw=4 ts=4: */ +/* + * public domain -- Dave 'Kill a Cop' Cinege + * + * makedevs + * Make ranges of device files quickly. + * known bugs: can't deal with alpha ranges + */ + +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +int makedevs_main(int argc, char **argv) +{ + mode_t mode; + char *basedev, *type, *nodname, buf[255]; + int major, Sminor, S, E; + + if (argc < 7 || *argv[1]=='-') + show_usage(); + + basedev = argv[1]; + type = argv[2]; + major = atoi(argv[3]) << 8; /* correcting param to mknod() */ + Sminor = atoi(argv[4]); + S = atoi(argv[5]); + E = atoi(argv[6]); + nodname = argc == 8 ? basedev : buf; + + mode = 0660; + + switch (type[0]) { + case 'c': + mode |= S_IFCHR; + break; + case 'b': + mode |= S_IFBLK; + break; + case 'f': + mode |= S_IFIFO; + break; + default: + show_usage(); + } + + while (S <= E) { + int sz; + + sz = snprintf(buf, sizeof(buf), "%s%d", basedev, S); + if(sz<0 || sz>=sizeof(buf)) /* libc different */ + error_msg_and_die("%s too large", basedev); + + /* if mode != S_IFCHR and != S_IFBLK third param in mknod() ignored */ + + if (mknod(nodname, mode, major | Sminor)) + error_msg("Failed to create: %s", nodname); + + if (nodname == basedev) /* ex. /dev/hda - to /dev/hda1 ... */ + nodname = buf; + S++; + Sminor++; + } + + return 0; +} + +/* +And this is what this program replaces. The shell is too slow! + +makedev () { +local basedev=$1; local S=$2; local E=$3 +local major=$4; local Sminor=$5; local type=$6 +local sbase=$7 + + if [ ! "$sbase" = "" ]; then + mknod "$basedev" $type $major $Sminor + S=`expr $S + 1` + Sminor=`expr $Sminor + 1` + fi + + while [ $S -le $E ]; do + mknod "$basedev$S" $type $major $Sminor + S=`expr $S + 1` + Sminor=`expr $Sminor + 1` + done +} +*/ diff --git a/md5sum.c b/md5sum.c new file mode 100644 index 000000000..da79f83d8 --- /dev/null +++ b/md5sum.c @@ -0,0 +1,1074 @@ +/* md5sum.c - Compute MD5 checksum of files or strings according to the + * definition of MD5 in RFC 1321 from April 1992. + * Copyright (C) 1995-1999 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Written by Ulrich Drepper */ +/* 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) + +/* 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))) + + +//---------------------------------------------------------------------------- +//--------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 + + 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) + + /* 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 = wfopen(filename, "r"); + if (fp == NULL) + return FALSE; + } + + if (md5_stream(fp, md5_result)) { + perror_msg("%s", filename); + + if (fp != stdin) + fclose(fp); + return FALSE; + } + + if (fp != stdin && fclose(fp) == EOF) { + 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 = 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) { + 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)) { + error_msg("%s: read error", checkfile_name); + return FALSE; + } + + if (checkfile_stream != stdin && fclose(checkfile_stream) == EOF) { + perror_msg("md5sum: %s", checkfile_name); + return FALSE; + } + + if (n_properly_formated_lines == 0) { + /* Warn if no tests are found. */ + 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) { + 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) { + 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: + show_usage(); + } + } + + if (file_type_specified && do_check) { + error_msg_and_die("the -b and -t options are meaningless when verifying checksums"); + } + + if (n_strings > 0 && do_check) { + error_msg_and_die("the -g and -c options are mutually exclusive"); + } + + if (status_only && !do_check) { + error_msg_and_die("the -s option is meaningful only when verifying checksums"); + } + + if (warn && !do_check) { + error_msg_and_die("the -w option is meaningful only when verifying checksums"); + } + + if (n_strings > 0) { + size_t i; + + if (optind < argc) { + 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) { + 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) { + error_msg_and_die("write error"); + } + + if (have_read_stdin && fclose (stdin) == EOF) { + error_msg_and_die("standard input"); + } + + if (err == 0) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; +} diff --git a/mk_loop_h.sh b/mk_loop_h.sh new file mode 100755 index 000000000..5adfbd55f --- /dev/null +++ b/mk_loop_h.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# +# Figure out (i) the type of dev_t (ii) the defines for loop stuff +# +# Output of this script is normally redirected to "loop.h". + +# Since 1.3.79 there is an include file +# that defines __kernel_dev_t. +# (The file itself appeared in 1.3.78, but there it defined __dev_t.) +# If it exists, we use it, or, rather, which +# avoids namespace pollution. Otherwise we guess that __kernel_dev_t +# is an unsigned short (which is true on i386, but false on alpha). + +# BUG: This test is actually broken if your gcc is not configured to +# search /usr/include, as may well happen with cross-compilers. +# It would be better to ask $(CC) if these files can be found. + +if [ -f ${LINUXDIR:-/usr}/include/linux/posix_types.h ]; then + echo '#include ' + echo '#undef dev_t' + echo '#define dev_t __kernel_dev_t' +else + echo '#undef dev_t' + echo '#define dev_t unsigned short' +fi + +# Next we have to find the loop stuff itself. +# First try kernel source, then a private version. + +if [ -f ${LINUXDIR:-/usr}/include/linux/loop.h ]; then + echo '#include ' +else + echo '#include "real_loop.h"' +fi + +echo '#undef dev_t' + diff --git a/mkdir.c b/mkdir.c new file mode 100644 index 000000000..03c49f098 --- /dev/null +++ b/mkdir.c @@ -0,0 +1,64 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini mkdir implementation for busybox + * + * 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "busybox.h" + +extern int mkdir_main (int argc, char **argv) +{ + mode_t mode = -1; + int flags = 0; + int status = 0; + int i, opt; + + while ((opt = getopt (argc, argv, "m:p")) != -1) { + switch (opt) { + case 'm': + mode = 0777; + if (!parse_mode (optarg, &mode)) + error_msg_and_die ("invalid mode `%s'", optarg); + break; + case 'p': + flags |= FILEUTILS_RECUR; + break; + default: + show_usage (); + } + } + + if (optind == argc) + show_usage (); + + for (i = optind; i < argc; i++) + if (make_directory (argv[i], mode, flags) < 0) + status = 1; + + return status; +} diff --git a/mkfifo.c b/mkfifo.c new file mode 100644 index 000000000..ca217fa23 --- /dev/null +++ b/mkfifo.c @@ -0,0 +1,60 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini mkfifo implementation for busybox + * + * Copyright (C) 1999 by Randolph Chung + * + * 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 "busybox.h" + +extern int mkfifo_main(int argc, char **argv) +{ + char *thisarg; + mode_t mode = 0666; + + argc--; + argv++; + + /* Parse any options */ + while (argc > 1) { + if (**argv != '-') + show_usage(); + thisarg = *argv; + thisarg++; + switch (*thisarg) { + case 'm': + argc--; + argv++; + parse_mode(*argv, &mode); + break; + default: + show_usage(); + } + argc--; + argv++; + } + if (argc < 1 || *argv[0] == '-') + show_usage(); + if (mkfifo(*argv, mode) < 0) + perror_msg_and_die("mkfifo"); + return EXIT_SUCCESS; +} diff --git a/mkfs_minix.c b/mkfs_minix.c new file mode 100644 index 000000000..ccc0e85d7 --- /dev/null +++ b/mkfs_minix.c @@ -0,0 +1,847 @@ +/* vi: set sw=4 ts=4: */ +/* + * mkfs.c - make a linux (minix) file-system. + * + * (C) 1991 Linus Torvalds. This file may be redistributed as per + * the Linux copyright. + */ + +/* + * DD.MM.YY + * + * 24.11.91 - Time began. Used the fsck sources to get started. + * + * 25.11.91 - Corrected some bugs. Added support for ".badblocks" + * The algorithm for ".badblocks" is a bit weird, but + * it should work. Oh, well. + * + * 25.01.92 - Added the -l option for getting the list of bad blocks + * out of a named file. (Dave Rivers, rivers@ponds.uucp) + * + * 28.02.92 - Added %-information when using -c. + * + * 28.02.93 - Added support for other namelengths than the original + * 14 characters so that I can test the new kernel routines.. + * + * 09.10.93 - Make exit status conform to that required by fsutil + * (Rik Faith, faith@cs.unc.edu) + * + * 31.10.93 - Added inode request feature, for backup floppies: use + * 32 inodes, for a news partition use more. + * (Scott Heavner, sdh@po.cwru.edu) + * + * 03.01.94 - Added support for file system valid flag. + * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu) + * + * 30.10.94 - added support for v2 filesystem + * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de) + * + * 09.11.94 - Added test to prevent overwrite of mounted fs adapted + * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs + * program. (Daniel Quinlan, quinlan@yggdrasil.com) + * + * 03.20.95 - Clear first 512 bytes of filesystem to make certain that + * the filesystem is not misidentified as a MS-DOS FAT filesystem. + * (Daniel Quinlan, quinlan@yggdrasil.com) + * + * 02.07.96 - Added small patch from Russell King to make the program a + * good deal more portable (janl@math.uio.no) + * + * Usage: mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks] + * + * -c for readablility checking (SLOW!) + * -l for getting a list of bad blocks from a file. + * -n for namelength (currently the kernel only uses 14 or 30) + * -i for number of inodes + * -v for v2 filesystem + * + * The device may be a block device or a image of one, but this isn't + * enforced (but it's not much fun on a character device :-). + * + * Modified for BusyBox by Erik Andersen -- + * removed getopt based parser and added a hand rolled one. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +#define MINIX_ROOT_INO 1 +#define MINIX_LINK_MAX 250 +#define MINIX2_LINK_MAX 65530 + +#define MINIX_I_MAP_SLOTS 8 +#define MINIX_Z_MAP_SLOTS 64 +#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ +#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ +#define MINIX2_SUPER_MAGIC 0x2468 /* minix V2 fs */ +#define MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 fs, 30 char names */ +#define MINIX_VALID_FS 0x0001 /* Clean fs. */ +#define MINIX_ERROR_FS 0x0002 /* fs has errors. */ + +#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) +#define MINIX2_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix2_inode))) + +#define MINIX_V1 0x0001 /* original minix fs */ +#define MINIX_V2 0x0002 /* minix V2 fs */ + +#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version + +/* + * This is the original minix inode layout on disk. + * Note the 8-bit gid and atime and ctime. + */ +struct minix_inode { + u_int16_t i_mode; + u_int16_t i_uid; + u_int32_t i_size; + u_int32_t i_time; + u_int8_t i_gid; + u_int8_t i_nlinks; + u_int16_t i_zone[9]; +}; + +/* + * The new minix inode has all the time entries, as well as + * long block numbers and a third indirect block (7+1+1+1 + * instead of 7+1+1). Also, some previously 8-bit values are + * now 16-bit. The inode is now 64 bytes instead of 32. + */ +struct minix2_inode { + u_int16_t i_mode; + u_int16_t i_nlinks; + u_int16_t i_uid; + u_int16_t i_gid; + u_int32_t i_size; + u_int32_t i_atime; + u_int32_t i_mtime; + u_int32_t i_ctime; + u_int32_t i_zone[10]; +}; + +/* + * minix super-block data on disk + */ +struct minix_super_block { + u_int16_t s_ninodes; + u_int16_t s_nzones; + u_int16_t s_imap_blocks; + u_int16_t s_zmap_blocks; + u_int16_t s_firstdatazone; + u_int16_t s_log_zone_size; + u_int32_t s_max_size; + u_int16_t s_magic; + u_int16_t s_state; + u_int32_t s_zones; +}; + +struct minix_dir_entry { + u_int16_t inode; + char name[0]; +}; + +#define BLOCK_SIZE_BITS 10 +#define BLOCK_SIZE (1<> 3] & (1<<(i & 7))) != 0; +} +#define inode_in_use(x) (bit(inode_map,(x))) +#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1)) + +#define mark_inode(x) (setbit(inode_map,(x))) +#define unmark_inode(x) (clrbit(inode_map,(x))) + +#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1)) +#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1)) + +/* + * Check to make certain that our new filesystem won't be created on + * an already mounted partition. Code adapted from mke2fs, Copyright + * (C) 1994 Theodore Ts'o. Also licensed under GPL. + */ +static void check_mount(void) +{ + FILE *f; + struct mntent *mnt; + + if ((f = setmntent(MOUNTED, "r")) == NULL) + return; + while ((mnt = getmntent(f)) != NULL) + if (strcmp(device_name, mnt->mnt_fsname) == 0) + break; + endmntent(f); + if (!mnt) + return; + + error_msg_and_die("%s is mounted; will not make a filesystem here!", device_name); +} + +static long valid_offset(int fd, int offset) +{ + char ch; + + if (lseek(fd, offset, 0) < 0) + return 0; + if (read(fd, &ch, 1) < 1) + return 0; + return 1; +} + +static int count_blocks(int fd) +{ + int high, low; + + low = 0; + for (high = 1; valid_offset(fd, high); high *= 2) + low = high; + while (low < high - 1) { + const int mid = (low + high) / 2; + + if (valid_offset(fd, mid)) + low = mid; + else + high = mid; + } + valid_offset(fd, 0); + return (low + 1); +} + +static int get_size(const char *file) +{ + int fd; + long size; + + if ((fd = open(file, O_RDWR)) < 0) + perror_msg_and_die("%s", file); + if (ioctl(fd, BLKGETSIZE, &size) >= 0) { + close(fd); + return (size * 512); + } + + size = count_blocks(fd); + close(fd); + return size; +} + +static void write_tables(void) +{ + /* Mark the super block valid. */ + Super.s_state |= MINIX_VALID_FS; + Super.s_state &= ~MINIX_ERROR_FS; + + if (lseek(DEV, 0, SEEK_SET)) + error_msg_and_die("seek to boot block failed in write_tables"); + if (512 != write(DEV, boot_block_buffer, 512)) + error_msg_and_die("unable to clear boot sector"); + if (BLOCK_SIZE != lseek(DEV, BLOCK_SIZE, SEEK_SET)) + error_msg_and_die("seek failed in write_tables"); + if (BLOCK_SIZE != write(DEV, super_block_buffer, BLOCK_SIZE)) + error_msg_and_die("unable to write super-block"); + if (IMAPS * BLOCK_SIZE != write(DEV, inode_map, IMAPS * BLOCK_SIZE)) + error_msg_and_die("unable to write inode map"); + if (ZMAPS * BLOCK_SIZE != write(DEV, zone_map, ZMAPS * BLOCK_SIZE)) + error_msg_and_die("unable to write zone map"); + if (INODE_BUFFER_SIZE != write(DEV, inode_buffer, INODE_BUFFER_SIZE)) + error_msg_and_die("unable to write inodes"); + +} + +static void write_block(int blk, char *buffer) +{ + if (blk * BLOCK_SIZE != lseek(DEV, blk * BLOCK_SIZE, SEEK_SET)) + error_msg_and_die("seek failed in write_block"); + if (BLOCK_SIZE != write(DEV, buffer, BLOCK_SIZE)) + error_msg_and_die("write failed in write_block"); +} + +static int get_free_block(void) +{ + int blk; + + if (used_good_blocks + 1 >= MAX_GOOD_BLOCKS) + error_msg_and_die("too many bad blocks"); + if (used_good_blocks) + blk = good_blocks_table[used_good_blocks - 1] + 1; + else + blk = FIRSTZONE; + while (blk < ZONES && zone_in_use(blk)) + blk++; + if (blk >= ZONES) + error_msg_and_die("not enough good blocks"); + good_blocks_table[used_good_blocks] = blk; + used_good_blocks++; + return blk; +} + +static void mark_good_blocks(void) +{ + int blk; + + for (blk = 0; blk < used_good_blocks; blk++) + mark_zone(good_blocks_table[blk]); +} + +static int next(int zone) +{ + if (!zone) + zone = FIRSTZONE - 1; + while (++zone < ZONES) + if (zone_in_use(zone)) + return zone; + return 0; +} + +static void make_bad_inode(void) +{ + struct minix_inode *inode = &Inode[MINIX_BAD_INO]; + int i, j, zone; + int ind = 0, dind = 0; + unsigned short ind_block[BLOCK_SIZE >> 1]; + unsigned short dind_block[BLOCK_SIZE >> 1]; + +#define NEXT_BAD (zone = next(zone)) + + if (!badblocks) + return; + mark_inode(MINIX_BAD_INO); + inode->i_nlinks = 1; + inode->i_time = time(NULL); + inode->i_mode = S_IFREG + 0000; + inode->i_size = badblocks * BLOCK_SIZE; + zone = next(0); + for (i = 0; i < 7; i++) { + inode->i_zone[i] = zone; + if (!NEXT_BAD) + goto end_bad; + } + inode->i_zone[7] = ind = get_free_block(); + memset(ind_block, 0, BLOCK_SIZE); + for (i = 0; i < 512; i++) { + ind_block[i] = zone; + if (!NEXT_BAD) + goto end_bad; + } + inode->i_zone[8] = dind = get_free_block(); + memset(dind_block, 0, BLOCK_SIZE); + for (i = 0; i < 512; i++) { + write_block(ind, (char *) ind_block); + dind_block[i] = ind = get_free_block(); + memset(ind_block, 0, BLOCK_SIZE); + for (j = 0; j < 512; j++) { + ind_block[j] = zone; + if (!NEXT_BAD) + goto end_bad; + } + } + error_msg_and_die("too many bad blocks"); + end_bad: + if (ind) + write_block(ind, (char *) ind_block); + if (dind) + write_block(dind, (char *) dind_block); +} + +#ifdef BB_FEATURE_MINIX2 +static void make_bad_inode2(void) +{ + struct minix2_inode *inode = &Inode2[MINIX_BAD_INO]; + int i, j, zone; + int ind = 0, dind = 0; + unsigned long ind_block[BLOCK_SIZE >> 2]; + unsigned long dind_block[BLOCK_SIZE >> 2]; + + if (!badblocks) + return; + mark_inode(MINIX_BAD_INO); + inode->i_nlinks = 1; + inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL); + inode->i_mode = S_IFREG + 0000; + inode->i_size = badblocks * BLOCK_SIZE; + zone = next(0); + for (i = 0; i < 7; i++) { + inode->i_zone[i] = zone; + if (!NEXT_BAD) + goto end_bad; + } + inode->i_zone[7] = ind = get_free_block(); + memset(ind_block, 0, BLOCK_SIZE); + for (i = 0; i < 256; i++) { + ind_block[i] = zone; + if (!NEXT_BAD) + goto end_bad; + } + inode->i_zone[8] = dind = get_free_block(); + memset(dind_block, 0, BLOCK_SIZE); + for (i = 0; i < 256; i++) { + write_block(ind, (char *) ind_block); + dind_block[i] = ind = get_free_block(); + memset(ind_block, 0, BLOCK_SIZE); + for (j = 0; j < 256; j++) { + ind_block[j] = zone; + if (!NEXT_BAD) + goto end_bad; + } + } + /* Could make triple indirect block here */ + error_msg_and_die("too many bad blocks"); + end_bad: + if (ind) + write_block(ind, (char *) ind_block); + if (dind) + write_block(dind, (char *) dind_block); +} +#endif + +static void make_root_inode(void) +{ + struct minix_inode *inode = &Inode[MINIX_ROOT_INO]; + + mark_inode(MINIX_ROOT_INO); + inode->i_zone[0] = get_free_block(); + inode->i_nlinks = 2; + inode->i_time = time(NULL); + if (badblocks) + inode->i_size = 3 * dirsize; + else { + root_block[2 * dirsize] = '\0'; + root_block[2 * dirsize + 1] = '\0'; + inode->i_size = 2 * dirsize; + } + inode->i_mode = S_IFDIR + 0755; + inode->i_uid = getuid(); + if (inode->i_uid) + inode->i_gid = getgid(); + write_block(inode->i_zone[0], root_block); +} + +#ifdef BB_FEATURE_MINIX2 +static void make_root_inode2(void) +{ + struct minix2_inode *inode = &Inode2[MINIX_ROOT_INO]; + + mark_inode(MINIX_ROOT_INO); + inode->i_zone[0] = get_free_block(); + inode->i_nlinks = 2; + inode->i_atime = inode->i_mtime = inode->i_ctime = time(NULL); + if (badblocks) + inode->i_size = 3 * dirsize; + else { + root_block[2 * dirsize] = '\0'; + root_block[2 * dirsize + 1] = '\0'; + inode->i_size = 2 * dirsize; + } + inode->i_mode = S_IFDIR + 0755; + inode->i_uid = getuid(); + if (inode->i_uid) + inode->i_gid = getgid(); + write_block(inode->i_zone[0], root_block); +} +#endif + +static void setup_tables(void) +{ + int i; + unsigned long inodes; + + memset(super_block_buffer, 0, BLOCK_SIZE); + memset(boot_block_buffer, 0, 512); + MAGIC = magic; + ZONESIZE = 0; + MAXSIZE = version2 ? 0x7fffffff : (7 + 512 + 512 * 512) * 1024; + ZONES = BLOCKS; +/* some magic nrs: 1 inode / 3 blocks */ + if (req_nr_inodes == 0) + inodes = BLOCKS / 3; + else + inodes = req_nr_inodes; + /* Round up inode count to fill block size */ +#ifdef BB_FEATURE_MINIX2 + if (version2) + inodes = ((inodes + MINIX2_INODES_PER_BLOCK - 1) & + ~(MINIX2_INODES_PER_BLOCK - 1)); + else +#endif + inodes = ((inodes + MINIX_INODES_PER_BLOCK - 1) & + ~(MINIX_INODES_PER_BLOCK - 1)); + if (inodes > 65535) + inodes = 65535; + INODES = inodes; + IMAPS = UPPER(INODES + 1, BITS_PER_BLOCK); + ZMAPS = 0; + i = 0; + while (ZMAPS != + UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1, + BITS_PER_BLOCK) && i < 1000) { + ZMAPS = + UPPER(BLOCKS - (2 + IMAPS + ZMAPS + INODE_BLOCKS) + 1, + BITS_PER_BLOCK); + i++; + } + /* Real bad hack but overwise mkfs.minix can be thrown + * in infinite loop... + * try: + * dd if=/dev/zero of=test.fs count=10 bs=1024 + * /sbin/mkfs.minix -i 200 test.fs + * */ + if (i >= 999) { + error_msg_and_die("unable to allocate buffers for maps"); + } + FIRSTZONE = NORM_FIRSTZONE; + inode_map = xmalloc(IMAPS * BLOCK_SIZE); + zone_map = xmalloc(ZMAPS * BLOCK_SIZE); + memset(inode_map, 0xff, IMAPS * BLOCK_SIZE); + memset(zone_map, 0xff, ZMAPS * BLOCK_SIZE); + for (i = FIRSTZONE; i < ZONES; i++) + unmark_zone(i); + for (i = MINIX_ROOT_INO; i <= INODES; i++) + unmark_inode(i); + inode_buffer = xmalloc(INODE_BUFFER_SIZE); + memset(inode_buffer, 0, INODE_BUFFER_SIZE); + printf("%ld inodes\n", INODES); + printf("%ld blocks\n", ZONES); + printf("Firstdatazone=%ld (%ld)\n", FIRSTZONE, NORM_FIRSTZONE); + printf("Zonesize=%d\n", BLOCK_SIZE << ZONESIZE); + printf("Maxsize=%ld\n\n", MAXSIZE); +} + +/* + * Perform a test of a block; return the number of + * blocks readable/writeable. + */ +static long do_check(char *buffer, int try, unsigned int current_block) +{ + long got; + + /* Seek to the correct loc. */ + if (lseek(DEV, current_block * BLOCK_SIZE, SEEK_SET) != + current_block * BLOCK_SIZE) { + error_msg_and_die("seek failed during testing of blocks"); + } + + + /* Try the read */ + got = read(DEV, buffer, try * BLOCK_SIZE); + if (got < 0) + got = 0; + if (got & (BLOCK_SIZE - 1)) { + printf("Weird values in do_check: probably bugs\n"); + } + got /= BLOCK_SIZE; + return got; +} + +static unsigned int currently_testing = 0; + +static void alarm_intr(int alnum) +{ + if (currently_testing >= ZONES) + return; + signal(SIGALRM, alarm_intr); + alarm(5); + if (!currently_testing) + return; + printf("%d ...", currently_testing); + fflush(stdout); +} + +static void check_blocks(void) +{ + int try, got; + static char buffer[BLOCK_SIZE * TEST_BUFFER_BLOCKS]; + + currently_testing = 0; + signal(SIGALRM, alarm_intr); + alarm(5); + while (currently_testing < ZONES) { + if (lseek(DEV, currently_testing * BLOCK_SIZE, SEEK_SET) != + currently_testing * BLOCK_SIZE) + error_msg_and_die("seek failed in check_blocks"); + try = TEST_BUFFER_BLOCKS; + if (currently_testing + try > ZONES) + try = ZONES - currently_testing; + got = do_check(buffer, try, currently_testing); + currently_testing += got; + if (got == try) + continue; + if (currently_testing < FIRSTZONE) + error_msg_and_die("bad blocks before data-area: cannot make fs"); + mark_zone(currently_testing); + badblocks++; + currently_testing++; + } + if (badblocks > 1) + printf("%d bad blocks\n", badblocks); + else if (badblocks == 1) + printf("one bad block\n"); +} + +static void get_list_blocks(filename) +char *filename; + +{ + FILE *listfile; + unsigned long blockno; + + listfile = xfopen(filename, "r"); + while (!feof(listfile)) { + fscanf(listfile, "%ld\n", &blockno); + mark_zone(blockno); + badblocks++; + } + if (badblocks > 1) + printf("%d bad blocks\n", badblocks); + else if (badblocks == 1) + printf("one bad block\n"); +} + +extern int mkfs_minix_main(int argc, char **argv) +{ + int i=1; + char *tmp; + struct stat statbuf; + char *listfile = NULL; + int stopIt=FALSE; + + if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE) + error_msg_and_die("bad inode size"); +#ifdef BB_FEATURE_MINIX2 + if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE) + error_msg_and_die("bad inode size"); +#endif + + /* Parse options */ + argv++; + while (--argc >= 0 && *argv && **argv) { + if (**argv == '-') { + stopIt=FALSE; + while (i > 0 && *++(*argv) && stopIt==FALSE) { + switch (**argv) { + case 'c': + check = 1; + break; + case 'i': + { + char *cp=NULL; + if (*(*argv+1) != 0) { + cp = ++(*argv); + } else { + if (--argc == 0) { + goto goodbye; + } + cp = *(++argv); + } + req_nr_inodes = strtoul(cp, &tmp, 0); + if (*tmp) + show_usage(); + stopIt=TRUE; + break; + } + case 'l': + if (--argc == 0) { + goto goodbye; + } + listfile = *(++argv); + break; + case 'n': + { + char *cp=NULL; + + if (*(*argv+1) != 0) { + cp = ++(*argv); + } else { + if (--argc == 0) { + goto goodbye; + } + cp = *(++argv); + } + i = strtoul(cp, &tmp, 0); + if (*tmp) + show_usage(); + if (i == 14) + magic = MINIX_SUPER_MAGIC; + else if (i == 30) + magic = MINIX_SUPER_MAGIC2; + else + show_usage(); + namelen = i; + dirsize = i + 2; + stopIt=TRUE; + break; + } + case 'v': +#ifdef BB_FEATURE_MINIX2 + version2 = 1; +#else + error_msg("%s: not compiled with minix v2 support", + device_name); + exit(-1); +#endif + break; + case '-': + case 'h': + default: +goodbye: + show_usage(); + } + } + } else { + if (device_name == NULL) + device_name = *argv; + else if (BLOCKS == 0) + BLOCKS = strtol(*argv, &tmp, 0); + else { + goto goodbye; + } + } + argv++; + } + + if (device_name && !BLOCKS) + BLOCKS = get_size(device_name) / 1024; + if (!device_name || BLOCKS < 10) { + show_usage(); + } +#ifdef BB_FEATURE_MINIX2 + if (version2) { + if (namelen == 14) + magic = MINIX2_SUPER_MAGIC; + else + magic = MINIX2_SUPER_MAGIC2; + } else +#endif + if (BLOCKS > 65535) + BLOCKS = 65535; + check_mount(); /* is it already mounted? */ + tmp = root_block; + *(short *) tmp = 1; + strcpy(tmp + 2, "."); + tmp += dirsize; + *(short *) tmp = 1; + strcpy(tmp + 2, ".."); + tmp += dirsize; + *(short *) tmp = 2; + strcpy(tmp + 2, ".badblocks"); + DEV = open(device_name, O_RDWR); + if (DEV < 0) + error_msg_and_die("unable to open %s", device_name); + if (fstat(DEV, &statbuf) < 0) + error_msg_and_die("unable to stat %s", device_name); + if (!S_ISBLK(statbuf.st_mode)) + check = 0; + else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) + error_msg_and_die("will not try to make filesystem on '%s'", device_name); + setup_tables(); + if (check) + check_blocks(); + else if (listfile) + get_list_blocks(listfile); +#ifdef BB_FEATURE_MINIX2 + if (version2) { + make_root_inode2(); + make_bad_inode2(); + } else +#endif + { + make_root_inode(); + make_bad_inode(); + } + mark_good_blocks(); + write_tables(); + return( 0); + +} diff --git a/mknod.c b/mknod.c new file mode 100644 index 000000000..10d026ce3 --- /dev/null +++ b/mknod.c @@ -0,0 +1,93 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini mknod implementation for busybox + * + * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 1999-2002 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +int mknod_main(int argc, char **argv) +{ + char *thisarg; + mode_t mode = 0; + mode_t perm = 0666; + dev_t dev = 0; + + argc--; + argv++; + + /* Parse any options */ + while (argc > 1) { + if (**argv != '-') + break; + thisarg = *argv; + thisarg++; + switch (*thisarg) { + case 'm': + argc--; + argv++; + parse_mode(*argv, &perm); + umask(0); + break; + default: + show_usage(); + } + argc--; + argv++; + } + if (argc != 4 && argc != 2) { + show_usage(); + } + switch (argv[1][0]) { + case 'c': + case 'u': + mode = S_IFCHR; + break; + case 'b': + mode = S_IFBLK; + break; + case 'p': + mode = S_IFIFO; + if (argc!=2) { + show_usage(); + } + break; + default: + show_usage(); + } + + if (mode == S_IFCHR || mode == S_IFBLK) { + dev = (atoi(argv[2]) << 8) | atoi(argv[3]); + } + + mode |= perm; + + if (mknod(argv[0], mode, dev) != 0) + perror_msg_and_die("%s", argv[0]); + return EXIT_SUCCESS; +} + diff --git a/mkswap.c b/mkswap.c new file mode 100644 index 000000000..bbf02095c --- /dev/null +++ b/mkswap.c @@ -0,0 +1,422 @@ +/* vi: set sw=4 ts=4: */ +/* + * mkswap.c - set up a linux swap device + * + * (C) 1991 Linus Torvalds. This file may be redistributed as per + * the Linux copyright. + */ + +/* + * 20.12.91 - time began. Got VM working yesterday by doing this by hand. + * + * Usage: mkswap [-c] [-vN] [-f] device [size-in-blocks] + * + * -c for readability checking. (Use it unless you are SURE!) + * -vN for swap areas version N. (Only N=0,1 known today.) + * -f for forcing swap creation even if it would smash partition table. + * + * The device may be a block device or an image of one, but this isn't + * enforced (but it's not much fun on a character device :-). + * + * Patches from jaggy@purplet.demon.co.uk (Mike Jagdis) to make the + * size-in-blocks parameter optional added Wed Feb 8 10:33:43 1995. + * + * Version 1 swap area code (for kernel 2.1.117), aeb, 981010. + * + * Sparc fixes, jj@ultra.linux.cz (Jakub Jelinek), 981201 - mangled by aeb. + * V1_MAX_PAGES fixes, jj, 990325. + * + * 1999-02-22 Arkadiusz Mi¶kiewicz + * - added Native Language Support + * + * from util-linux -- adapted for busybox by + * Erik Andersen . I ripped out Native Language + * Support, made some stuff smaller, and fitted for life in busybox. + * + */ + +#include +#include +#include +#include +#include +#include /* for _IO */ +#include +#include /* for PAGE_SIZE and PAGE_SHIFT */ + /* we also get PAGE_SIZE via getpagesize() */ +#include "busybox.h" + +#ifndef _IO +/* pre-1.3.45 */ +static const int BLKGETSIZE = 0x1260; +#else +/* same on i386, m68k, arm; different on alpha, mips, sparc, ppc */ +#define BLKGETSIZE _IO(0x12,96) +#endif + +static char *device_name = NULL; +static int DEV = -1; +static long PAGES = 0; +static int check = 0; +static int badpages = 0; +static int version = -1; + +#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r)) + +/* + * The definition of the union swap_header uses the constant PAGE_SIZE. + * Unfortunately, on some architectures this depends on the hardware model, + * and can only be found at run time -- we use getpagesize(). + */ + +static int pagesize; +static int *signature_page; + +static struct swap_header_v1 { + char bootbits[1024]; /* Space for disklabel etc. */ + unsigned int version; + unsigned int last_page; + unsigned int nr_badpages; + unsigned int padding[125]; + unsigned int badpages[1]; +} *p; + +static inline void init_signature_page() +{ + pagesize = getpagesize(); + +#ifdef PAGE_SIZE + if (pagesize != PAGE_SIZE) + error_msg("Assuming pages of size %d", pagesize); +#endif + signature_page = (int *) xmalloc(pagesize); + memset(signature_page, 0, pagesize); + p = (struct swap_header_v1 *) signature_page; +} + +static inline void write_signature(char *sig) +{ + char *sp = (char *) signature_page; + + strncpy(sp + pagesize - 10, sig, 10); +} + +#define V0_MAX_PAGES (8 * (pagesize - 10)) +/* Before 2.2.0pre9 */ +#define V1_OLD_MAX_PAGES ((0x7fffffff / pagesize) - 1) +/* Since 2.2.0pre9: + error if nr of pages >= SWP_OFFSET(SWP_ENTRY(0,~0UL)) + with variations on + #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8)) + #define SWP_OFFSET(entry) ((entry) >> 8) + on the various architectures. Below the result - yuk. + + Machine pagesize SWP_ENTRY SWP_OFFSET bound+1 oldbound+2 + i386 2^12 o<<8 e>>8 1<<24 1<<19 + mips 2^12 o<<15 e>>15 1<<17 1<<19 + alpha 2^13 o<<40 e>>40 1<<24 1<<18 + m68k 2^12 o<<12 e>>12 1<<20 1<<19 + sparc 2^{12,13} (o&0x3ffff)<<9 (e>>9)&0x3ffff 1<<18 1<<{19,18} + sparc64 2^13 o<<13 e>>13 1<<51 1<<18 + ppc 2^12 o<<8 e>>8 1<<24 1<<19 + armo 2^{13,14,15} o<<8 e>>8 1<<24 1<<{18,17,16} + armv 2^12 o<<9 e>>9 1<<23 1<<19 + + assuming that longs have 64 bits on alpha and sparc64 and 32 bits elsewhere. + + The bad part is that we need to know this since the kernel will + refuse a swap space if it is too large. +*/ +/* patch from jj - why does this differ from the above? */ +#if defined(__alpha__) +#define V1_MAX_PAGES ((1 << 24) - 1) +#elif defined(__mips__) +#define V1_MAX_PAGES ((1 << 17) - 1) +#elif defined(__sparc_v9__) +#define V1_MAX_PAGES ((3 << 29) - 1) +#elif defined(__sparc__) +#define V1_MAX_PAGES (pagesize == 8192 ? ((3 << 29) - 1) : ((1 << 18) - 1)) +#else +#define V1_MAX_PAGES V1_OLD_MAX_PAGES +#endif +/* man page now says: +The maximum useful size of a swap area now depends on the architecture. +It is roughly 2GB on i386, PPC, m68k, ARM, 1GB on sparc, 512MB on mips, +128GB on alpha and 3TB on sparc64. +*/ + +#define MAX_BADPAGES ((pagesize-1024-128*sizeof(int)-10)/sizeof(int)) + +static inline void bit_set(unsigned int *addr, unsigned int nr) +{ + unsigned int r, m; + + addr += nr / (8 * sizeof(int)); + + r = *addr; + m = 1 << (nr & (8 * sizeof(int) - 1)); + + *addr = r | m; +} + +static int bit_test_and_clear(unsigned int *addr, unsigned int nr) +{ + unsigned int r, m; + + addr += nr / (8 * sizeof(int)); + + r = *addr; + m = 1 << (nr & (8 * sizeof(int) - 1)); + + *addr = r & ~m; + return (r & m) != 0; +} + + +static void page_ok(int page) +{ + if (version == 0) + bit_set(signature_page, page); +} + +static inline void page_bad(int page) +{ + if (version == 0) + bit_test_and_clear(signature_page, page); + else { + if (badpages == MAX_BADPAGES) + error_msg_and_die("too many bad pages"); + p->badpages[badpages] = page; + } + badpages++; +} + +static void check_blocks(void) +{ + unsigned int current_page; + int do_seek = 1; + char *buffer; + + buffer = xmalloc(pagesize); + current_page = 0; + while (current_page < PAGES) { + if (!check) { + page_ok(current_page++); + continue; + } + if (do_seek && lseek(DEV, current_page * pagesize, SEEK_SET) != + current_page * pagesize) + error_msg_and_die("seek failed in check_blocks"); + if ((do_seek = (pagesize != read(DEV, buffer, pagesize)))) { + page_bad(current_page++); + continue; + } + page_ok(current_page++); + } + if (badpages == 1) + printf("one bad page\n"); + else if (badpages > 1) + printf("%d bad pages\n", badpages); +} + +static long valid_offset(int fd, int offset) +{ + char ch; + + if (lseek(fd, offset, 0) < 0) + return 0; + if (read(fd, &ch, 1) < 1) + return 0; + return 1; +} + +static int find_size(int fd) +{ + unsigned int high, low; + + low = 0; + for (high = 1; high > 0 && valid_offset(fd, high); high *= 2) + low = high; + while (low < high - 1) { + const int mid = (low + high) / 2; + + if (valid_offset(fd, mid)) + low = mid; + else + high = mid; + } + return (low + 1); +} + +/* return size in pages, to avoid integer overflow */ +static long get_size(const char *file) +{ + int fd; + long size; + + if ((fd = open(file, O_RDONLY)) < 0) + perror_msg_and_die("%s", file); + if (ioctl(fd, BLKGETSIZE, &size) >= 0) { + int sectors_per_page = pagesize / 512; + + size /= sectors_per_page; + } else { + size = find_size(fd) / pagesize; + } + close(fd); + return size; +} + +int mkswap_main(int argc, char **argv) +{ + char *tmp; + struct stat statbuf; + int sz; + int maxpages; + int goodpages; + int offset; + int force = 0; + + init_signature_page(); /* get pagesize */ + + while (argc-- > 1) { + argv++; + if (argv[0][0] != '-') { + if (device_name) { + int blocks_per_page = pagesize / 1024; + + PAGES = strtol(argv[0], &tmp, 0) / blocks_per_page; + if (*tmp) + show_usage(); + } else + device_name = argv[0]; + } else { + switch (argv[0][1]) { + case 'c': + check = 1; + break; + case 'f': + force = 1; + break; + case 'v': + version = atoi(argv[0] + 2); + break; + default: + show_usage(); + } + } + } + if (!device_name) { + error_msg("error: Nowhere to set up swap on?"); + show_usage(); + } + sz = get_size(device_name); + if (!PAGES) { + PAGES = sz; + } else if (PAGES > sz && !force) { + error_msg("error: size %ld is larger than device size %d", + PAGES * (pagesize / 1024), sz * (pagesize / 1024)); + return EXIT_FAILURE; + } + + if (version == -1) { + if (PAGES <= V0_MAX_PAGES) + version = 0; + else if (get_kernel_revision() < MAKE_VERSION(2, 1, 117)) + version = 0; + else if (pagesize < 2048) + version = 0; + else + version = 1; + } + if (version != 0 && version != 1) { + error_msg("error: unknown version %d", version); + show_usage(); + } + if (PAGES < 10) { + error_msg("error: swap area needs to be at least %ldkB", + (long) (10 * pagesize / 1024)); + show_usage(); + } +#if 0 + maxpages = ((version == 0) ? V0_MAX_PAGES : V1_MAX_PAGES); +#else + if (!version) + maxpages = V0_MAX_PAGES; + else if (get_kernel_revision() >= MAKE_VERSION(2, 2, 1)) + maxpages = V1_MAX_PAGES; + else { + maxpages = V1_OLD_MAX_PAGES; + if (maxpages > V1_MAX_PAGES) + maxpages = V1_MAX_PAGES; + } +#endif + if (PAGES > maxpages) { + PAGES = maxpages; + error_msg("warning: truncating swap area to %ldkB", + PAGES * pagesize / 1024); + } + + DEV = open(device_name, O_RDWR); + if (DEV < 0 || fstat(DEV, &statbuf) < 0) + perror_msg_and_die("%s", device_name); + if (!S_ISBLK(statbuf.st_mode)) + check = 0; + else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340) + error_msg_and_die("Will not try to make swapdevice on '%s'", device_name); + +#ifdef __sparc__ + if (!force && version == 0) { + /* Don't overwrite partition table unless forced */ + unsigned char *buffer = (unsigned char *) signature_page; + unsigned short *q, sum; + + if (read(DEV, buffer, 512) != 512) + error_msg_and_die("fatal: first page unreadable"); + if (buffer[508] == 0xDA && buffer[509] == 0xBE) { + q = (unsigned short *) (buffer + 510); + for (sum = 0; q >= (unsigned short *) buffer;) + sum ^= *q--; + if (!sum) { + error_msg("Device '%s' contains a valid Sun disklabel.\n" +"This probably means creating v0 swap would destroy your partition table\n" +"No swap created. If you really want to create swap v0 on that device, use\n" +"the -f option to force it.", device_name); + return EXIT_FAILURE; + } + } + } +#endif + + if (version == 0 || check) + check_blocks(); + if (version == 0 && !bit_test_and_clear(signature_page, 0)) + error_msg_and_die("fatal: first page unreadable"); + if (version == 1) { + p->version = version; + p->last_page = PAGES - 1; + p->nr_badpages = badpages; + } + + goodpages = PAGES - badpages - 1; + if (goodpages <= 0) + error_msg_and_die("Unable to set up swap-space: unreadable"); + printf("Setting up swapspace version %d, size = %ld bytes\n", + version, (long) (goodpages * pagesize)); + write_signature((version == 0) ? "SWAP-SPACE" : "SWAPSPACE2"); + + offset = ((version == 0) ? 0 : 1024); + if (lseek(DEV, offset, SEEK_SET) != offset) + error_msg_and_die("unable to rewind swap-device"); + if (write(DEV, (char *) signature_page + offset, pagesize - offset) + != pagesize - offset) + error_msg_and_die("unable to write signature page"); + + /* + * A subsequent swapon() will fail if the signature + * is not actually on disk. (This is a kernel bug.) + */ + if (fsync(DEV)) + error_msg_and_die("fsync failed"); + return EXIT_SUCCESS; +} diff --git a/mktemp.c b/mktemp.c new file mode 100644 index 000000000..bc47d0af0 --- /dev/null +++ b/mktemp.c @@ -0,0 +1,40 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini mktemp implementation for busybox + * + * + * Copyright (C) 2000 by Daniel Jacobowitz + * Written by Daniel Jacobowitz + * + * 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 "busybox.h" + +extern int mktemp_main(int argc, char **argv) +{ + if (argc != 2 && (argc != 3 || strcmp(argv[1], "-q"))) + show_usage(); + if(mkstemp(argv[argc-1]) < 0) + return EXIT_FAILURE; + (void) puts(argv[argc-1]); + return EXIT_SUCCESS; +} diff --git a/modprobe.c b/modprobe.c new file mode 100644 index 000000000..3cca57dee --- /dev/null +++ b/modprobe.c @@ -0,0 +1,366 @@ +/* vi: set sw=4 ts=4: */ +/* + * really dumb modprobe implementation for busybox + * Copyright (C) 2001 Lineo, davidm@lineo.com + * + * BB_FEATURE_MODPROBE_DEPEND stuff was added and is + * Copyright (C) 2002 Robert Griebl, griebl@gmx.de + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +#define BB_FEATURE_MODPROBE_DEPEND + +#ifdef BB_FEATURE_MODPROBE_DEPEND + +#include + +/* Jump through hoops to simulate how fgets() grabs just one line at a time... + * Don't use any stdio since modprobe gets called from a kernel thread and + * stdio junk can overflow the limited stack... */ +static char *reads ( int fd, char *buffer, size_t len ) +{ + ssize_t n = read ( fd, buffer, len ); + if ( n > 0 ) { + char *p; + buffer [len-1] = 0; + p = strchr ( buffer, '\n' ); + if ( p ) { + off_t offset; + offset = lseek ( fd, 0L, SEEK_CUR ); + /* Get the current file descriptor offset */ + lseek ( fd, offset-n + (p-buffer) + 1, SEEK_SET ); + /* Set the file descriptor offset to right after the \n */ + p[1] = 0; + } + return buffer; + } else { + return 0; + } +} + +struct dep_t { + char * m_module; + int m_depcnt; + char ** m_deparr; + + struct dep_t * m_next; +}; + + +static struct dep_t *build_dep ( void ) +{ + int fd; + struct utsname un; + struct dep_t *first = 0; + struct dep_t *current = 0; + char buffer [256]; + char *filename = buffer; + int continuation_line = 0; + + if ( uname ( &un )) + return 0; + strcpy ( filename, "/lib/modules/" ); + strcat ( filename, un.release ); + strcat ( filename, "/modules.dep" ); + + if ((fd = open ( filename, O_RDONLY )) < 0) + return 0; + + while ( reads ( fd, buffer, sizeof( buffer ))) { + char *p; + int l = xstrlen ( buffer ); + + if ( buffer [l-1] == '\n' ) { + buffer [l-1] = 0; + l--; + } + + if ( l == 0 ) { + continuation_line = 0; + continue; + } + + if ( !continuation_line ) { + char *col = strchr ( buffer, ':' ); + + if ( col ) { + char *mods; + char *mod; + int ext = 0; + + *col = 0; + mods = strrchr ( buffer, '/' ); + + if ( !mods ) + mods = buffer; + else + mods++; + + if (( *(col-2) == '.' ) && ( *(col-1) == 'o' )) + ext = 2; + + mod = xstrndup ( mods, col - mods - ext ); + + if ( !current ) { + first = current = (struct dep_t *) malloc ( sizeof ( struct dep_t )); + } + else { + current->m_next = (struct dep_t *) malloc ( sizeof ( struct dep_t )); + current = current->m_next; + } + current->m_module = mod; + current->m_depcnt = 0; + current->m_deparr = 0; + current->m_next = 0; + + //printf ( "%s:\n", mod ); + + p = col + 1; + } + else + p = 0; + } + else + p = buffer; + + if ( p && *p ) { + char *end = &buffer [l-1]; + char *deps = strrchr ( end, '/' ); + char *dep; + int ext = 0; + + while ( isblank ( *end ) || ( *end == '\\' )) + end--; + + deps = strrchr ( p, '/' ); + + if ( !deps || ( deps < p )) { + deps = p; + + while ( isblank ( *deps )) + deps++; + } + else + deps++; + + if (( *(end-1) == '.' ) && ( *end == 'o' )) + ext = 2; + + /* Cope with blank lines */ + if ((end-deps-ext+1) <= 0) + continue; + + dep = xstrndup ( deps, end - deps - ext + 1 ); + + current->m_depcnt++; + current->m_deparr = (char **) xrealloc ( current->m_deparr, sizeof ( char *) * current->m_depcnt ); + current->m_deparr [current->m_depcnt - 1] = dep; + + //printf ( " %d) %s\n", current->m_depcnt, current->m_deparr [current->m_depcnt -1] ); + } + + if ( buffer [l-1] == '\\' ) + continuation_line = 1; + else + continuation_line = 0; + } + close ( fd ); + + return first; +} + + +static struct dep_t *find_dep ( struct dep_t *dt, char *mod ) +{ + int lm = xstrlen ( mod ); + int extpos = 0; + + if (( mod [lm-2] == '.' ) && ( mod [lm-1] == 'o' )) + extpos = 2; + + if ( extpos > 0 ) + mod [lm - extpos] = 0; + + while ( dt ) { + if ( !strcmp ( dt->m_module, mod )) + break; + + dt = dt->m_next; + } + if ( extpos > 0 ) + mod [lm - extpos] = '.'; + + return dt; +} + +#define MODPROBE_EXECUTE 0x1 +#define MODPROBE_INSERT 0x2 +#define MODPROBE_REMOVE 0x4 + +static void check_dep ( char *mod, int do_syslog, + int show_only, int verbose, int flags ) +{ + static struct dep_t *depend = (struct dep_t *) -1; + struct dep_t *dt; + + if ( depend == (struct dep_t *) -1 ) + depend = build_dep ( ); + + if (( dt = find_dep ( depend, mod ))) { + int i; + + for ( i = 0; i < dt->m_depcnt; i++ ) + check_dep ( dt->m_deparr [i], do_syslog, + show_only, verbose, flags|MODPROBE_EXECUTE); + } + if ( flags & MODPROBE_EXECUTE ) { + char lcmd [256]; + if ( flags & MODPROBE_INSERT ) { + snprintf(lcmd, sizeof(lcmd)-1, "insmod %s -q -k %s 2>/dev/null", + do_syslog ? "-s" : "", mod ); + } + if ( flags & MODPROBE_REMOVE ) { + snprintf(lcmd, sizeof(lcmd)-1, "insmod %s -q -k %s 2>/dev/null", + do_syslog ? "-s" : "", mod ); + } + if ( flags & (MODPROBE_REMOVE|MODPROBE_INSERT) ) { + if (verbose) + printf("%s\n", lcmd); + if (!show_only) + system ( lcmd ); + } + } +} + +#endif + + +extern int modprobe_main(int argc, char** argv) +{ + int ch, rc = 0; + int loadall = 0, showconfig = 0, debug = 0, autoclean = 0, list = 0; + int show_only = 0, quiet = 0, remove_opt = 0, do_syslog = 0, verbose = 0; + char *load_type = NULL, *config = NULL; + char cmd[256]; + + while ((ch = getopt(argc, argv, "acdklnqrst:vVC:")) != -1) + switch(ch) { + case 'a': + loadall++; + break; + case 'c': + showconfig++; + break; + case 'd': + debug++; + break; + case 'k': + autoclean++; + break; + case 'l': + list++; + break; + case 'n': + show_only++; + break; + case 'q': + quiet++; + break; + case 'r': + remove_opt++; + break; + case 's': + do_syslog++; + break; + case 't': + load_type = optarg; + break; + case 'v': + verbose++; + break; + case 'C': + config = optarg; + break; + case 'V': + default: + show_usage(); + break; + } + + if (load_type || config) { + fprintf(stderr, "-t and -C not supported\n"); + exit(EXIT_FAILURE); + } + + if (showconfig) + exit(EXIT_SUCCESS); + + if (list) + exit(EXIT_SUCCESS); + + if (remove_opt) { + do { + snprintf(cmd, sizeof(cmd)-1, "rmmod %s %s %s", + optind >= argc ? "-a" : "", + do_syslog ? "-s" : "", + optind < argc ? argv[optind] : ""); + if (do_syslog) + syslog(LOG_INFO, "%s", cmd); + if (verbose) + printf("%s\n", cmd); + if (!show_only) + rc = system(cmd); + +#ifdef BB_FEATURE_MODPROBE_DEPEND + if ( optind < argc ) + check_dep ( argv [optind], do_syslog, show_only, verbose, MODPROBE_REMOVE); +#endif + } while (++optind < argc); + exit(EXIT_SUCCESS); + } + + if (optind >= argc) { + fprintf(stderr, "No module or pattern provided\n"); + exit(EXIT_FAILURE); + } + + snprintf(cmd, sizeof(cmd)-1, "insmod %s %s %s", + do_syslog ? "-s" : "", + quiet ? "-q" : "", + autoclean ? "-k" : ""); + +#ifdef BB_FEATURE_MODPROBE_DEPEND + check_dep ( argv [optind], do_syslog, show_only, verbose, MODPROBE_INSERT); +#endif + + while (optind < argc) { + if (strlen(cmd) + 1 + strlen(argv[optind]) >= sizeof(cmd)) + { + error_msg_and_die("Too many module parameters!\n"); + } + strcat(cmd, " "); + strcat(cmd, argv[optind]); + optind++; + } + if (do_syslog) + syslog(LOG_INFO, "%s", cmd); + if (verbose) + printf("%s\n", cmd); + if (!show_only) + rc = system(cmd); + else + rc = 0; + + exit(rc ? EXIT_FAILURE : EXIT_SUCCESS); +} + + diff --git a/more.c b/more.c new file mode 100644 index 000000000..f4958802b --- /dev/null +++ b/more.c @@ -0,0 +1,214 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini more implementation for busybox + * + * Copyright (C) 1995, 1996 by Bruce Perens . + * + * Latest version blended by Erik Andersen , based + * on the original more implementation by Bruce, code from the Debian + * boot-floppies team, and my own bits of stuff. + * + * Termios corrects by Vladimir Oleynik + * + * 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 "busybox.h" + +static FILE *cin; + +#ifdef BB_FEATURE_USE_TERMIOS +#include +#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp) +#define getTermSettings(fd,argp) tcgetattr(fd, argp); + +static struct termios initial_settings, new_settings; + +static void set_tty_to_initial_mode(void) +{ + setTermSettings(fileno(cin), &initial_settings); +} + +static void gotsig(int sig) +{ + putchar('\n'); + exit(EXIT_FAILURE); +} +#endif /* BB_FEATURE_USE_TERMIOS */ + + +static int terminal_width = 79; /* not 80 in case terminal has linefold bug */ +static int terminal_height = 24; + + +extern int more_main(int argc, char **argv) +{ + int c, lines, input = 0; + int please_display_more_prompt = -1; + struct stat st; + FILE *file; + int len, page_height; + +#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS + struct winsize win = { 0, 0, 0, 0 }; +#endif + + argc--; + argv++; + + + /* not use inputing from terminal if usage: more > outfile */ + if(isatty(fileno(stdout))) { + cin = fopen(CURRENT_TTY, "r"); + if (!cin) + cin = xfopen(CONSOLE_DEV, "r"); + please_display_more_prompt = 0; +#ifdef BB_FEATURE_USE_TERMIOS + getTermSettings(fileno(cin), &initial_settings); + new_settings = initial_settings; + new_settings.c_lflag &= ~ICANON; + new_settings.c_lflag &= ~ECHO; + new_settings.c_cc[VMIN] = 1; + new_settings.c_cc[VTIME] = 0; + setTermSettings(fileno(cin), &new_settings); + atexit(set_tty_to_initial_mode); + (void) signal(SIGINT, gotsig); + (void) signal(SIGQUIT, gotsig); + (void) signal(SIGTERM, gotsig); +#endif + } + + do { + if (argc == 0) { + file = stdin; + } else + file = wfopen(*argv, "r"); + if(file==0) + goto loop; + + st.st_size = 0; + fstat(fileno(file), &st); + + if(please_display_more_prompt>0) + please_display_more_prompt = 0; + +#if defined BB_FEATURE_AUTOWIDTH && defined BB_FEATURE_USE_TERMIOS + ioctl(fileno(stdout), TIOCGWINSZ, &win); + if (win.ws_row > 4) + terminal_height = win.ws_row - 2; + if (win.ws_col > 0) + terminal_width = win.ws_col - 1; +#endif + len=0; + lines = 0; + page_height = terminal_height; + while ((c = getc(file)) != EOF) { + + if (please_display_more_prompt>0) { + len = printf("--More-- "); + if (file != stdin && st.st_size > 0) { +#if _FILE_OFFSET_BITS == 64 + len += printf("(%d%% of %lld bytes)", + (int) (100 * ((double) ftell(file) / + (double) st.st_size)), (long long)st.st_size); +#else + len += printf("(%d%% of %ld bytes)", + (int) (100 * ((double) ftell(file) / + (double) st.st_size)), (long)st.st_size); +#endif + } + + fflush(stdout); + + /* + * We've just displayed the "--More--" prompt, so now we need + * to get input from the user. + */ + input = getc(cin); +#ifndef BB_FEATURE_USE_TERMIOS + printf("\033[A"); /* up cursor */ +#endif + /* Erase the "More" message */ + putc('\r', stdout); + while (--len >= 0) + putc(' ', stdout); + putc('\r', stdout); + fflush(stdout); + len=0; + lines = 0; + page_height = terminal_height; + please_display_more_prompt = 0; + + if (input == 'q') + goto end; + } + + /* + * There are two input streams to worry about here: + * + * c : the character we are reading from the file being "mored" + * input : a character received from the keyboard + * + * If we hit a newline in the _file_ stream, we want to test and + * see if any characters have been hit in the _input_ stream. This + * allows the user to quit while in the middle of a file. + */ + if (c == '\n') { + /* increment by just one line if we are at + * the end of this line */ + if (input == '\n') + if(please_display_more_prompt==0) + please_display_more_prompt = 1; + /* Adjust the terminal height for any overlap, so that + * no lines get lost off the top. */ + if (len >= terminal_width) { + int quot, rem; + quot = len / terminal_width; + rem = len - (quot * terminal_width); + if (quot) { + if (rem) + page_height-=quot; + else + page_height-=(quot-1); + } + } + if (++lines >= page_height) { + if(please_display_more_prompt==0) + please_display_more_prompt = 1; + } + len=0; + } + /* + * If we just read a newline from the file being 'mored' and any + * key other than a return is hit, scroll by one page + */ + putc(c, stdout); + len++; + } + fclose(file); + fflush(stdout); +loop: + argv++; + } while (--argc > 0); + end: + return 0; +} diff --git a/mount.c b/mount.c new file mode 100644 index 000000000..aa77f9818 --- /dev/null +++ b/mount.c @@ -0,0 +1,505 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini mount implementation for busybox + * + * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 1999-2002 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 + * + * 3/21/1999 Charles P. Wright + * searches through fstab when -a is passed + * will try mounting stuff with all fses when passed -t auto + * + * 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab. + * + * 1999-10-07 Erik Andersen . + * Rewrite of a lot of code. Removed mtab usage (I plan on + * putting it back as a compile-time option some time), + * major adjustments to option parsing, and some serious + * dieting all around. + * + * 1999-11-06 mtab suppport is back - andersee + * + * 2000-01-12 Ben Collins , Borrowed utils-linux's + * mount to add loop support. + * + * 2000-04-30 Dave Cinege + * Rewrote fstab while loop and lower mount section. Can now do + * single mounts from fstab. Can override fstab options for single + * mount. Common mount_one call for single mounts and 'all'. Fixed + * mtab updating and stale entries. Removed 'remount' default. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" +#if defined BB_FEATURE_USE_DEVPS_PATCH +# include /* For Erik's nifty devmtab device driver */ +#endif + +enum { + MS_MGC_VAL = 0xc0ed0000, /* Magic number indicatng "new" flags */ + MS_RDONLY = 1, /* Mount read-only */ + MS_NOSUID = 2, /* Ignore suid and sgid bits */ + MS_NODEV = 4, /* Disallow access to device special files */ + MS_NOEXEC = 8, /* Disallow program execution */ + MS_SYNCHRONOUS = 16, /* Writes are synced at once */ + MS_REMOUNT = 32, /* Alter flags of a mounted FS */ + MS_MANDLOCK = 64, /* Allow mandatory locks on an FS */ + S_QUOTA = 128, /* Quota initialized for file/directory/symlink */ + S_APPEND = 256, /* Append-only file */ + S_IMMUTABLE = 512, /* Immutable file */ + MS_NOATIME = 1024, /* Do not update access times. */ + MS_NODIRATIME = 2048, /* Do not update directory access times */ + MS_BIND = 4096, /* Use the new linux 2.4.x "mount --bind" feature */ +}; + + +#if defined BB_FEATURE_MOUNT_LOOP +#include +#include +static int use_loop = FALSE; +#endif + +extern int mount (__const char *__special_file, __const char *__dir, + __const char *__fstype, unsigned long int __rwflag, + __const void *__data); +extern int umount (__const char *__special_file); +extern int umount2 (__const char *__special_file, int __flags); + +extern int sysfs( int option, unsigned int fs_index, char * buf); + +extern const char mtab_file[]; /* Defined in utility.c */ + +struct mount_options { + const char *name; + unsigned long and; + unsigned long or; +}; + +static const struct mount_options mount_options[] = { + {"async", ~MS_SYNCHRONOUS, 0}, + {"atime", ~0, ~MS_NOATIME}, + {"defaults", ~0, 0}, + {"noauto", ~0, 0}, + {"dev", ~MS_NODEV, 0}, + {"diratime", ~0, ~MS_NODIRATIME}, + {"exec", ~MS_NOEXEC, 0}, + {"noatime", ~0, MS_NOATIME}, + {"nodev", ~0, MS_NODEV}, + {"nodiratime", ~0, MS_NODIRATIME}, + {"noexec", ~0, MS_NOEXEC}, + {"nosuid", ~0, MS_NOSUID}, + {"remount", ~0, MS_REMOUNT}, + {"ro", ~0, MS_RDONLY}, + {"rw", ~MS_RDONLY, 0}, + {"suid", ~MS_NOSUID, 0}, + {"sync", ~0, MS_SYNCHRONOUS}, + {"bind", ~0, MS_BIND}, + {0, 0, 0} +}; + +static int +do_mount(char *specialfile, char *dir, char *filesystemtype, + long flags, void *string_flags, int useMtab, int fakeIt, + char *mtab_opts, int mount_all) +{ + int status = 0; +#if defined BB_FEATURE_MOUNT_LOOP + char *lofile = NULL; +#endif + + if (! fakeIt) + { +#if defined BB_FEATURE_MOUNT_LOOP + if (use_loop==TRUE) { + int loro = flags & MS_RDONLY; + + lofile = specialfile; + + specialfile = find_unused_loop_device(); + if (specialfile == NULL) { + error_msg_and_die("Could not find a spare loop device"); + } + if (set_loop(specialfile, lofile, 0, &loro)) { + error_msg_and_die("Could not setup loop device"); + } + if (!(flags & MS_RDONLY) && loro) { /* loop is ro, but wanted rw */ + error_msg("WARNING: loop device is read-only"); + flags |= MS_RDONLY; + } + } +#endif + status = mount(specialfile, dir, filesystemtype, flags, string_flags); + if (status < 0 && errno == EROFS) { + error_msg("%s is write-protected, mounting read-only", specialfile); + status = mount(specialfile, dir, filesystemtype, flags |= MS_RDONLY, string_flags); + } + /* Don't whine about already mounted filesystems when mounting all. */ + if (status < 0 && errno == EBUSY && mount_all) + return TRUE; + } + + + /* If the mount was sucessful, do anything needed, then return TRUE */ + if (status == 0 || fakeIt==TRUE) { + +#if defined BB_FEATURE_MTAB_SUPPORT + if (useMtab) { + erase_mtab(specialfile); // Clean any stale entries + write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts); + } +#endif + return (TRUE); + } + + /* Bummer. mount failed. Clean up */ +#if defined BB_FEATURE_MOUNT_LOOP + if (lofile != NULL) { + del_loop(specialfile); + } +#endif + + if (errno == EPERM) { + error_msg_and_die("permission denied. Are you root?"); + } + + return (FALSE); +} + + +static void paste_str(char **s1, const char *s2) +{ + *s1 = xrealloc(*s1, strlen(*s1)+strlen(s2)+1); + strcat(*s1, s2); +} + +/* Seperate standard mount options from the nonstandard string options */ +static void +parse_mount_options(char *options, int *flags, char **strflags) +{ + while (options) { + int gotone = FALSE; + char *comma = strchr(options, ','); + const struct mount_options *f = mount_options; + + if (comma) + *comma = '\0'; + + while (f->name != 0) { + if (strcasecmp(f->name, options) == 0) { + + *flags &= f->and; + *flags |= f->or; + gotone = TRUE; + break; + } + f++; + } +#if defined BB_FEATURE_MOUNT_LOOP + if (!strcasecmp("loop", options)) { /* loop device support */ + use_loop = TRUE; + gotone = TRUE; + } +#endif + if (! gotone) { + if (**strflags) /* have previous parsed options */ + paste_str(strflags, ","); + paste_str(strflags, options); + } + if (comma) { + *comma = ','; + options = ++comma; + } else { + break; + } + } +} + +static int +mount_one(char *blockDevice, char *directory, char *filesystemType, + unsigned long flags, char *string_flags, int useMtab, int fakeIt, + char *mtab_opts, int whineOnErrors, int mount_all) +{ + int status = 0; + +#if defined BB_FEATURE_USE_DEVPS_PATCH + if (strcmp(filesystemType, "auto") == 0) { + static const char *noauto_array[] = { "tmpfs", "shm", "proc", "ramfs", "devpts", "devfs", "usbdevfs", 0 }; + const char **noauto_fstype; + const int num_of_filesystems = sysfs(3, 0, 0); + char buf[255]; + int i=0; + + filesystemType=buf; + + while(i < num_of_filesystems) { + sysfs(2, i++, filesystemType); + for (noauto_fstype = noauto_array; *noauto_fstype; noauto_fstype++) { + if (!strcmp(filesystemType, *noauto_fstype)) { + break; + } + } + if (!*noauto_fstype) { + status = do_mount(blockDevice, directory, filesystemType, + flags | MS_MGC_VAL, string_flags, + useMtab, fakeIt, mtab_opts, mount_all); + if (status) + break; + } + } + } +#else + if (strcmp(filesystemType, "auto") == 0) { + char buf[255]; + FILE *f = xfopen("/proc/filesystems", "r"); + + while (fgets(buf, sizeof(buf), f) != NULL) { + filesystemType = buf; + if (*filesystemType == '\t') { // Not a nodev filesystem + + // Add NULL termination to each line + while (*filesystemType && *filesystemType != '\n') + filesystemType++; + *filesystemType = '\0'; + + filesystemType = buf; + filesystemType++; // hop past tab + + status = do_mount(blockDevice, directory, filesystemType, + flags | MS_MGC_VAL, string_flags, + useMtab, fakeIt, mtab_opts, mount_all); + if (status) + break; + } + } + fclose(f); + } +#endif + else { + status = do_mount(blockDevice, directory, filesystemType, + flags | MS_MGC_VAL, string_flags, useMtab, + fakeIt, mtab_opts, mount_all); + } + + if (! status) { + if (whineOnErrors) { + perror_msg("Mounting %s on %s failed", blockDevice, directory); + } + return (FALSE); + } + return (TRUE); +} + +static void show_mounts(char *onlytype) +{ +#if defined BB_FEATURE_USE_DEVPS_PATCH + int fd, i, numfilesystems; + char device[] = "/dev/mtab"; + struct k_mntent *mntentlist; + + /* open device */ + fd = open(device, O_RDONLY); + if (fd < 0) + perror_msg_and_die("open failed for `%s'", device); + + /* How many mounted filesystems? We need to know to + * allocate enough space for later... */ + numfilesystems = ioctl (fd, DEVMTAB_COUNT_MOUNTS); + if (numfilesystems<0) + perror_msg_and_die( "\nDEVMTAB_COUNT_MOUNTS"); + mntentlist = (struct k_mntent *) xcalloc ( numfilesystems, sizeof(struct k_mntent)); + + /* Grab the list of mounted filesystems */ + if (ioctl (fd, DEVMTAB_GET_MOUNTS, mntentlist)<0) + perror_msg_and_die( "\nDEVMTAB_GET_MOUNTS"); + + for( i = 0 ; i < numfilesystems ; i++) { + if ( !onlytype || ( strcmp ( mntentlist[i].mnt_type, onlytype ) == 0 )) { + printf( "%s %s %s %s %d %d\n", mntentlist[i].mnt_fsname, + mntentlist[i].mnt_dir, mntentlist[i].mnt_type, + mntentlist[i].mnt_opts, mntentlist[i].mnt_freq, + mntentlist[i].mnt_passno); + } + } +#ifdef BB_FEATURE_CLEAN_UP + /* Don't bother to close files or free memory. Exit + * does that automagically, so we can save a few bytes */ + free( mntentlist); + close(fd); +#endif + exit(EXIT_SUCCESS); +#else + FILE *mountTable = setmntent(mtab_file, "r"); + + if (mountTable) { + struct mntent *m; + + while ((m = getmntent(mountTable)) != 0) { + char *blockDevice = m->mnt_fsname; + if (strcmp(blockDevice, "/dev/root") == 0) { + blockDevice = find_real_root_device_name(blockDevice); + } + if ( !onlytype || ( strcmp ( m-> mnt_type, onlytype ) == 0 )) { + printf("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir, + m->mnt_type, m->mnt_opts); + } +#ifdef BB_FEATURE_CLEAN_UP + if(blockDevice != m->mnt_fsname) + free(blockDevice); +#endif + } + endmntent(mountTable); + } else { + perror_msg_and_die("%s", mtab_file); + } + exit(EXIT_SUCCESS); +#endif +} + +extern int mount_main(int argc, char **argv) +{ + struct stat statbuf; + char *string_flags = xstrdup(""); + char *extra_opts; + int flags = 0; + char *filesystemType = "auto"; + int got_filesystemType = 0; + char *device = xmalloc(PATH_MAX); + char *directory = xmalloc(PATH_MAX); + struct mntent *m = NULL; + int all = FALSE; + int fakeIt = FALSE; + int useMtab = TRUE; + int rc = EXIT_FAILURE; + FILE *f = 0; + int opt; + + /* Parse options */ + while ((opt = getopt(argc, argv, "o:rt:wafnv")) > 0) { + switch (opt) { + case 'o': + parse_mount_options(optarg, &flags, &string_flags); + break; + case 'r': + flags |= MS_RDONLY; + break; + case 't': + filesystemType = optarg; + got_filesystemType = 1; + break; + case 'w': + flags &= ~MS_RDONLY; + break; + case 'a': + all = TRUE; + break; + case 'f': + fakeIt = TRUE; + break; +#ifdef BB_FEATURE_MTAB_SUPPORT + case 'n': + useMtab = FALSE; + break; +#endif + case 'v': + break; /* ignore -v */ + } + } + + if (!all && optind == argc) + show_mounts(got_filesystemType ? filesystemType : 0); + + if (optind < argc) { + /* if device is a filename get its real path */ + if (stat(argv[optind], &statbuf) == 0) { + char *tmp = simplify_path(argv[optind]); + safe_strncpy(device, tmp, PATH_MAX); + } else { + safe_strncpy(device, argv[optind], PATH_MAX); + } + } + + if (optind + 1 < argc) + directory = simplify_path(argv[optind + 1]); + + if (all || optind + 1 == argc) { + f = setmntent("/etc/fstab", "r"); + + if (f == NULL) + perror_msg_and_die( "\nCannot read /etc/fstab"); + + while ((m = getmntent(f)) != NULL) { + if (! all && optind + 1 == argc && ( + (strcmp(device, m->mnt_fsname) != 0) && + (strcmp(device, m->mnt_dir) != 0) ) ) { + continue; + } + + if (all && ( // If we're mounting 'all' + (strstr(m->mnt_opts, "noauto")) || // and the file system isn't noauto, + (strstr(m->mnt_type, "swap")) || // and isn't swap or nfs, then mount it + (strstr(m->mnt_type, "nfs")) ) ) { + continue; + } + + if (all || flags == 0) { // Allow single mount to override fstab flags + flags = 0; + string_flags[0] = 0; + parse_mount_options(m->mnt_opts, &flags, &string_flags); + } + + strcpy(device, m->mnt_fsname); + strcpy(directory, m->mnt_dir); + filesystemType = xstrdup(m->mnt_type); +singlemount: + extra_opts = string_flags; + rc = EXIT_SUCCESS; +#ifdef BB_NFSMOUNT + if (strchr(device, ':') != NULL) { + filesystemType = "nfs"; + if (nfsmount (device, directory, &flags, &extra_opts, + &string_flags, 1)) { + perror_msg("nfsmount failed"); + rc = EXIT_FAILURE; + } + } +#endif + if (!mount_one(device, directory, filesystemType, flags, + string_flags, useMtab, fakeIt, extra_opts, TRUE, all)) + rc = EXIT_FAILURE; + + if (! all) + break; + } + if (f) + endmntent(f); + + if (! all && f && m == NULL) + fprintf(stderr, "Can't find %s in /etc/fstab\n", device); + + return rc; + } + + goto singlemount; +} diff --git a/msh.c b/msh.c new file mode 100644 index 000000000..f3890d7c2 --- /dev/null +++ b/msh.c @@ -0,0 +1,4759 @@ +/* vi: set sw=4 ts=4: */ +/* + * Minix shell port for busybox + * + * This version of the Minix shell was adapted for use in busybox + * by Erik Andersen and + * Vladimir Oleynik + * + * 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 + * + * Original copyright notice is retained at the end of this file. + */ + +/* -------- sh.h -------- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "cmdedit.h" +#include "busybox.h" + +/* define this to use fork on MMU-systems instead of vfork */ +#if defined(__uClinux__) +#undef USE_FORK +#else +#define USE_FORK +#endif + +#ifdef test +//#undef BB_FEATURE_COMMAND_EDITING +const char *applet_name = "msh"; + +#define TEST_NEW_VERSION +#define Abort() { fprintf(stderr, "Abort %d\n", __LINE__); abort(); } +#else +#undef TEST_NEW_VERSION +#define Abort() abort() +#endif + +/* + * shell + */ + +#define LINELIM 4096 +#define NPUSH 8 /* limit to input nesting */ + +#ifndef NOFILE +#define NOFILE 20 /* Number of open files */ +#endif +#define NUFILE 10 /* Number of user-accessible files */ +#define FDBASE 10 /* First file usable by Shell */ + +/* + * values returned by wait + */ +#define WAITSIG(s) ((s)&0177) +#define WAITVAL(s) (((s)>>8)&0377) +#define WAITCORE(s) (((s)&0200)!=0) + +/* + * library and system defintions + */ +typedef void xint; /* base type of jmp_buf, for not broken compilers */ + +/* + * shell components + */ + +#define QUOTE 0200 + +#define NOBLOCK ((struct op *)NULL) +#define NOWORD ((char *)NULL) +#define NOWORDS ((char **)NULL) +#define NOPIPE ((int *)NULL) + +/* + * Description of a command or an operation on commands. + * Might eventually use a union. + */ +struct op { + int type; /* operation type, see below */ + char **words; /* arguments to a command */ + struct ioword **ioact; /* IO actions (eg, < > >>) */ + struct op *left; + struct op *right; + char *str; /* identifier for case and for */ +}; + +#define TCOM 1 /* command */ +#define TPAREN 2 /* (c-list) */ +#define TPIPE 3 /* a | b */ +#define TLIST 4 /* a [&;] b */ +#define TOR 5 /* || */ +#define TAND 6 /* && */ +#define TFOR 7 +#define TDO 8 +#define TCASE 9 +#define TIF 10 +#define TWHILE 11 +#define TUNTIL 12 +#define TELIF 13 +#define TPAT 14 /* pattern in case */ +#define TBRACE 15 /* {c-list} */ +#define TASYNC 16 /* c & */ + +/* + * actions determining the environment of a process + */ +#define BIT(i) (1<<(i)) +#define FEXEC BIT(0) /* execute without forking */ + +/* + * flags to control evaluation of words + */ +#define DOSUB 1 /* interpret $, `, and quotes */ +#define DOBLANK 2 /* perform blank interpretation */ +#define DOGLOB 4 /* interpret [?* */ +#define DOKEY 8 /* move words with `=' to 2nd arg. list */ +#define DOTRIM 16 /* trim resulting string */ + +#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM) + +static char **dolv; +static int dolc; +static int exstat; +static char gflg; +static int interactive; /* interactive (interactive-type wireless) */ +static int execflg; +static int multiline; /* \n changed to ; */ +static struct op *outtree; /* result from parser */ + +static xint *failpt; +static xint *errpt; + +struct brkcon { + jmp_buf brkpt; + struct brkcon *nextlev; +}; +static struct brkcon *brklist; +static int isbreak; + +/* + * redirection + */ +struct ioword { + short io_unit; /* unit affected */ + short io_flag; /* action (below) */ + char *io_name; /* file name */ +}; + +#define IOREAD 1 /* < */ +#define IOHERE 2 /* << (here file) */ +#define IOWRITE 4 /* > */ +#define IOCAT 8 /* >> */ +#define IOXHERE 16 /* ${}, ` in << */ +#define IODUP 32 /* >&digit */ +#define IOCLOSE 64 /* >&- */ + +#define IODEFAULT (-1) /* token for default IO unit */ + +struct wdblock { + short w_bsize; + short w_nword; + /* bounds are arbitrary */ + char *w_words[1]; +}; + +static struct wdblock *wdlist; +static struct wdblock *iolist; + +/* + * parsing & execution environment + */ +static struct env { + char *linep; + struct io *iobase; + struct io *iop; + xint *errpt; + int iofd; + struct env *oenv; +} e; + +/* + * flags: + * -e: quit on error + * -k: look for name=value everywhere on command line + * -n: no execution + * -t: exit after reading and executing one command + * -v: echo as read + * -x: trace + * -u: unset variables net diagnostic + */ +static char *flag; + +static char *null; /* null value for variable */ +static int intr; /* interrupt pending */ + +static char *trap[_NSIG + 1]; +static char ourtrap[_NSIG + 1]; +static int trapset; /* trap pending */ + +static int heedint; /* heed interrupt signals */ + +static int yynerrs; /* yacc */ + +static char line[LINELIM]; +static char *elinep; + +/* + * other functions + */ +static int (*inbuilt(char *s)) (void); + +static char *rexecve(char *c, char **v, char **envp); +static char *space(int n); +static char *strsave(char *s, int a); +static char *evalstr(char *cp, int f); +static char *putn(int n); +static char *itoa(unsigned u, int n); +static char *unquote(char *as); +static struct var *lookup(char *n); +static int rlookup(char *n); +static struct wdblock *glob(char *cp, struct wdblock *wb); +static int subgetc(int ec, int quoted); +static char **makenv(int all); +static char **eval(char **ap, int f); +static int setstatus(int s); +static int waitfor(int lastpid, int canintr); + +static void onintr(int s); /* SIGINT handler */ + +static int newenv(int f); +static void quitenv(void); +static void err(char *s); +static int anys(char *s1, char *s2); +static int any(int c, char *s); +static void next(int f); +static void setdash(void); +static void onecommand(void); +static void runtrap(int i); +static int letter(int c); +static int digit(int c); +static int letnum(int c); +static int gmatch(char *s, char *p); + +/* + * error handling + */ +static void leave(void) __attribute__ ((noreturn)); /* abort shell (or fail in subshell) */ +static void fail(void); /* fail but return to process next command */ +static void warn(char *s); +static void sig(int i); /* default signal handler */ + +/* -------- var.h -------- */ + +struct var { + char *value; + char *name; + struct var *next; + char status; +}; + +#define COPYV 1 /* flag to setval, suggesting copy */ +#define RONLY 01 /* variable is read-only */ +#define EXPORT 02 /* variable is to be exported */ +#define GETCELL 04 /* name & value space was got with getcell */ + +static struct var *vlist; /* dictionary */ + +static struct var *homedir; /* home directory */ +static struct var *prompt; /* main prompt */ +static struct var *cprompt; /* continuation prompt */ +static struct var *path; /* search path for commands */ +static struct var *shell; /* shell to interpret command files */ +static struct var *ifs; /* field separators */ + +static int yyparse(void); +static struct var *lookup(char *n); +static void setval(struct var *vp, char *val); +static void nameval(struct var *vp, char *val, char *name); +static void export(struct var *vp); +static void ronly(struct var *vp); +static int isassign(char *s); +static int checkname(char *cp); +static int assign(char *s, int cf); +static void putvlist(int f, int out); +static int eqname(char *n1, char *n2); + +static int execute(struct op *t, int *pin, int *pout, int act); + +/* -------- io.h -------- */ +/* io buffer */ +struct iobuf { + unsigned id; /* buffer id */ + char buf[512]; /* buffer */ + char *bufp; /* pointer into buffer */ + char *ebufp; /* pointer to end of buffer */ +}; + +/* possible arguments to an IO function */ +struct ioarg { + char *aword; + char **awordlist; + int afile; /* file descriptor */ + unsigned afid; /* buffer id */ + long afpos; /* file position */ + struct iobuf *afbuf; /* buffer for this file */ +}; +static struct ioarg ioargstack[NPUSH]; + +#define AFID_NOBUF (~0) +#define AFID_ID 0 + +/* an input generator's state */ +struct io { + int (*iofn) (); + struct ioarg *argp; + int peekc; + char prev; /* previous character read by readc() */ + char nlcount; /* for `'s */ + char xchar; /* for `'s */ + char task; /* reason for pushed IO */ +}; +static struct io iostack[NPUSH]; + +#define XOTHER 0 /* none of the below */ +#define XDOLL 1 /* expanding ${} */ +#define XGRAVE 2 /* expanding `'s */ +#define XIO 3 /* file IO */ + +/* in substitution */ +#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL) + +/* + * input generators for IO structure + */ +static int nlchar(struct ioarg *ap); +static int strchar(struct ioarg *ap); +static int qstrchar(struct ioarg *ap); +static int filechar(struct ioarg *ap); +static int herechar(struct ioarg *ap); +static int linechar(struct ioarg *ap); +static int gravechar(struct ioarg *ap, struct io *iop); +static int qgravechar(struct ioarg *ap, struct io *iop); +static int dolchar(struct ioarg *ap); +static int wdchar(struct ioarg *ap); +static void scraphere(void); +static void freehere(int area); +static void gethere(void); +static void markhere(char *s, struct ioword *iop); +static int herein(char *hname, int xdoll); +static int run(struct ioarg *argp, int (*f) (struct ioarg * ap)); + +/* + * IO functions + */ +static int eofc(void); +static int getqc(int ec); +static int readc(void); +static void unget(int c); +static void ioecho(int c); +static void prs(char *s); +static void put1c(int c); +static void prn(unsigned u); +static void closef(int i); +static void closeall(void); + +/* + * IO control + */ +static void pushio(struct ioarg *argp, int (*fn) ()); +static int remap(int fd); +static int openpipe(int *pv); +static void closepipe(int *pv); +static struct io *setbase(struct io *ip); + +static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */ + +#define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen))) +#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen))) + +/* -------- word.h -------- */ + +static struct wdblock *addword(char *wd, struct wdblock *wb); +static struct wdblock *newword(int nw); +static char **getwords(struct wdblock *wb); + +/* -------- area.h -------- */ + +/* + * storage allocation + */ +static char *getcell(unsigned nbytes); +static void garbage(void); +static void setarea(char *cp, int a); +static int getarea(char *cp); +static void freearea(int a); +static void freecell(void *cp); + +static int areanum; /* current allocation area */ + +#define NEW(type) (type *)getcell(sizeof(type)) +/* -------- sh.c -------- */ +/* + * shell + */ + +static int intr; +static int inparse; +static char flags['z' - 'a' + 1]; +static char *flag = flags - 'a'; +static char *elinep = line + sizeof(line) - 5; +static char *null = ""; +static int heedint = 1; +static struct env e = { line, iostack, iostack - 1, + (xint *) NULL, FDBASE, (struct env *) NULL +}; + +extern char **environ; /* environment pointer */ + +/* + * default shell, search rules + */ +static char shellname[] = "/bin/sh"; +static char search[] = ":/bin:/usr/bin"; + +static void (*qflag) (int) = SIG_IGN; + +static int newfile(char *s); +static char *findeq(char *cp); +static char *cclass(char *p, int sub); +static void initarea(void); + +struct here { + char *h_tag; + int h_dosub; + struct ioword *h_iop; + struct here *h_next; +}; + +static struct here *inhere; /* list of hear docs while parsing */ +static struct here *acthere; /* list of active here documents */ + +#ifdef BB_FEATURE_COMMAND_EDITING +static char *current_prompt; +#endif + +#ifdef test +int main(int argc, char **argv) +#else +int msh_main(int argc, char **argv) +#endif +{ + register int f; + register char *s; + int cflag; + char *name, **ap; + int (*iof) (); + + initarea(); + if ((ap = environ) != NULL) { + while (*ap) + assign(*ap++, !COPYV); + for (ap = environ; *ap;) + export(lookup(*ap++)); + } + closeall(); + areanum = 1; + + shell = lookup("SHELL"); + if (shell->value == null) + setval(shell, shellname); + export(shell); + + homedir = lookup("HOME"); + if (homedir->value == null) + setval(homedir, "/"); + export(homedir); +#ifdef TEST_NEW_VERSION +#ifdef BB_FEATURE_SH_FANCY_PROMPT + cwd = xgetcwd(0); + if (cwd == 0) + cwd = (char *) unknown; +#endif +#endif + setval(lookup("$"), itoa(getpid(), 5)); + + path = lookup("PATH"); + if (path->value == null) + setval(path, search); + export(path); + + ifs = lookup("IFS"); + if (ifs->value == null) + setval(ifs, " \t\n"); + + prompt = lookup("PS1"); +#ifdef BB_FEATURE_SH_FANCY_PROMPT + if (prompt->value == null) +#endif + setval(prompt, "$ "); + + if (geteuid() == 0) { + setval(prompt, "# "); + prompt->status &= ~EXPORT; + } + cprompt = lookup("PS2"); +#ifdef BB_FEATURE_SH_FANCY_PROMPT + if (cprompt->value == null) +#endif + setval(cprompt, "> "); + + iof = filechar; + cflag = 0; + name = *argv++; + if (--argc >= 1) { + if (argv[0][0] == '-' && argv[0][1] != '\0') { + for (s = argv[0] + 1; *s; s++) + switch (*s) { + case 'c': + prompt->status &= ~EXPORT; + cprompt->status &= ~EXPORT; + setval(prompt, ""); + setval(cprompt, ""); + cflag = 1; + if (--argc > 0) + PUSHIO(aword, *++argv, iof = nlchar); + break; + + case 'q': + qflag = SIG_DFL; + break; + + case 's': + /* standard input */ + break; + + case 't': + prompt->status &= ~EXPORT; + setval(prompt, ""); + iof = linechar; + break; + + case 'i': + interactive++; + default: + if (*s >= 'a' && *s <= 'z') + flag[(int) *s]++; + } + } else { + argv--; + argc++; + } + if (iof == filechar && --argc > 0) { + setval(prompt, ""); + setval(cprompt, ""); + prompt->status &= ~EXPORT; + cprompt->status &= ~EXPORT; + if (newfile(name = *++argv)) + exit(1); + } + } + setdash(); + if (e.iop < iostack) { + PUSHIO(afile, 0, iof); + if (isatty(0) && isatty(1) && !cflag) { + interactive++; + printf( "\n\n" BB_BANNER " Built-in shell (msh)\n"); + printf( "Enter 'help' for a list of built-in commands.\n\n"); + } + } + signal(SIGQUIT, qflag); + if (name && name[0] == '-') { + interactive++; + if ((f = open(".profile", 0)) >= 0) + next(remap(f)); + if ((f = open("/etc/profile", 0)) >= 0) + next(remap(f)); + } + if (interactive) + signal(SIGTERM, sig); + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, onintr); + dolv = argv; + dolc = argc; + dolv[0] = name; + if (dolc > 1) + for (ap = ++argv; --argc > 0;) { + if (assign(*ap = *argv++, !COPYV)) + dolc--; /* keyword */ + else + ap++; + } + setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc)); + + for (;;) { + if (interactive && e.iop <= iostack) +#ifdef BB_FEATURE_COMMAND_EDITING + current_prompt = prompt->value; +#else + prs(prompt->value); +#endif + onecommand(); + /* Ensure that getenv("PATH") stays current */ + setenv("PATH", path->value, 1); + } +} + +void setdash() +{ + register char *cp, c; + char m['z' - 'a' + 1]; + + cp = m; + for (c = 'a'; c <= 'z'; c++) + if (flag[(int) c]) + *cp++ = c; + *cp = 0; + setval(lookup("-"), m); +} + +int newfile(s) +register char *s; +{ + int f; + + if (strcmp(s, "-") != 0) { + f = open(s, 0); + if (f < 0) { + prs(s); + err(": cannot open"); + return (1); + } + } else + f = 0; + next(remap(f)); + return (0); +} + +void onecommand() +{ + int i; + jmp_buf m1; + + while (e.oenv) + quitenv(); + areanum = 1; + freehere(areanum); + freearea(areanum); + garbage(); + wdlist = 0; + iolist = 0; + e.errpt = 0; + e.linep = line; + yynerrs = 0; + multiline = 0; + inparse = 1; + intr = 0; + execflg = 0; + setjmp(failpt = m1); /* Bruce Evans' fix */ + if (setjmp(failpt = m1) || yyparse() || intr) { + while (e.oenv) + quitenv(); + scraphere(); + if (!interactive && intr) + leave(); + inparse = 0; + intr = 0; + return; + } + inparse = 0; + brklist = 0; + intr = 0; + execflg = 0; + if (!flag['n']) + execute(outtree, NOPIPE, NOPIPE, 0); + if (!interactive && intr) { + execflg = 0; + leave(); + } + if ((i = trapset) != 0) { + trapset = 0; + runtrap(i); + } +} + +void fail() +{ + longjmp(failpt, 1); + /* NOTREACHED */ +} + +void leave() +{ + if (execflg) + fail(); + scraphere(); + freehere(1); + runtrap(0); + _exit(exstat); + /* NOTREACHED */ +} + +void warn(s) +register char *s; +{ + if (*s) { + prs(s); + exstat = -1; + } + prs("\n"); + if (flag['e']) + leave(); +} + +void err(s) +char *s; +{ + warn(s); + if (flag['n']) + return; + if (!interactive) + leave(); + if (e.errpt) + longjmp(e.errpt, 1); + closeall(); + e.iop = e.iobase = iostack; +} + +int newenv(f) +int f; +{ + register struct env *ep; + + if (f) { + quitenv(); + return (1); + } + ep = (struct env *) space(sizeof(*ep)); + if (ep == NULL) { + while (e.oenv) + quitenv(); + fail(); + } + *ep = e; + e.oenv = ep; + e.errpt = errpt; + return (0); +} + +void quitenv() +{ + register struct env *ep; + int fd; + + if ((ep = e.oenv) != NULL) { + fd = e.iofd; + e = *ep; + /* should close `'d files */ + freecell(ep); + while (--fd >= e.iofd) + close(fd); + } +} + +/* + * Is any character from s1 in s2? + */ +int anys(s1, s2) +register char *s1, *s2; +{ + while (*s1) + if (any(*s1++, s2)) + return (1); + return (0); +} + +/* + * Is character c in s? + */ +int any(c, s) +register int c; +register char *s; +{ + while (*s) + if (*s++ == c) + return (1); + return (0); +} + +char *putn(n) +register int n; +{ + return (itoa(n, -1)); +} + +char *itoa(u, n) +register unsigned u; +int n; +{ + register char *cp; + static char s[20]; + int m; + + m = 0; + if (n < 0 && (int) u < 0) { + m++; + u = -u; + } + cp = s + sizeof(s); + *--cp = 0; + do { + *--cp = u % 10 + '0'; + u /= 10; + } while (--n > 0 || u); + if (m) + *--cp = '-'; + return (cp); +} + +void next(f) +int f; +{ + PUSHIO(afile, f, filechar); +} + +void onintr(s) +int s; /* ANSI C requires a parameter */ +{ + signal(SIGINT, onintr); + intr = 1; + if (interactive) { + if (inparse) { + prs("\n"); + fail(); + } + } else if (heedint) { + execflg = 0; + leave(); + } +} + +int letter(c) +int c; +{ + return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'); +} + +int digit(c) +int c; +{ + return (c >= '0' && c <= '9'); +} + +int letnum(c) +int c; +{ + return (letter(c) || digit(c)); +} + +char *space(n) +int n; +{ + register char *cp; + + if ((cp = getcell(n)) == 0) + err("out of string space"); + return (cp); +} + +char *strsave(s, a) +register char *s; +int a; +{ + register char *cp, *xp; + + if ((cp = space(strlen(s) + 1)) != NULL) { + setarea((char *) cp, a); + for (xp = cp; (*xp++ = *s++) != '\0';); + return (cp); + } + return (""); +} + +/* + * trap handling + */ +void sig(i) +register int i; +{ + trapset = i; + signal(i, sig); +} + +void runtrap(i) +int i; +{ + char *trapstr; + + if ((trapstr = trap[i]) == NULL) + return; + if (i == 0) + trap[i] = 0; + RUN(aword, trapstr, nlchar); +} + +/* -------- var.c -------- */ + +/* + * Find the given name in the dictionary + * and return its value. If the name was + * not previously there, enter it now and + * return a null value. + */ +struct var *lookup(n) +register char *n; +{ + register struct var *vp; + register char *cp; + register int c; + static struct var dummy; + + if (digit(*n)) { + dummy.name = n; + for (c = 0; digit(*n) && c < 1000; n++) + c = c * 10 + *n - '0'; + dummy.status = RONLY; + dummy.value = c <= dolc ? dolv[c] : null; + return (&dummy); + } + for (vp = vlist; vp; vp = vp->next) + if (eqname(vp->name, n)) + return (vp); + cp = findeq(n); + vp = (struct var *) space(sizeof(*vp)); + if (vp == 0 || (vp->name = space((int) (cp - n) + 2)) == 0) { + dummy.name = dummy.value = ""; + return (&dummy); + } + for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++); + if (*cp == 0) + *cp = '='; + *++cp = 0; + setarea((char *) vp, 0); + setarea((char *) vp->name, 0); + vp->value = null; + vp->next = vlist; + vp->status = GETCELL; + vlist = vp; + return (vp); +} + +/* + * give variable at `vp' the value `val'. + */ +void setval(vp, val) +struct var *vp; +char *val; +{ + nameval(vp, val, (char *) NULL); +} + +/* + * if name is not NULL, it must be + * a prefix of the space `val', + * and end with `='. + * this is all so that exporting + * values is reasonably painless. + */ +void nameval(vp, val, name) +register struct var *vp; +char *val, *name; +{ + register char *cp, *xp; + char *nv; + int fl; + + if (vp->status & RONLY) { + for (xp = vp->name; *xp && *xp != '=';) + put1c(*xp++); + err(" is read-only"); + return; + } + fl = 0; + if (name == NULL) { + xp = space(strlen(vp->name) + strlen(val) + 2); + if (xp == 0) + return; + /* make string: name=value */ + setarea((char *) xp, 0); + name = xp; + for (cp = vp->name; (*xp = *cp++) && *xp != '='; xp++); + if (*xp++ == 0) + xp[-1] = '='; + nv = xp; + for (cp = val; (*xp++ = *cp++) != '\0';); + val = nv; + fl = GETCELL; + } + if (vp->status & GETCELL) + freecell(vp->name); /* form new string `name=value' */ + vp->name = name; + vp->value = val; + vp->status |= fl; +} + +void export(vp) +struct var *vp; +{ + vp->status |= EXPORT; +} + +void ronly(vp) +struct var *vp; +{ + if (letter(vp->name[0])) /* not an internal symbol ($# etc) */ + vp->status |= RONLY; +} + +int isassign(s) +register char *s; +{ + if (!letter((int) *s)) + return (0); + for (; *s != '='; s++) + if (*s == 0 || !letnum(*s)) + return (0); + return (1); +} + +int assign(s, cf) +register char *s; +int cf; +{ + register char *cp; + struct var *vp; + + if (!letter(*s)) + return (0); + for (cp = s; *cp != '='; cp++) + if (*cp == 0 || !letnum(*cp)) + return (0); + vp = lookup(s); + nameval(vp, ++cp, cf == COPYV ? (char *) NULL : s); + if (cf != COPYV) + vp->status &= ~GETCELL; + return (1); +} + +int checkname(cp) +register char *cp; +{ + if (!letter(*cp++)) + return (0); + while (*cp) + if (!letnum(*cp++)) + return (0); + return (1); +} + +void putvlist(f, out) +register int f, out; +{ + register struct var *vp; + + for (vp = vlist; vp; vp = vp->next) + if (vp->status & f && letter(*vp->name)) { + if (vp->status & EXPORT) + write(out, "export ", 7); + if (vp->status & RONLY) + write(out, "readonly ", 9); + write(out, vp->name, (int) (findeq(vp->name) - vp->name)); + write(out, "\n", 1); + } +} + +int eqname(n1, n2) +register char *n1, *n2; +{ + for (; *n1 != '=' && *n1 != 0; n1++) + if (*n2++ != *n1) + return (0); + return (*n2 == 0 || *n2 == '='); +} + +static char *findeq(cp) +register char *cp; +{ + while (*cp != '\0' && *cp != '=') + cp++; + return (cp); +} + +/* -------- gmatch.c -------- */ +/* + * int gmatch(string, pattern) + * char *string, *pattern; + * + * Match a pattern as in sh(1). + */ + +#define CMASK 0377 +#define QUOTE 0200 +#define QMASK (CMASK&~QUOTE) +#define NOT '!' /* might use ^ */ + +int gmatch(s, p) +register char *s, *p; +{ + register int sc, pc; + + if (s == NULL || p == NULL) + return (0); + while ((pc = *p++ & CMASK) != '\0') { + sc = *s++ & QMASK; + switch (pc) { + case '[': + if ((p = cclass(p, sc)) == NULL) + return (0); + break; + + case '?': + if (sc == 0) + return (0); + break; + + case '*': + s--; + do { + if (*p == '\0' || gmatch(s, p)) + return (1); + } while (*s++ != '\0'); + return (0); + + default: + if (sc != (pc & ~QUOTE)) + return (0); + } + } + return (*s == 0); +} + +static char *cclass(p, sub) +register char *p; +register int sub; +{ + register int c, d, not, found; + + if ((not = *p == NOT) != 0) + p++; + found = not; + do { + if (*p == '\0') + return ((char *) NULL); + c = *p & CMASK; + if (p[1] == '-' && p[2] != ']') { + d = p[2] & CMASK; + p++; + } else + d = c; + if (c == sub || (c <= sub && sub <= d)) + found = !not; + } while (*++p != ']'); + return (found ? p + 1 : (char *) NULL); +} + +/* -------- area.c -------- */ +#define REGSIZE sizeof(struct region) +#define GROWBY 256 +#define FREE 32767 +#define BUSY 0 +#define ALIGN (sizeof(int)-1) + +/* #include "area.h" */ + +struct region { + struct region *next; + int area; +}; + +/* + * All memory between (char *)areabot and (char *)(areatop+1) is + * exclusively administered by the area management routines. + */ +#define sbrk(X) ({ void * __q = (void *)-1; if (brkaddr + (int)(X) < brktop) { __q = brkaddr; brkaddr+=(int)(X); } __q;}) + +static struct region *areabot; /* bottom of area */ +static struct region *areatop; /* top of area */ +static struct region *areanxt; /* starting point of scan */ + +static void *brktop; +static void *brkaddr; + +static void initarea() +{ + brkaddr = malloc(65000); + brktop = brkaddr + 65000; + + while ((int) sbrk(0) & ALIGN) + sbrk(1); + areabot = (struct region *) sbrk(REGSIZE); + + areabot->next = areabot; + areabot->area = BUSY; + areatop = areabot; + areanxt = areabot; +} + +char *getcell(nbytes) +unsigned nbytes; +{ + int nregio; + register struct region *p, *q; + int i; + + if (nbytes == 0) /* silly and defeats the algorithm */ + Abort(); + + /* + * round upwards and add administration area + */ + nregio = (nbytes + (REGSIZE - 1)) / REGSIZE + 1; + for (p = areanxt;;) { + if (p->area > areanum) { + /* + * merge free cells + */ + while ((q = p->next)->area > areanum && q != areanxt) + p->next = q->next; + /* + * exit loop if cell big enough + */ + if (q >= p + nregio) + goto found; + } + p = p->next; + if (p == areanxt) + break; + } + i = nregio >= GROWBY ? nregio : GROWBY; + p = (struct region *) sbrk(i * REGSIZE); + if (p == (struct region *) -1) + return ((char *) NULL); + p--; + if (p != areatop) /* allocated areas are contiguous */ + Abort(); + + q = p + i; + p->next = q; + p->area = FREE; + q->next = areabot; + q->area = BUSY; + areatop = q; + found: + /* + * we found a FREE area big enough, pointed to by 'p', and up to 'q' + */ + areanxt = p + nregio; + if (areanxt < q) { + /* + * split into requested area and rest + */ + if (areanxt + 1 > q) /* insufficient space left for admin */ + Abort(); + + areanxt->next = q; + areanxt->area = FREE; + p->next = areanxt; + } + p->area = areanum; + return ((char *) (p + 1)); +} + + +void freecell(void *cp) +{ + register struct region *p; + + if ((p = (struct region *) cp) != NULL) { + p--; + if (p < areanxt) + areanxt = p; + p->area = FREE; + } +} + +void freearea(a) +register int a; +{ + register struct region *p, *top; + + top = areatop; + for (p = areabot; p != top; p = p->next) + if (p->area >= a) + p->area = FREE; +} + +void setarea(cp, a) +char *cp; +int a; +{ + register struct region *p; + + if ((p = (struct region *) cp) != NULL) + (p - 1)->area = a; +} + +int getarea(cp) +char *cp; +{ + return ((struct region *) cp - 1)->area; +} + +void garbage() +{ + register struct region *p, *q, *top; + + top = areatop; + for (p = areabot; p != top; p = p->next) { + if (p->area > areanum) { + while ((q = p->next)->area > areanum) + p->next = q->next; + areanxt = p; + } + } +} + +/* -------- csyn.c -------- */ +/* + * shell: syntax (C version) + */ + +typedef union { + char *cp; + char **wp; + int i; + struct op *o; +} YYSTYPE; + +#define WORD 256 +#define LOGAND 257 +#define LOGOR 258 +#define BREAK 259 +#define IF 260 +#define THEN 261 +#define ELSE 262 +#define ELIF 263 +#define FI 264 +#define CASE 265 +#define ESAC 266 +#define FOR 267 +#define WHILE 268 +#define UNTIL 269 +#define DO 270 +#define DONE 271 +#define IN 272 +#define YYERRCODE 300 + +/* flags to yylex */ +#define CONTIN 01 /* skip new lines to complete command */ + +#define SYNTAXERR zzerr() +static int startl; +static int peeksym; +static int nlseen; +static int iounit = IODEFAULT; + +static YYSTYPE yylval; + +static struct op *pipeline(int cf); +static struct op *andor(void); +static struct op *c_list(void); +static int synio(int cf); +static void musthave(int c, int cf); +static struct op *simple(void); +static struct op *nested(int type, int mark); +static struct op *command(int cf); +static struct op *dogroup(int onlydone); +static struct op *thenpart(void); +static struct op *elsepart(void); +static struct op *caselist(void); +static struct op *casepart(void); +static char **pattern(void); +static char **wordlist(void); +static struct op *list(struct op *t1, struct op *t2); +static struct op *block(int type, struct op *t1, struct op *t2, char **wp); +static struct op *newtp(void); +static struct op *namelist(struct op *t); +static char **copyw(void); +static void word(char *cp); +static struct ioword **copyio(void); +static struct ioword *io(int u, int f, char *cp); +static void zzerr(void); +static void yyerror(char *s); +static int yylex(int cf); +static int collect(int c, int c1); +static int dual(int c); +static void diag(int ec); +static char *tree(unsigned size); + +int yyparse() +{ + startl = 1; + peeksym = 0; + yynerrs = 0; + outtree = c_list(); + musthave('\n', 0); + return (yynerrs != 0); +} + +static struct op *pipeline(cf) +int cf; +{ + register struct op *t, *p; + register int c; + + t = command(cf); + if (t != NULL) { + while ((c = yylex(0)) == '|') { + if ((p = command(CONTIN)) == NULL) + SYNTAXERR; + if (t->type != TPAREN && t->type != TCOM) { + /* shell statement */ + t = block(TPAREN, t, NOBLOCK, NOWORDS); + } + t = block(TPIPE, t, p, NOWORDS); + } + peeksym = c; + } + return (t); +} + +static struct op *andor() +{ + register struct op *t, *p; + register int c; + + t = pipeline(0); + if (t != NULL) { + while ((c = yylex(0)) == LOGAND || c == LOGOR) { + if ((p = pipeline(CONTIN)) == NULL) + SYNTAXERR; + t = block(c == LOGAND ? TAND : TOR, t, p, NOWORDS); + } + peeksym = c; + } + return (t); +} + +static struct op *c_list() +{ + register struct op *t, *p; + register int c; + + t = andor(); + if (t != NULL) { + if ((peeksym = yylex(0)) == '&') + t = block(TASYNC, t, NOBLOCK, NOWORDS); + while ((c = yylex(0)) == ';' || c == '&' + || (multiline && c == '\n')) { + if ((p = andor()) == NULL) + return (t); + if ((peeksym = yylex(0)) == '&') + p = block(TASYNC, p, NOBLOCK, NOWORDS); + t = list(t, p); + } + peeksym = c; + } + return (t); +} + + +static int synio(cf) +int cf; +{ + register struct ioword *iop; + register int i; + register int c; + + if ((c = yylex(cf)) != '<' && c != '>') { + peeksym = c; + return (0); + } + i = yylval.i; + musthave(WORD, 0); + iop = io(iounit, i, yylval.cp); + iounit = IODEFAULT; + if (i & IOHERE) + markhere(yylval.cp, iop); + return (1); +} + +static void musthave(c, cf) +int c, cf; +{ + if ((peeksym = yylex(cf)) != c) + SYNTAXERR; + peeksym = 0; +} + +static struct op *simple() +{ + register struct op *t; + + t = NULL; + for (;;) { + switch (peeksym = yylex(0)) { + case '<': + case '>': + (void) synio(0); + break; + + case WORD: + if (t == NULL) { + t = newtp(); + t->type = TCOM; + } + peeksym = 0; + word(yylval.cp); + break; + + default: + return (t); + } + } +} + +static struct op *nested(type, mark) +int type, mark; +{ + register struct op *t; + + multiline++; + t = c_list(); + musthave(mark, 0); + multiline--; + return (block(type, t, NOBLOCK, NOWORDS)); +} + +static struct op *command(cf) +int cf; +{ + register struct op *t; + struct wdblock *iosave; + register int c; + + iosave = iolist; + iolist = NULL; + if (multiline) + cf |= CONTIN; + while (synio(cf)) + cf = 0; + switch (c = yylex(cf)) { + default: + peeksym = c; + if ((t = simple()) == NULL) { + if (iolist == NULL) + return ((struct op *) NULL); + t = newtp(); + t->type = TCOM; + } + break; + + case '(': + t = nested(TPAREN, ')'); + break; + + case '{': + t = nested(TBRACE, '}'); + break; + + case FOR: + t = newtp(); + t->type = TFOR; + musthave(WORD, 0); + startl = 1; + t->str = yylval.cp; + multiline++; + t->words = wordlist(); + if ((c = yylex(0)) != '\n' && c != ';') + peeksym = c; + t->left = dogroup(0); + multiline--; + break; + + case WHILE: + case UNTIL: + multiline++; + t = newtp(); + t->type = c == WHILE ? TWHILE : TUNTIL; + t->left = c_list(); + t->right = dogroup(1); + t->words = NULL; + multiline--; + break; + + case CASE: + t = newtp(); + t->type = TCASE; + musthave(WORD, 0); + t->str = yylval.cp; + startl++; + multiline++; + musthave(IN, CONTIN); + startl++; + t->left = caselist(); + musthave(ESAC, 0); + multiline--; + break; + + case IF: + multiline++; + t = newtp(); + t->type = TIF; + t->left = c_list(); + t->right = thenpart(); + musthave(FI, 0); + multiline--; + break; + } + while (synio(0)); + t = namelist(t); + iolist = iosave; + return (t); +} + +static struct op *dogroup(onlydone) +int onlydone; +{ + register int c; + register struct op *oplist; + + c = yylex(CONTIN); + if (c == DONE && onlydone) + return ((struct op *) NULL); + if (c != DO) + SYNTAXERR; + oplist = c_list(); + musthave(DONE, 0); + return (oplist); +} + +static struct op *thenpart() +{ + register int c; + register struct op *t; + + if ((c = yylex(0)) != THEN) { + peeksym = c; + return ((struct op *) NULL); + } + t = newtp(); + t->type = 0; + t->left = c_list(); + if (t->left == NULL) + SYNTAXERR; + t->right = elsepart(); + return (t); +} + +static struct op *elsepart() +{ + register int c; + register struct op *t; + + switch (c = yylex(0)) { + case ELSE: + if ((t = c_list()) == NULL) + SYNTAXERR; + return (t); + + case ELIF: + t = newtp(); + t->type = TELIF; + t->left = c_list(); + t->right = thenpart(); + return (t); + + default: + peeksym = c; + return ((struct op *) NULL); + } +} + +static struct op *caselist() +{ + register struct op *t; + + t = NULL; + while ((peeksym = yylex(CONTIN)) != ESAC) + t = list(t, casepart()); + return (t); +} + +static struct op *casepart() +{ + register struct op *t; + + t = newtp(); + t->type = TPAT; + t->words = pattern(); + musthave(')', 0); + t->left = c_list(); + if ((peeksym = yylex(CONTIN)) != ESAC) + musthave(BREAK, CONTIN); + return (t); +} + +static char **pattern() +{ + register int c, cf; + + cf = CONTIN; + do { + musthave(WORD, cf); + word(yylval.cp); + cf = 0; + } while ((c = yylex(0)) == '|'); + peeksym = c; + word(NOWORD); + return (copyw()); +} + +static char **wordlist() +{ + register int c; + + if ((c = yylex(0)) != IN) { + peeksym = c; + return ((char **) NULL); + } + startl = 0; + while ((c = yylex(0)) == WORD) + word(yylval.cp); + word(NOWORD); + peeksym = c; + return (copyw()); +} + +/* + * supporting functions + */ +static struct op *list(t1, t2) +register struct op *t1, *t2; +{ + if (t1 == NULL) + return (t2); + if (t2 == NULL) + return (t1); + return (block(TLIST, t1, t2, NOWORDS)); +} + +static struct op *block(type, t1, t2, wp) +int type; +struct op *t1, *t2; +char **wp; +{ + register struct op *t; + + t = newtp(); + t->type = type; + t->left = t1; + t->right = t2; + t->words = wp; + return (t); +} + +static struct res { + char *r_name; + int r_val; +} restab[] = { + { + "for", FOR}, { + "case", CASE}, { + "esac", ESAC}, { + "while", WHILE}, { + "do", DO}, { + "done", DONE}, { + "if", IF}, { + "in", IN}, { + "then", THEN}, { + "else", ELSE}, { + "elif", ELIF}, { + "until", UNTIL}, { + "fi", FI}, { + ";;", BREAK}, { + "||", LOGOR}, { + "&&", LOGAND}, { + "{", '{'}, { + "}", '}'}, { + 0, 0} +}; + +int rlookup(n) +register char *n; +{ + register struct res *rp; + + for (rp = restab; rp->r_name; rp++) + if (strcmp(rp->r_name, n) == 0) + return (rp->r_val); + return (0); +} + +static struct op *newtp() +{ + register struct op *t; + + t = (struct op *) tree(sizeof(*t)); + t->type = 0; + t->words = NULL; + t->ioact = NULL; + t->left = NULL; + t->right = NULL; + t->str = NULL; + return (t); +} + +static struct op *namelist(t) +register struct op *t; +{ + if (iolist) { + iolist = addword((char *) NULL, iolist); + t->ioact = copyio(); + } else + t->ioact = NULL; + if (t->type != TCOM) { + if (t->type != TPAREN && t->ioact != NULL) { + t = block(TPAREN, t, NOBLOCK, NOWORDS); + t->ioact = t->left->ioact; + t->left->ioact = NULL; + } + return (t); + } + word(NOWORD); + t->words = copyw(); + return (t); +} + +static char **copyw() +{ + register char **wd; + + wd = getwords(wdlist); + wdlist = 0; + return (wd); +} + +static void word(cp) +char *cp; +{ + wdlist = addword(cp, wdlist); +} + +static struct ioword **copyio() +{ + register struct ioword **iop; + + iop = (struct ioword **) getwords(iolist); + iolist = 0; + return (iop); +} + +static struct ioword *io(u, f, cp) +int u; +int f; +char *cp; +{ + register struct ioword *iop; + + iop = (struct ioword *) tree(sizeof(*iop)); + iop->io_unit = u; + iop->io_flag = f; + iop->io_name = cp; + iolist = addword((char *) iop, iolist); + return (iop); +} + +static void zzerr() +{ + yyerror("syntax error"); +} + +void yyerror(s) +char *s; +{ + yynerrs++; + if (interactive && e.iop <= iostack) { + multiline = 0; + while (eofc() == 0 && yylex(0) != '\n'); + } + err(s); + fail(); +} + +static int yylex(cf) +int cf; +{ + register int c, c1; + int atstart; + + if ((c = peeksym) > 0) { + peeksym = 0; + if (c == '\n') + startl = 1; + return (c); + } + nlseen = 0; + e.linep = line; + atstart = startl; + startl = 0; + yylval.i = 0; + + loop: + while ((c = getqc(0)) == ' ' || c == '\t'); + switch (c) { + default: + if (any(c, "0123456789")) { + unget(c1 = getqc(0)); + if (c1 == '<' || c1 == '>') { + iounit = c - '0'; + goto loop; + } + *e.linep++ = c; + c = c1; + } + break; + + case '#': + while ((c = getqc(0)) != 0 && c != '\n'); + unget(c); + goto loop; + + case 0: + return (c); + + case '$': + *e.linep++ = c; + if ((c = getqc(0)) == '{') { + if ((c = collect(c, '}')) != '\0') + return (c); + goto pack; + } + break; + + case '`': + case '\'': + case '"': + if ((c = collect(c, c)) != '\0') + return (c); + goto pack; + + case '|': + case '&': + case ';': + if ((c1 = dual(c)) != '\0') { + startl = 1; + return (c1); + } + startl = 1; + return (c); + case '^': + startl = 1; + return ('|'); + case '>': + case '<': + diag(c); + return (c); + + case '\n': + nlseen++; + gethere(); + startl = 1; + if (multiline || cf & CONTIN) { + if (interactive && e.iop <= iostack) +#ifdef BB_FEATURE_COMMAND_EDITING + current_prompt = cprompt->value; +#else + prs(cprompt->value); +#endif + if (cf & CONTIN) + goto loop; + } + return (c); + + case '(': + case ')': + startl = 1; + return (c); + } + + unget(c); + + pack: + while ((c = getqc(0)) != 0 && !any(c, "`$ '\"\t;&<>()|^\n")) + if (e.linep >= elinep) + err("word too long"); + else + *e.linep++ = c; + unget(c); + if (any(c, "\"'`$")) + goto loop; + *e.linep++ = '\0'; + if (atstart && (c = rlookup(line)) != 0) { + startl = 1; + return (c); + } + yylval.cp = strsave(line, areanum); + return (WORD); +} + +int collect(c, c1) +int c, c1; +{ + char s[2]; + + *e.linep++ = c; + while ((c = getqc(c1)) != c1) { + if (c == 0) { + unget(c); + s[0] = c1; + s[1] = 0; + prs("no closing "); + yyerror(s); + return (YYERRCODE); + } + if (interactive && c == '\n' && e.iop <= iostack) +#ifdef BB_FEATURE_COMMAND_EDITING + current_prompt = cprompt->value; +#else + prs(cprompt->value); +#endif + *e.linep++ = c; + } + *e.linep++ = c; + return (0); +} + +int dual(c) +int c; +{ + char s[3]; + register char *cp = s; + + *cp++ = c; + *cp++ = getqc(0); + *cp = 0; + if ((c = rlookup(s)) == 0) + unget(*--cp); + return (c); +} + +static void diag(ec) +register int ec; +{ + register int c; + + c = getqc(0); + if (c == '>' || c == '<') { + if (c != ec) + zzerr(); + yylval.i = ec == '>' ? IOWRITE | IOCAT : IOHERE; + c = getqc(0); + } else + yylval.i = ec == '>' ? IOWRITE : IOREAD; + if (c != '&' || yylval.i == IOHERE) + unget(c); + else + yylval.i |= IODUP; +} + +static char *tree(size) +unsigned size; +{ + register char *t; + + if ((t = getcell(size)) == NULL) { + prs("command line too complicated\n"); + fail(); + /* NOTREACHED */ + } + return (t); +} + +/* -------- exec.c -------- */ + +/* + * execute tree + */ + +static char *signame[] = { + "Signal 0", + "Hangup", + (char *) NULL, /* interrupt */ + "Quit", + "Illegal instruction", + "Trace/BPT trap", + "Abort", + "EMT trap", + "Floating exception", + "Killed", + "Bus error", + "Memory fault", + "Bad system call", + (char *) NULL, /* broken pipe */ + "Alarm clock", + "Terminated", +}; + +#define NSIGNAL (sizeof(signame)/sizeof(signame[0])) + +/* + * common actions when creating a new child + */ +#ifdef USE_FORK +#define XFORK fork +static int parent() +{ + register int i; + + i = fork(); + if (i != 0) { + if (i == -1) + warn("try again"); + } + return (i); +} +#else +# define parent vfork +# define XFORK vfork +#endif + +static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp, + int *pforked); +static int iosetup(struct ioword *iop, int pipein, int pipeout); +static void echo(char **wp); +static struct op **find1case(struct op *t, char *w); +static struct op *findcase(struct op *t, char *w); +static void brkset(struct brkcon *bc); +static int dolabel(void); +static int dochdir(struct op *t); +static int doshift(struct op *t); +static int dologin(struct op *t); +static int doumask(struct op *t); +static int doexec(struct op *t); +static int dodot(struct op *t); +static int dowait(struct op *t); +static int doread(struct op *t); +static int doeval(struct op *t); +static int dotrap(struct op *t); +static int getsig(char *s); +static void setsig(int n, void (*f) ()); +static int getn(char *as); +static int dobreak(struct op *t); +static int docontinue(struct op *t); +static int brkcontin(char *cp, int val); +static int doexit(struct op *t); +static int doexport(struct op *t); +static int doreadonly(struct op *t); +static void rdexp(char **wp, void (*f) (), int key); +static void badid(char *s); +static int doset(struct op *t); +static void varput(char *s, int out); +static int dotimes(void); + +int execute(t, pin, pout, act) +register struct op *t; +int *pin, *pout; +int act; +{ + register struct op *t1; + int i, pv[2], rv, child, a; + char *cp, **wp, **wp2; + struct var *vp; + struct brkcon bc; + +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &i; + (void) &rv; + (void) ℘ +#endif + + if (t == NULL) + return (0); + rv = 0; + a = areanum++; + wp = (wp2 = t->words) != NULL + ? eval(wp2, t->type == TCOM ? DOALL : DOALL & ~DOKEY) + : NULL; + + switch (t->type) { + case TPAREN: + case TCOM: + rv = forkexec(t, pin, pout, act, wp, &child); + if (child) { + exstat = rv; + leave(); + } + break; + + case TPIPE: + if ((rv = openpipe(pv)) < 0) + break; + pv[0] = remap(pv[0]); + pv[1] = remap(pv[1]); + (void) execute(t->left, pin, pv, 0); + rv = execute(t->right, pv, pout, 0); + break; + + case TLIST: + (void) execute(t->left, pin, pout, 0); + rv = execute(t->right, pin, pout, 0); + break; + + case TASYNC: + { + /* save global vars altered by child */ + int hinteractive = interactive; + + i = parent(); + if (i != 0) { + /* restore global vars */ + interactive = hinteractive; + + if (i != -1) { + setval(lookup("!"), putn(i)); + if (pin != NULL) + closepipe(pin); + if (interactive) { + prs(putn(i)); + prs("\n"); + } + } else + rv = -1; + setstatus(rv); + } else { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + if (interactive) + signal(SIGTERM, SIG_DFL); + interactive = 0; + if (pin == NULL) { + close(0); + open("/dev/null", 0); + } + _exit(execute(t->left, pin, pout, FEXEC)); + } + break; + } + case TOR: + case TAND: + rv = execute(t->left, pin, pout, 0); + if ((t1 = t->right) != NULL && (rv == 0) == (t->type == TAND)) + rv = execute(t1, pin, pout, 0); + break; + + case TFOR: + if (wp == NULL) { + wp = dolv + 1; + if ((i = dolc) < 0) + i = 0; + } else { + i = -1; + while (*wp++ != NULL); + } + vp = lookup(t->str); + while (setjmp(bc.brkpt)) + if (isbreak) + goto broken; + brkset(&bc); + for (t1 = t->left; i-- && *wp != NULL;) { + setval(vp, *wp++); + rv = execute(t1, pin, pout, 0); + } + brklist = brklist->nextlev; + break; + + case TWHILE: + case TUNTIL: + while (setjmp(bc.brkpt)) + if (isbreak) + goto broken; + brkset(&bc); + t1 = t->left; + while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE)) + rv = execute(t->right, pin, pout, 0); + brklist = brklist->nextlev; + break; + + case TIF: + case TELIF: + if (t->right != NULL) { + rv = !execute(t->left, pin, pout, 0) ? + execute(t->right->left, pin, pout, 0) : + execute(t->right->right, pin, pout, 0); + } + break; + + case TCASE: + if ((cp = evalstr(t->str, DOSUB | DOTRIM)) == 0) + cp = ""; + if ((t1 = findcase(t->left, cp)) != NULL) + rv = execute(t1, pin, pout, 0); + break; + + case TBRACE: +/* + if (iopp = t->ioact) + while (*iopp) + if (iosetup(*iopp++, pin!=NULL, pout!=NULL)) { + rv = -1; + break; + } +*/ + if (rv >= 0 && (t1 = t->left)) + rv = execute(t1, pin, pout, 0); + break; + } + + broken: + t->words = wp2; + isbreak = 0; + freehere(areanum); + freearea(areanum); + areanum = a; + if (interactive && intr) { + closeall(); + fail(); + } + if ((i = trapset) != 0) { + trapset = 0; + runtrap(i); + } + return (rv); +} + +static int forkexec(t, pin, pout, act, wp, pforked) +register struct op *t; +int *pin, *pout; +int act; +char **wp; +int *pforked; +{ + int i, rv, (*shcom) (); + register int f; + char *cp = NULL; + struct ioword **iopp; + int resetsig; + char **owp; + + int *hpin = pin; + int *hpout = pout; + int hforked; + char *hwp; + int hinteractive; + int hintr; + struct brkcon * hbrklist; + int hexecflg; + +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &pin; + (void) &pout; + (void) ℘ + (void) &shcom; + (void) &cp; + (void) &resetsig; + (void) &owp; +#endif + + owp = wp; + resetsig = 0; + *pforked = 0; + shcom = NULL; + rv = -1; /* system-detected error */ + if (t->type == TCOM) { + while ((cp = *wp++) != NULL); + cp = *wp; + + /* strip all initial assignments */ + /* not correct wrt PATH=yyy command etc */ + if (flag['x']) + echo(cp ? wp : owp); + if (cp == NULL && t->ioact == NULL) { + while ((cp = *owp++) != NULL && assign(cp, COPYV)); + return (setstatus(0)); + } else if (cp != NULL) + shcom = inbuilt(cp); + } + t->words = wp; + f = act; + if (shcom == NULL && (f & FEXEC) == 0) { + + /* save vars altered by child (needed by vfork) */ + hpin = pin; + hpout = pout; + hforked = *pforked; + hwp = *wp; + hinteractive = interactive; + hintr = intr; + hbrklist = brklist; + hexecflg = execflg; + + i = parent(); + if (i != 0) { + /* restore vars altered by child (needed by vfork) */ + pin = hpin; + pout = hpout; + *pforked = hforked; + *wp = hwp; + interactive = hinteractive; + intr = hintr; + brklist = hbrklist; + execflg = hexecflg; + + *pforked = 0; + if (i == -1) + return (rv); + if (pin != NULL) + closepipe(pin); + return (pout == NULL ? setstatus(waitfor(i, 0)) : 0); + } + if (interactive) { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + resetsig = 1; + } + interactive = 0; + intr = 0; + (*pforked)++; + brklist = 0; + execflg = 0; + } + if (owp != NULL) + while ((cp = *owp++) != NULL && assign(cp, COPYV)) + if (shcom == NULL) + export(lookup(cp)); +#ifdef COMPIPE + if ((pin != NULL || pout != NULL) && shcom != NULL && shcom != doexec) { + err("piping to/from shell builtins not yet done"); + return (-1); + } +#endif + if (pin != NULL) { + dup2(pin[0], 0); + closepipe(pin); + } + if (pout != NULL) { + dup2(pout[1], 1); + closepipe(pout); + } + if ((iopp = t->ioact) != NULL) { + if (shcom != NULL && shcom != doexec) { + prs(cp); + err(": cannot redirect shell command"); + return (-1); + } + while (*iopp) + if (iosetup(*iopp++, pin != NULL, pout != NULL)) + return (rv); + } + if (shcom) + return (setstatus((*shcom) (t))); + /* should use FIOCEXCL */ + for (i = FDBASE; i < NOFILE; i++) + close(i); + if (resetsig) { + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + } + if (t->type == TPAREN) + _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC)); + if (wp[0] == NULL) + _exit(0); + cp = rexecve(wp[0], wp, makenv(0)); + prs(wp[0]); + prs(": "); + warn(cp); + if (!execflg) + trap[0] = NULL; +#ifdef __uClinux__ + _exit(1); +#else + leave(); +#endif + /* NOTREACHED */ +} + +/* + * 0< 1> are ignored as required + * within pipelines. + */ +int iosetup(iop, pipein, pipeout) +register struct ioword *iop; +int pipein, pipeout; +{ + int u; + char *msg; + char *cp = NULL; + + if (iop->io_unit == IODEFAULT) /* take default */ + iop->io_unit = iop->io_flag & (IOREAD | IOHERE) ? 0 : 1; + if (pipein && iop->io_unit == 0) + return (0); + if (pipeout && iop->io_unit == 1) + return (0); + msg = iop->io_flag & (IOREAD | IOHERE) ? "open" : "create"; + if ((iop->io_flag & IOHERE) == 0) { + cp = iop->io_name; + if ((cp = evalstr(cp, DOSUB | DOTRIM)) == NULL) + return (1); + } + if (iop->io_flag & IODUP) { + if (cp[1] || (!digit(*cp) && *cp != '-')) { + prs(cp); + err(": illegal >& argument"); + return (1); + } + if (*cp == '-') + iop->io_flag = IOCLOSE; + iop->io_flag &= ~(IOREAD | IOWRITE); + } + switch (iop->io_flag) { + case IOREAD: + u = open(cp, 0); + break; + + case IOHERE: + case IOHERE | IOXHERE: + u = herein(iop->io_name, iop->io_flag & IOXHERE); + cp = "here file "; + break; + + case IOWRITE | IOCAT: + if ((u = open(cp, 1)) >= 0) { + lseek(u, (long) 0, 2); + break; + } + case IOWRITE: + u = creat(cp, 0666); + break; + + case IODUP: + u = dup2(*cp - '0', iop->io_unit); + break; + + case IOCLOSE: + close(iop->io_unit); + return (0); + default: + u = -1; + break; + } + if (u < 0) { + int sav_err = errno; + + prs(cp); + if (iop->io_flag & IOHERE) + prs(iop->io_name); + prs(": cannot "); + prs(msg); + prs(" ("); + prs(strerror(sav_err)); + warn(")"); + return (1); + } else { + if (u != iop->io_unit) { + dup2(u, iop->io_unit); + close(u); + } + } + return (0); +} + +static void echo(wp) +register char **wp; +{ + int i; + + prs("+"); + for (i = 0; wp[i]; i++) { + if (i) + prs(" "); + prs(wp[i]); + } + prs("\n"); +} + +static struct op **find1case(t, w) +struct op *t; +char *w; +{ + register struct op *t1; + struct op **tp; + register char **wp, *cp; + + if (t == NULL) + return ((struct op **) NULL); + if (t->type == TLIST) { + if ((tp = find1case(t->left, w)) != NULL) + return (tp); + t1 = t->right; /* TPAT */ + } else + t1 = t; + for (wp = t1->words; *wp;) + if ((cp = evalstr(*wp++, DOSUB)) && gmatch(w, cp)) + return (&t1->left); + return ((struct op **) NULL); +} + +static struct op *findcase(t, w) +struct op *t; +char *w; +{ + register struct op **tp; + + return ((tp = find1case(t, w)) != NULL ? *tp : (struct op *) NULL); +} + +/* + * Enter a new loop level (marked for break/continue). + */ +static void brkset(bc) +struct brkcon *bc; +{ + bc->nextlev = brklist; + brklist = bc; +} + +/* + * Wait for the last process created. + * Print a message for each process found + * that was killed by a signal. + * Ignore interrupt signals while waiting + * unless `canintr' is true. + */ +int waitfor(lastpid, canintr) +register int lastpid; +int canintr; +{ + register int pid, rv; + int s; + int oheedint = heedint; + + heedint = 0; + rv = 0; + do { + pid = wait(&s); + if (pid == -1) { + if (errno != EINTR || canintr) + break; + } else { + if ((rv = WAITSIG(s)) != 0) { + if (rv < NSIGNAL) { + if (signame[rv] != NULL) { + if (pid != lastpid) { + prn(pid); + prs(": "); + } + prs(signame[rv]); + } + } else { + if (pid != lastpid) { + prn(pid); + prs(": "); + } + prs("Signal "); + prn(rv); + prs(" "); + } + if (WAITCORE(s)) + prs(" - core dumped"); + if (rv >= NSIGNAL || signame[rv]) + prs("\n"); + rv = -1; + } else + rv = WAITVAL(s); + } + } while (pid != lastpid); + heedint = oheedint; + if (intr) { + if (interactive) { + if (canintr) + intr = 0; + } else { + if (exstat == 0) + exstat = rv; + onintr(0); + } + } + return (rv); +} + +int setstatus(s) +register int s; +{ + exstat = s; + setval(lookup("?"), putn(s)); + return (s); +} + +/* + * PATH-searching interface to execve. + * If getenv("PATH") were kept up-to-date, + * execvp might be used. + */ +char *rexecve(c, v, envp) +char *c, **v, **envp; +{ + register int i; + register char *sp, *tp; + int eacces = 0, asis = 0; + +#ifdef BB_FEATURE_SH_STANDALONE_SHELL + char *name = c; +#ifdef BB_FEATURE_SH_APPLETS_ALWAYS_WIN + name = get_last_path_component(name); +#endif + optind = 1; + if (find_applet_by_name(name)) { + /* We have to exec here since we vforked. Running + * run_applet_by_name() won't work and bad things + * will happen. */ + execve("/proc/self/exe", v, envp); + execve("busybox", v, envp); + } +#endif + + sp = any('/', c)? "": path->value; + asis = *sp == '\0'; + while (asis || *sp != '\0') { + asis = 0; + tp = e.linep; + for (; *sp != '\0'; tp++) + if ((*tp = *sp++) == ':') { + asis = *sp == '\0'; + break; + } + if (tp != e.linep) + *tp++ = '/'; + for (i = 0; (*tp++ = c[i++]) != '\0';); + execve(e.linep, v, envp); + switch (errno) { + case ENOEXEC: + *v = e.linep; + tp = *--v; + *v = e.linep; + execve("/bin/sh", v, envp); + *v = tp; + return ("no Shell"); + + case ENOMEM: + return ("program too big"); + + case E2BIG: + return ("argument list too long"); + + case EACCES: + eacces++; + break; + } + } + return (errno == ENOENT ? "not found" : "cannot execute"); +} + +/* + * Run the command produced by generator `f' + * applied to stream `arg'. + */ +int run(argp, f) +struct ioarg *argp; +int (*f) (); +{ + struct op *otree; + struct wdblock *swdlist; + struct wdblock *siolist; + jmp_buf ev, rt; + xint *ofail; + int rv; + +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &rv; +#endif + areanum++; + swdlist = wdlist; + siolist = iolist; + otree = outtree; + ofail = failpt; + rv = -1; + if (newenv(setjmp(errpt = ev)) == 0) { + wdlist = 0; + iolist = 0; + pushio(argp, f); + e.iobase = e.iop; + yynerrs = 0; + if (setjmp(failpt = rt) == 0 && yyparse() == 0) + rv = execute(outtree, NOPIPE, NOPIPE, 0); + quitenv(); + } + wdlist = swdlist; + iolist = siolist; + failpt = ofail; + outtree = otree; + freearea(areanum--); + return (rv); +} + +/* -------- do.c -------- */ + +/* + * built-in commands: doX + */ + +static int +dolabel() +{ + return (0); +} + +static int +dochdir(t) +register struct op *t; +{ + register char *cp, *er; + + if ((cp = t->words[1]) == NULL && (cp = homedir->value) == NULL) + er = ": no home directory"; + else if (chdir(cp) < 0) + er = ": bad directory"; + else { +#ifdef TEST_NEW_VERSION +#ifdef BB_FEATURE_SH_FANCY_PROMPT + char *cated = NULL; + + if (*cp != '/') + cp = cated = concat_path_file(cwd, cp); + if (cwd != unknown) + free(cwd); + cwd = simplify_path(cp); + free(cated); +#endif +#endif + return (0); + } + prs(cp != NULL ? cp : "cd"); + err(er); + return (1); +} + +int doshift(t) +register struct op *t; +{ + int n; + + n = t->words[1] ? getn(t->words[1]) : 1; + if (dolc < n) { + err("nothing to shift"); + return (1); + } + dolv[n] = dolv[0]; + dolv += n; + dolc -= n; + setval(lookup("#"), putn(dolc)); + return (0); +} + +/* + * execute login and newgrp directly + */ +int dologin(t) +struct op *t; +{ + register char *cp; + + if (interactive) { + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + } + cp = rexecve(t->words[0], t->words, makenv(0)); + prs(t->words[0]); + prs(": "); + err(cp); + return (1); +} + +int doumask(t) +register struct op *t; +{ + register int i, n; + register char *cp; + + if ((cp = t->words[1]) == NULL) { + i = umask(0); + umask(i); + for (n = 3 * 4; (n -= 3) >= 0;) + put1c('0' + ((i >> n) & 07)); + put1c('\n'); + } else { + for (n = 0; *cp >= '0' && *cp <= '9'; cp++) + n = n * 8 + (*cp - '0'); + umask(n); + } + return (0); +} + +int doexec(t) +register struct op *t; +{ + int i; + jmp_buf ex; + xint *ofail; + + t->ioact = NULL; + for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++); + if (i == 0) + return (1); + execflg = 1; + ofail = failpt; + if (setjmp(failpt = ex) == 0) + execute(t, NOPIPE, NOPIPE, FEXEC); + failpt = ofail; + execflg = 0; + return (1); +} + +int dodot(t) +struct op *t; +{ + int i; + register char *sp, *tp; + char *cp; + + if ((cp = t->words[1]) == NULL) + return (0); + sp = any('/', cp) ? ":" : path->value; + while (*sp) { + tp = e.linep; + while (*sp && (*tp = *sp++) != ':') + tp++; + if (tp != e.linep) + *tp++ = '/'; + for (i = 0; (*tp++ = cp[i++]) != '\0';); + if ((i = open(e.linep, 0)) >= 0) { + exstat = 0; + next(remap(i)); + return (exstat); + } + } + prs(cp); + err(": not found"); + return (-1); +} + +int dowait(t) +struct op *t; +{ + int i; + register char *cp; + + if ((cp = t->words[1]) != NULL) { + i = getn(cp); + if (i == 0) + return (0); + } else + i = -1; + setstatus(waitfor(i, 1)); + return (0); +} + +int doread(t) +struct op *t; +{ + register char *cp, **wp; + int nb = 0; + register int nl = 0; + + if (t->words[1] == NULL) { + err("Usage: read name ..."); + return (1); + } + for (wp = t->words + 1; *wp; wp++) { + for (cp = e.linep; !nl && cp < elinep - 1; cp++) + if ((nb = read(0, cp, sizeof(*cp))) != sizeof(*cp) || + (nl = (*cp == '\n')) || (wp[1] && any(*cp, ifs->value))) + break; + *cp = 0; + if (nb <= 0) + break; + setval(lookup(*wp), e.linep); + } + return (nb <= 0); +} + +int doeval(t) +register struct op *t; +{ + return (RUN(awordlist, t->words + 1, wdchar)); +} + +int dotrap(t) +register struct op *t; +{ + register int n, i; + register int resetsig; + + if (t->words[1] == NULL) { + for (i = 0; i <= _NSIG; i++) + if (trap[i]) { + prn(i); + prs(": "); + prs(trap[i]); + prs("\n"); + } + return (0); + } + resetsig = digit(*t->words[1]); + for (i = resetsig ? 1 : 2; t->words[i] != NULL; ++i) { + n = getsig(t->words[i]); + freecell(trap[n]); + trap[n] = 0; + if (!resetsig) { + if (*t->words[1] != '\0') { + trap[n] = strsave(t->words[1], 0); + setsig(n, sig); + } else + setsig(n, SIG_IGN); + } else { + if (interactive) + if (n == SIGINT) + setsig(n, onintr); + else + setsig(n, n == SIGQUIT ? SIG_IGN : SIG_DFL); + else + setsig(n, SIG_DFL); + } + } + return (0); +} + +int getsig(s) +char *s; +{ + register int n; + + if ((n = getn(s)) < 0 || n > _NSIG) { + err("trap: bad signal number"); + n = 0; + } + return (n); +} + +void setsig(n, f) +int n; +void (*f) (int); +{ + if (n == 0) + return; + if (signal(n, SIG_IGN) != SIG_IGN || ourtrap[n]) { + ourtrap[n] = 1; + signal(n, f); + } +} + +int getn(as) +char *as; +{ + register char *s; + int n, m; + + s = as; + m = 1; + if (*s == '-') { + m = -1; + s++; + } + for (n = 0; digit(*s); s++) + n = (n * 10) + (*s - '0'); + if (*s) { + prs(as); + err(": bad number"); + } + return (n * m); +} + +int dobreak(t) +struct op *t; +{ + return (brkcontin(t->words[1], 1)); +} + +int docontinue(t) +struct op *t; +{ + return (brkcontin(t->words[1], 0)); +} + +static int brkcontin(cp, val) +register char *cp; +int val; +{ + register struct brkcon *bc; + int nl; + + nl = cp == NULL ? 1 : getn(cp); + if (nl <= 0) + nl = 999; + do { + if ((bc = brklist) == NULL) + break; + brklist = bc->nextlev; + } while (--nl); + if (nl) { + err("bad break/continue level"); + return (1); + } + isbreak = val; + longjmp(bc->brkpt, 1); + /* NOTREACHED */ +} + +int doexit(t) +struct op *t; +{ + register char *cp; + + execflg = 0; + if ((cp = t->words[1]) != NULL) + setstatus(getn(cp)); + leave(); + /* NOTREACHED */ +} + +int doexport(t) +struct op *t; +{ + rdexp(t->words + 1, export, EXPORT); + return (0); +} + +int doreadonly(t) +struct op *t; +{ + rdexp(t->words + 1, ronly, RONLY); + return (0); +} + +static void rdexp(wp, f, key) +register char **wp; +void (*f) (); +int key; +{ + if (*wp != NULL) { + for (; *wp != NULL; wp++) + if (checkname(*wp)) + (*f) (lookup(*wp)); + else + badid(*wp); + } else + putvlist(key, 1); +} + +static void badid(s) +register char *s; +{ + prs(s); + err(": bad identifier"); +} + +int doset(t) +register struct op *t; +{ + register struct var *vp; + register char *cp; + int n; + + if ((cp = t->words[1]) == NULL) { + for (vp = vlist; vp; vp = vp->next) + varput(vp->name, 1); + return (0); + } + if (*cp == '-') { + /* bad: t->words++; */ + for (n = 0; (t->words[n] = t->words[n + 1]) != NULL; n++); + if (*++cp == 0) + flag['x'] = flag['v'] = 0; + else + for (; *cp; cp++) + switch (*cp) { + case 'e': + if (!interactive) + flag['e']++; + break; + + default: + if (*cp >= 'a' && *cp <= 'z') + flag[(int) *cp]++; + break; + } + setdash(); + } + if (t->words[1]) { + t->words[0] = dolv[0]; + for (n = 1; t->words[n]; n++) + setarea((char *) t->words[n], 0); + dolc = n - 1; + dolv = t->words; + setval(lookup("#"), putn(dolc)); + setarea((char *) (dolv - 1), 0); + } + return (0); +} + +void varput(s, out) +register char *s; +int out; +{ + if (letnum(*s)) { + write(out, s, strlen(s)); + write(out, "\n", 1); + } +} + + +#define SECS 60L +#define MINS 3600L + +int dotimes() +{ + struct tms tbuf; + + times(&tbuf); + + prn((int) (tbuf.tms_cutime / MINS)); + prs("m"); + prn((int) ((tbuf.tms_cutime % MINS) / SECS)); + prs("s "); + prn((int) (tbuf.tms_cstime / MINS)); + prs("m"); + prn((int) ((tbuf.tms_cstime % MINS) / SECS)); + prs("s\n"); + return (0); +} + +struct builtin { + char *command; + int (*fn) (); +}; +static struct builtin builtin[] = { + {":", dolabel}, + {"cd", dochdir}, + {"shift", doshift}, + {"exec", doexec}, + {"wait", dowait}, + {"read", doread}, + {"eval", doeval}, + {"trap", dotrap}, + {"break", dobreak}, + {"continue", docontinue}, + {"exit", doexit}, + {"export", doexport}, + {"readonly", doreadonly}, + {"set", doset}, + {".", dodot}, + {"umask", doumask}, + {"login", dologin}, + {"newgrp", dologin}, + {"times", dotimes}, + {0, 0} +}; + +int (*inbuilt(s)) () +register char *s; +{ + register struct builtin *bp; + + for (bp = builtin; bp->command != NULL; bp++) + if (strcmp(bp->command, s) == 0) + return (bp->fn); + return ((int (*)()) NULL); +} + + +/* -------- eval.c -------- */ + +/* + * ${} + * `command` + * blank interpretation + * quoting + * glob + */ + +static int expand(char *cp, struct wdblock **wbp, int f); +static char *blank(int f); +static int dollar(int quoted); +static int grave(int quoted); +static void globname(char *we, char *pp); +static char *generate(char *start1, char *end1, char *middle, char *end); +static int anyspcl(struct wdblock *wb); +static int xstrcmp(char *p1, char *p2); +static void glob0(char *a0, unsigned int a1, int a2, + int (*a3) (char *, char *)); +static void glob1(char *base, char *lim); +static void glob2(char *i, char *j); +static void glob3(char *i, char *j, char *k); + + +char **eval(ap, f) +char **ap; +int f; +{ + struct wdblock *wb; + char **wp; + char **wf; + jmp_buf ev; + +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) ℘ + (void) ≈ +#endif + + wp = NULL; + wb = NULL; + wf = NULL; + if (newenv(setjmp(errpt = ev)) == 0) { + while (*ap && isassign(*ap)) + expand(*ap++, &wb, f & ~DOGLOB); + if (flag['k']) { + for (wf = ap; *wf; wf++) { + if (isassign(*wf)) + expand(*wf, &wb, f & ~DOGLOB); + } + } + for (wb = addword((char *) 0, wb); *ap; ap++) { + if (!flag['k'] || !isassign(*ap)) + expand(*ap, &wb, f & ~DOKEY); + } + wb = addword((char *) 0, wb); + wp = getwords(wb); + quitenv(); + } else + gflg = 1; + return (gflg ? (char **) NULL : wp); +} + +/* + * Make the exported environment from the exported + * names in the dictionary. Keyword assignments + * will already have been done. + */ +char **makenv(int all) +{ + register struct wdblock *wb; + register struct var *vp; + + wb = NULL; + for (vp = vlist; vp; vp = vp->next) + if (all || vp->status & EXPORT) + wb = addword(vp->name, wb); + wb = addword((char *) 0, wb); + return (getwords(wb)); +} + +char *evalstr(cp, f) +char *cp; +int f; +{ + struct wdblock *wb; + +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &cp; +#endif + + wb = NULL; + if (expand(cp, &wb, f)) { + if (wb == NULL || wb->w_nword == 0 + || (cp = wb->w_words[0]) == NULL) + cp = ""; + freecell(wb); + } else + cp = NULL; + return (cp); +} + +static int expand(cp, wbp, f) +char *cp; +register struct wdblock **wbp; +int f; +{ + jmp_buf ev; + +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &cp; +#endif + + gflg = 0; + if (cp == NULL) + return (0); + if (!anys("$`'\"", cp) && + !anys(ifs->value, cp) && ((f & DOGLOB) == 0 || !anys("[*?", cp))) { + cp = strsave(cp, areanum); + if (f & DOTRIM) + unquote(cp); + *wbp = addword(cp, *wbp); + return (1); + } + if (newenv(setjmp(errpt = ev)) == 0) { + PUSHIO(aword, cp, strchar); + e.iobase = e.iop; + while ((cp = blank(f)) && gflg == 0) { + e.linep = cp; + cp = strsave(cp, areanum); + if ((f & DOGLOB) == 0) { + if (f & DOTRIM) + unquote(cp); + *wbp = addword(cp, *wbp); + } else + *wbp = glob(cp, *wbp); + } + quitenv(); + } else + gflg = 1; + return (gflg == 0); +} + +/* + * Blank interpretation and quoting + */ +static char *blank(f) +int f; +{ + int c, c1; + register char *sp; + int scanequals, foundequals; + + sp = e.linep; + scanequals = f & DOKEY; + foundequals = 0; + + loop: + switch (c = subgetc('"', foundequals)) { + case 0: + if (sp == e.linep) + return (0); + *e.linep++ = 0; + return (sp); + + default: + if (f & DOBLANK && any(c, ifs->value)) + goto loop; + break; + + case '"': + case '\'': + scanequals = 0; + if (INSUB()) + break; + for (c1 = c; (c = subgetc(c1, 1)) != c1;) { + if (c == 0) + break; + if (c == '\'' || !any(c, "$`\"")) + c |= QUOTE; + *e.linep++ = c; + } + c = 0; + } + unget(c); + if (!letter(c)) + scanequals = 0; + for (;;) { + c = subgetc('"', foundequals); + if (c == 0 || + (f & DOBLANK && any(c, ifs->value)) || + (!INSUB() && any(c, "\"'"))) { + scanequals = 0; + unget(c); + if (any(c, "\"'")) + goto loop; + break; + } + if (scanequals) { + if (c == '=') { + foundequals = 1; + scanequals = 0; + } else if (!letnum(c)) + scanequals = 0; + } + *e.linep++ = c; + } + *e.linep++ = 0; + return (sp); +} + +/* + * Get characters, substituting for ` and $ + */ +int subgetc(ec, quoted) +register char ec; +int quoted; +{ + register char c; + + again: + c = getqc(ec); + if (!INSUB() && ec != '\'') { + if (c == '`') { + if (grave(quoted) == 0) + return (0); + e.iop->task = XGRAVE; + goto again; + } + if (c == '$' && (c = dollar(quoted)) == 0) { + e.iop->task = XDOLL; + goto again; + } + } + return (c); +} + +/* + * Prepare to generate the string returned by ${} substitution. + */ +static int dollar(quoted) +int quoted; +{ + int otask; + struct io *oiop; + char *dolp; + register char *s, c, *cp; + struct var *vp; + + c = readc(); + s = e.linep; + if (c != '{') { + *e.linep++ = c; + if (letter(c)) { + while ((c = readc()) != 0 && letnum(c)) + if (e.linep < elinep) + *e.linep++ = c; + unget(c); + } + c = 0; + } else { + oiop = e.iop; + otask = e.iop->task; + e.iop->task = XOTHER; + while ((c = subgetc('"', 0)) != 0 && c != '}' && c != '\n') + if (e.linep < elinep) + *e.linep++ = c; + if (oiop == e.iop) + e.iop->task = otask; + if (c != '}') { + err("unclosed ${"); + gflg++; + return (c); + } + } + if (e.linep >= elinep) { + err("string in ${} too long"); + gflg++; + e.linep -= 10; + } + *e.linep = 0; + if (*s) { + for (cp = s + 1; *cp; cp++) + if (any(*cp, "=-+?")) { + c = *cp; + *cp++ = 0; + break; + } + } else { + cp = s; + } + if (s[1] == 0 && (*s == '*' || *s == '@')) { + if (dolc > 1) { + /* currently this does not distinguish $* and $@ */ + /* should check dollar */ + e.linep = s; + PUSHIO(awordlist, dolv + 1, dolchar); + return (0); + } else { /* trap the nasty ${=} */ + s[0] = '1'; + s[1] = 0; + } + } + e.linep = s; + vp = lookup(s); + if ((dolp = vp->value) == null) { + switch (c) { + case '=': + if (digit(*s)) { + err("cannot use ${...=...} with $n"); + gflg++; + break; + } + cp = evalstr(strsave(cp, areanum), DOSUB); + setval(vp, cp); + dolp = vp->value; + break; + + case '-': + dolp = evalstr(strsave(cp, areanum), DOSUB); + break; + + case '?': + if (*cp == 0) { + prs("missing value for "); + err(s); + } else + err(evalstr(strsave(cp, areanum), DOSUB)); + gflg++; + break; + } + } else if (c == '+') { + dolp = evalstr(strsave(cp, areanum), DOSUB); + } + if (flag['u'] && dolp == null) { + prs("unset variable: "); + err(s); + gflg++; + } + PUSHIO(aword, dolp, quoted ? qstrchar : strchar); + return (0); +} + +/* + * Run the command in `...` and read its output. + */ +static int grave(quoted) +int quoted; +{ + int otask; + struct io *oiop; + register char *cp, *s; + register int i, c; + int pf[2]; +#ifndef USE_FORK + char *av[4]; + char **env; +#endif + + c = readc(); + s = e.linep; + *e.linep++ = c; + oiop = e.iop; + otask = e.iop->task; + e.iop->task = XOTHER; + while ((c = subgetc('\'', 0)) != 0 && c != '`') + if (e.linep < elinep) + *e.linep++ = c; + if (oiop == e.iop) + e.iop->task = otask; + if (c != '`') { + err("no closing `"); + return (0); + } + if (openpipe(pf) < 0) + return (0); +#ifndef USE_FORK + env = makenv(1); +#endif + if ((i = XFORK()) == -1) { + closepipe(pf); + err("try again"); + return (0); + } + if (i != 0) { + e.linep = s; + close(pf[1]); + PUSHIO(afile, remap(pf[0]), quoted ? qgravechar : gravechar); + return (1); + } + *e.linep = 0; + /* allow trapped signals */ + for (i = 0; i <= _NSIG; i++) + if (ourtrap[i] && signal(i, SIG_IGN) != SIG_IGN) + signal(i, SIG_DFL); + dup2(pf[1], 1); + closepipe(pf); + cp = strsave(e.linep = s, 0); +#ifdef USE_FORK + flag['e'] = 0; + flag['v'] = 0; + flag['n'] = 0; + areanum = 1; + inhere = acthere = (struct here *) 0; + freearea(areanum); /* free old space */ + e.oenv = NULL; + e.iop = (e.iobase = iostack) - 1; + unquote(cp); + interactive = 0; + PUSHIO(aword, cp, nlchar); + onecommand(); + exit(1); +#else + /* NOTE: When we are vfork()'ing we've got to exec here. + * Therefore we start the command using /bin/sh -c. + */ + av[0] = "sh"; + av[1] = "-c"; + av[2] = cp; + av[3] = NULL; + execve("/bin/sh", av, env); + err("grave: execlp failed\n"); + _exit(1); +#endif +} + +char *unquote(as) +register char *as; +{ + register char *s; + + if ((s = as) != NULL) + while (*s) + *s++ &= ~QUOTE; + return (as); +} + +/* -------- glob.c -------- */ + +/* + * glob + */ + +#define scopy(x) strsave((x), areanum) +#define BLKSIZ 512 + + +static struct wdblock *cl, *nl; +static char spcl[] = "[?*"; + +struct wdblock *glob(cp, wb) +char *cp; +struct wdblock *wb; +{ + int i; + register char *pp; + + if (cp == 0) + return (wb); + i = 0; + for (pp = cp; *pp; pp++) + if (any(*pp, spcl)) + i++; + else if (!any(*pp & ~QUOTE, spcl)) + *pp &= ~QUOTE; + if (i != 0) { + for (cl = addword(scopy(cp), (struct wdblock *) 0); anyspcl(cl); + cl = nl) { + nl = newword(cl->w_nword * 2); + for (i = 0; i < cl->w_nword; i++) { /* for each argument */ + for (pp = cl->w_words[i]; *pp; pp++) + if (any(*pp, spcl)) { + globname(cl->w_words[i], pp); + break; + } + if (*pp == '\0') + nl = addword(scopy(cl->w_words[i]), nl); + } + for (i = 0; i < cl->w_nword; i++) + freecell(cl->w_words[i]); + freecell(cl); + } + for (i = 0; i < cl->w_nword; i++) + unquote(cl->w_words[i]); + glob0((char *) cl->w_words, cl->w_nword, sizeof(char *), xstrcmp); + if (cl->w_nword) { + for (i = 0; i < cl->w_nword; i++) + wb = addword(cl->w_words[i], wb); + freecell(cl); + return (wb); + } + } + wb = addword(unquote(cp), wb); + return (wb); +} + +void globname(we, pp) +char *we; +register char *pp; +{ + register char *np, *cp; + char *name, *gp, *dp; + int k; + DIR *dirp; + struct dirent *de; + char dname[NAME_MAX + 1]; + struct stat dbuf; + + for (np = we; np != pp; pp--) + if (pp[-1] == '/') + break; + for (dp = cp = space((int) (pp - np) + 3); np < pp;) + *cp++ = *np++; + *cp++ = '.'; + *cp = '\0'; + for (gp = cp = space(strlen(pp) + 1); *np && *np != '/';) + *cp++ = *np++; + *cp = '\0'; + dirp = opendir(dp); + if (dirp == 0) { + freecell(dp); + freecell(gp); + return; + } + dname[NAME_MAX] = '\0'; + while ((de = readdir(dirp)) != NULL) { + strncpy(dname, de->d_name, NAME_MAX); + if (dname[0] == '.') + if (*gp != '.') + continue; + for (k = 0; k < NAME_MAX; k++) + if (any(dname[k], spcl)) + dname[k] |= QUOTE; + if (gmatch(dname, gp)) { + name = generate(we, pp, dname, np); + if (*np && !anys(np, spcl)) { + if (stat(name, &dbuf)) { + freecell(name); + continue; + } + } + nl = addword(name, nl); + } + } + closedir(dirp); + freecell(dp); + freecell(gp); +} + +/* + * generate a pathname as below. + * start..end1 / middle end + * the slashes come for free + */ +static char *generate(start1, end1, middle, end) +char *start1; +register char *end1; +char *middle, *end; +{ + char *p; + register char *op, *xp; + + p = op = + space((int) (end1 - start1) + strlen(middle) + strlen(end) + 2); + for (xp = start1; xp != end1;) + *op++ = *xp++; + for (xp = middle; (*op++ = *xp++) != '\0';); + op--; + for (xp = end; (*op++ = *xp++) != '\0';); + return (p); +} + +static int anyspcl(wb) +register struct wdblock *wb; +{ + int i; + register char **wd; + + wd = wb->w_words; + for (i = 0; i < wb->w_nword; i++) + if (anys(spcl, *wd++)) + return (1); + return (0); +} + +static int xstrcmp(p1, p2) +char *p1, *p2; +{ + return (strcmp(*(char **) p1, *(char **) p2)); +} + +/* -------- word.c -------- */ + +#define NSTART 16 /* default number of words to allow for initially */ + +struct wdblock *newword(nw) +register int nw; +{ + register struct wdblock *wb; + + wb = (struct wdblock *) space(sizeof(*wb) + nw * sizeof(char *)); + wb->w_bsize = nw; + wb->w_nword = 0; + return (wb); +} + +struct wdblock *addword(wd, wb) +char *wd; +register struct wdblock *wb; +{ + register struct wdblock *wb2; + int nw; + + if (wb == NULL) + wb = newword(NSTART); + if ((nw = wb->w_nword) >= wb->w_bsize) { + wb2 = newword(nw * 2); + memcpy(wb2->w_words, wb->w_words, nw * sizeof(char *)); + wb2->w_nword = nw; + freecell(wb); + wb = wb2; + } + wb->w_words[wb->w_nword++] = wd; + return (wb); +} + +char **getwords(wb) +register struct wdblock *wb; +{ + register char **wd; + int nb; + + if (wb == NULL) + return ((char **) NULL); + if (wb->w_nword == 0) { + freecell(wb); + return ((char **) NULL); + } + wd = (char **) space(nb = sizeof(*wd) * wb->w_nword); + memcpy(wd, wb->w_words, nb); + freecell(wb); /* perhaps should done by caller */ + return (wd); +} + +static int (*func) (char *, char *); +static int globv; + +void glob0(a0, a1, a2, a3) +char *a0; +unsigned a1; +int a2; +int (*a3) (char *, char *); +{ + func = a3; + globv = a2; + glob1(a0, a0 + a1 * a2); +} + +void glob1(base, lim) +char *base, *lim; +{ + register char *i, *j; + int v2; + char *lptr, *hptr; + int c; + unsigned n; + + + v2 = globv; + + top: + if ((n = (int) (lim - base)) <= v2) + return; + n = v2 * (n / (2 * v2)); + hptr = lptr = base + n; + i = base; + j = lim - v2; + for (;;) { + if (i < lptr) { + if ((c = (*func) (i, lptr)) == 0) { + glob2(i, lptr -= v2); + continue; + } + if (c < 0) { + i += v2; + continue; + } + } + + begin: + if (j > hptr) { + if ((c = (*func) (hptr, j)) == 0) { + glob2(hptr += v2, j); + goto begin; + } + if (c > 0) { + if (i == lptr) { + glob3(i, hptr += v2, j); + i = lptr += v2; + goto begin; + } + glob2(i, j); + j -= v2; + i += v2; + continue; + } + j -= v2; + goto begin; + } + + + if (i == lptr) { + if (lptr - base >= lim - hptr) { + glob1(hptr + v2, lim); + lim = lptr; + } else { + glob1(base, lptr); + base = hptr + v2; + } + goto top; + } + + + glob3(j, lptr -= v2, i); + j = hptr -= v2; + } +} + +void glob2(i, j) +char *i, *j; +{ + register char *index1, *index2, c; + int m; + + m = globv; + index1 = i; + index2 = j; + do { + c = *index1; + *index1++ = *index2; + *index2++ = c; + } while (--m); +} + +void glob3(i, j, k) +char *i, *j, *k; +{ + register char *index1, *index2, *index3; + int c; + int m; + + m = globv; + index1 = i; + index2 = j; + index3 = k; + do { + c = *index1; + *index1++ = *index3; + *index3++ = *index2; + *index2++ = c; + } while (--m); +} + +/* -------- io.c -------- */ + +/* + * shell IO + */ + +static struct iobuf sharedbuf = { AFID_NOBUF }; +static struct iobuf mainbuf = { AFID_NOBUF }; +static unsigned bufid = AFID_ID; /* buffer id counter */ + + +static void readhere(char **name, char *s, int ec); +static void pushio(struct ioarg *argp, int (*fn) ()); +static int xxchar(struct ioarg *ap); +static void tempname(char *tname); + +int getqc(ec) +register int ec; +{ + register int c; + + if (e.linep > elinep) { + while ((c = readc()) != '\n' && c); + err("input line too long"); + gflg++; + return (c); + } + c = readc(); + if (ec != '\'' && e.iop->task != XGRAVE) { + if (c == '\\') { + c = readc(); + if (c == '\n' && ec != '\"') + return (getqc(ec)); + c |= QUOTE; + } + } + return (c); +} + +void unget(c) +int c; +{ + if (e.iop >= e.iobase) + e.iop->peekc = c; +} + +int eofc() +{ + return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0); +} + +int readc() +{ + int c; + + for (; e.iop >= e.iobase; e.iop--) + if ((c = e.iop->peekc) != '\0') { + e.iop->peekc = 0; + return (c); + } else { + if (e.iop->prev != 0) { + if ((c = (*e.iop->iofn) (e.iop->argp, e.iop)) != '\0') { + if (c == -1) { + e.iop++; + continue; + } + if (e.iop == iostack) + ioecho(c); + return (e.iop->prev = c); + } else if (e.iop->task == XIO && e.iop->prev != '\n') { + e.iop->prev = 0; + if (e.iop == iostack) + ioecho('\n'); + return '\n'; + } + } + if (e.iop->task == XIO) { + if (multiline) + return e.iop->prev = 0; + if (interactive && e.iop == iostack + 1) +#ifdef BB_FEATURE_COMMAND_EDITING + current_prompt = prompt->value; +#else + prs(prompt->value); +#endif + } + } + if (e.iop >= iostack) + return (0); + leave(); + /* NOTREACHED */ +} + +void ioecho(c) +char c; +{ + if (flag['v']) + write(2, &c, sizeof c); +} + +void pushio(argp, fn) +struct ioarg *argp; +int (*fn) (); +{ + if (++e.iop >= &iostack[NPUSH]) { + e.iop--; + err("Shell input nested too deeply"); + gflg++; + return; + } + e.iop->iofn = fn; + + if (argp->afid != AFID_NOBUF) + e.iop->argp = argp; + else { + e.iop->argp = ioargstack + (e.iop - iostack); + *e.iop->argp = *argp; + e.iop->argp->afbuf = e.iop == &iostack[0] ? &mainbuf : &sharedbuf; + if (isatty(e.iop->argp->afile) == 0 && + (e.iop == &iostack[0] || + lseek(e.iop->argp->afile, 0L, 1) != -1)) { + if (++bufid == AFID_NOBUF) + bufid = AFID_ID; + e.iop->argp->afid = bufid; + } + } + + e.iop->prev = ~'\n'; + e.iop->peekc = 0; + e.iop->xchar = 0; + e.iop->nlcount = 0; + if (fn == filechar || fn == linechar) + e.iop->task = XIO; + else if (fn == gravechar || fn == qgravechar) + e.iop->task = XGRAVE; + else + e.iop->task = XOTHER; +} + +struct io *setbase(ip) +struct io *ip; +{ + register struct io *xp; + + xp = e.iobase; + e.iobase = ip; + return (xp); +} + +/* + * Input generating functions + */ + +/* + * Produce the characters of a string, then a newline, then EOF. + */ +int nlchar(ap) +register struct ioarg *ap; +{ + register int c; + + if (ap->aword == NULL) + return (0); + if ((c = *ap->aword++) == 0) { + ap->aword = NULL; + return ('\n'); + } + return (c); +} + +/* + * Given a list of words, produce the characters + * in them, with a space after each word. + */ +int wdchar(ap) +register struct ioarg *ap; +{ + register char c; + register char **wl; + + if ((wl = ap->awordlist) == NULL) + return (0); + if (*wl != NULL) { + if ((c = *(*wl)++) != 0) + return (c & 0177); + ap->awordlist++; + return (' '); + } + ap->awordlist = NULL; + return ('\n'); +} + +/* + * Return the characters of a list of words, + * producing a space between them. + */ +int dolchar(ap) +register struct ioarg *ap; +{ + register char *wp; + + if ((wp = *ap->awordlist++) != NULL) { + PUSHIO(aword, wp, *ap->awordlist == NULL ? strchar : xxchar); + return (-1); + } + return (0); +} + +static int xxchar(ap) +register struct ioarg *ap; +{ + register int c; + + if (ap->aword == NULL) + return (0); + if ((c = *ap->aword++) == '\0') { + ap->aword = NULL; + return (' '); + } + return (c); +} + +/* + * Produce the characters from a single word (string). + */ +int strchar(ap) +register struct ioarg *ap; +{ + register int c; + + if (ap->aword == NULL || (c = *ap->aword++) == 0) + return (0); + return (c); +} + +/* + * Produce quoted characters from a single word (string). + */ +int qstrchar(ap) +register struct ioarg *ap; +{ + register int c; + + if (ap->aword == NULL || (c = *ap->aword++) == 0) + return (0); + return (c | QUOTE); +} + +/* + * Return the characters from a file. + */ +int filechar(ap) +register struct ioarg *ap; +{ + register int i; + char c; + struct iobuf *bp = ap->afbuf; + + if (ap->afid != AFID_NOBUF) { + if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) { + if (i) + lseek(ap->afile, ap->afpos, 0); + i = safe_read(ap->afile, bp->buf, sizeof(bp->buf)); + if (i <= 0) { + closef(ap->afile); + return 0; + } + bp->id = ap->afid; + bp->ebufp = (bp->bufp = bp->buf) + i; + } + ap->afpos++; + return *bp->bufp++ & 0177; + } +#ifdef BB_FEATURE_COMMAND_EDITING + if (interactive && ap->afile == 0) { + static char mycommand[BUFSIZ]; + static int position = 0, size = 0; + + while (size == 0 || position >= size) { + size = cmdedit_read_input(current_prompt, mycommand); + position = 0; + } + c = mycommand[position]; + position++; + return (c); + } else +#endif + { + i = safe_read(ap->afile, &c, sizeof(c)); + return (i == sizeof(c) ? c & 0177 : (closef(ap->afile), 0)); + } +} + +/* + * Return the characters from a here temp file. + */ +int herechar(ap) +register struct ioarg *ap; +{ + char c; + + + if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) { + close(ap->afile); + c = 0; + } + return (c); + +} + +/* + * Return the characters produced by a process (`...`). + * Quote them if required, and remove any trailing newline characters. + */ +int gravechar(ap, iop) +struct ioarg *ap; +struct io *iop; +{ + register int c; + + if ((c = qgravechar(ap, iop) & ~QUOTE) == '\n') + c = ' '; + return (c); +} + +int qgravechar(ap, iop) +register struct ioarg *ap; +struct io *iop; +{ + register int c; + + if (iop->xchar) { + if (iop->nlcount) { + iop->nlcount--; + return ('\n' | QUOTE); + } + c = iop->xchar; + iop->xchar = 0; + } else if ((c = filechar(ap)) == '\n') { + iop->nlcount = 1; + while ((c = filechar(ap)) == '\n') + iop->nlcount++; + iop->xchar = c; + if (c == 0) + return (c); + iop->nlcount--; + c = '\n'; + } + return (c != 0 ? c | QUOTE : 0); +} + +/* + * Return a single command (usually the first line) from a file. + */ +int linechar(ap) +register struct ioarg *ap; +{ + register int c; + + if ((c = filechar(ap)) == '\n') { + if (!multiline) { + closef(ap->afile); + ap->afile = -1; /* illegal value */ + } + } + return (c); +} + +void prs(s) +register char *s; +{ + fputs(s, stderr); +} + +void put1c(c) +char c; +{ + putc(c, stderr); +} + +void prn(u) +unsigned u; +{ + prs(itoa(u, 0)); +} + +void closef(i) +register int i; +{ + if (i > 2) + close(i); +} + +void closeall() +{ + int u; + + for (u = NUFILE; u < NOFILE;) + close(u++); +} + +/* + * remap fd into Shell's fd space + */ +int remap(fd) +register int fd; +{ + register int i; + int map[NOFILE]; + + if (fd < e.iofd) { + for (i = 0; i < NOFILE; i++) + map[i] = 0; + do { + map[fd] = 1; + fd = dup(fd); + } while (fd >= 0 && fd < e.iofd); + for (i = 0; i < NOFILE; i++) + if (map[i]) + close(i); + if (fd < 0) + err("too many files open in shell"); + } + return (fd); +} + +int openpipe(pv) +register int *pv; +{ + register int i; + + if ((i = pipe(pv)) < 0) + err("can't create pipe - try again"); + return (i); +} + +void closepipe(pv) +register int *pv; +{ + if (pv != NULL) { + close(*pv++); + close(*pv); + } +} + +/* -------- here.c -------- */ + +/* + * here documents + */ + +void markhere(s, iop) +register char *s; +struct ioword *iop; +{ + register struct here *h, *lh; + + h = (struct here *) space(sizeof(struct here)); + if (h == 0) + return; + h->h_tag = evalstr(s, DOSUB); + if (h->h_tag == 0) + return; + h->h_iop = iop; + iop->io_name = 0; + h->h_next = NULL; + if (inhere == 0) + inhere = h; + else + for (lh = inhere; lh != NULL; lh = lh->h_next) + if (lh->h_next == 0) { + lh->h_next = h; + break; + } + iop->io_flag |= IOHERE | IOXHERE; + for (s = h->h_tag; *s; s++) + if (*s & QUOTE) { + iop->io_flag &= ~IOXHERE; + *s &= ~QUOTE; + } + h->h_dosub = iop->io_flag & IOXHERE; +} + +void gethere() +{ + register struct here *h, *hp; + + /* Scan here files first leaving inhere list in place */ + for (hp = h = inhere; h != NULL; hp = h, h = h->h_next) + readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub ? 0 : '\''); + + /* Make inhere list active - keep list intact for scraphere */ + if (hp != NULL) { + hp->h_next = acthere; + acthere = inhere; + inhere = NULL; + } +} + +static void readhere(name, s, ec) +char **name; +register char *s; +int ec; +{ + int tf; + char tname[30]; + int c; + jmp_buf ev; + char read_line[LINELIM + 1]; + char *next_read_line; + +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &tf; +#endif + + tempname(tname); + *name = strsave(tname, areanum); + tf = creat(tname, 0600); + if (tf < 0) + return; + if (newenv(setjmp(errpt = ev)) != 0) + unlink(tname); + else { + pushio(e.iop->argp, e.iop->iofn); + e.iobase = e.iop; + for (;;) { + if (interactive && e.iop <= iostack) +#ifdef BB_FEATURE_COMMAND_EDITING + current_prompt = cprompt->value; +#else + prs(cprompt->value); +#endif + next_read_line = read_line; + while ((c = readc()) != '\n' && c) { + if (next_read_line >= &read_line[LINELIM]) { + c = 0; + break; + } + *next_read_line++ = c; + } + *next_read_line = 0; + if (strcmp(s, read_line) == 0 || c == 0) + break; + *next_read_line++ = '\n'; + write(tf, read_line, (int) (next_read_line - read_line)); + } + if (c == 0) { + prs("here document `"); + prs(s); + err("' unclosed"); + } + quitenv(); + } + close(tf); +} + +/* + * open here temp file. + * if unquoted here, expand here temp file into second temp file. + */ +int herein(hname, xdoll) +char *hname; +int xdoll; +{ + int hf, tf; + +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &tf; +#endif + + if (hname == 0) + return (-1); + hf = open(hname, 0); + if (hf < 0) + return (-1); + if (xdoll) { + char c; + char tname[30]; + jmp_buf ev; + + tempname(tname); + if ((tf = creat(tname, 0600)) < 0) + return (-1); + if (newenv(setjmp(errpt = ev)) == 0) { + PUSHIO(afile, hf, herechar); + setbase(e.iop); + while ((c = subgetc(0, 0)) != 0) { + char c1 = c & ~QUOTE; + + if (c & QUOTE && !any(c1, "`$\\")) + write(tf, "\\", 1); + write(tf, &c1, 1); + } + quitenv(); + } else + unlink(tname); + close(tf); + tf = open(tname, 0); + unlink(tname); + return (tf); + } else + return (hf); +} + +void scraphere() +{ + register struct here *h; + + for (h = inhere; h != NULL; h = h->h_next) { + if (h->h_iop && h->h_iop->io_name) + unlink(h->h_iop->io_name); + } + inhere = NULL; +} + +/* unlink here temp files before a freearea(area) */ +void freehere(area) +int area; +{ + register struct here *h, *hl; + + hl = NULL; + for (h = acthere; h != NULL; h = h->h_next) + if (getarea((char *) h) >= area) { + if (h->h_iop->io_name != NULL) + unlink(h->h_iop->io_name); + if (hl == NULL) + acthere = h->h_next; + else + hl->h_next = h->h_next; + } else + hl = h; +} + +void tempname(tname) +char *tname; +{ + static int inc; + register char *cp, *lp; + + for (cp = tname, lp = "/tmp/shtm"; (*cp = *lp++) != '\0'; cp++); + lp = putn(getpid() * 1000 + inc++); + for (; (*cp = *lp++) != '\0'; cp++); +} + +/* + * 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. + * + */ diff --git a/mt.c b/mt.c new file mode 100644 index 000000000..49dc70ac6 --- /dev/null +++ b/mt.c @@ -0,0 +1,121 @@ +/* vi: set sw=4 ts=4: */ +#include +#include +#include +#include +#include +#include "busybox.h" + +struct mt_opcodes { + char *name; + short value; +}; + +/* missing: eod/seod, stoptions, stwrthreshold, densities */ +static const struct mt_opcodes opcodes[] = { + {"bsf", MTBSF}, + {"bsfm", MTBSFM}, + {"bsr", MTBSR}, + {"bss", MTBSS}, + {"datacompression", MTCOMPRESSION}, + {"eom", MTEOM}, + {"erase", MTERASE}, + {"fsf", MTFSF}, + {"fsfm", MTFSFM}, + {"fsr", MTFSR}, + {"fss", MTFSS}, + {"load", MTLOAD}, + {"lock", MTLOCK}, + {"mkpart", MTMKPART}, + {"nop", MTNOP}, + {"offline", MTOFFL}, + {"rewoffline", MTOFFL}, + {"ras1", MTRAS1}, + {"ras2", MTRAS2}, + {"ras3", MTRAS3}, + {"reset", MTRESET}, + {"retension", MTRETEN}, + {"rewind", MTREW}, + {"seek", MTSEEK}, + {"setblk", MTSETBLK}, + {"setdensity", MTSETDENSITY}, + {"drvbuffer", MTSETDRVBUFFER}, + {"setpart", MTSETPART}, + {"tell", MTTELL}, + {"wset", MTWSM}, + {"unload", MTUNLOAD}, + {"unlock", MTUNLOCK}, + {"eof", MTWEOF}, + {"weof", MTWEOF}, + {0, 0} +}; + +extern int mt_main(int argc, char **argv) +{ + const char *file = "/dev/tape"; + const struct mt_opcodes *code = opcodes; + struct mtop op; + struct mtpos position; + int fd, mode; + + if (argc < 2) { + show_usage(); + } + + if (strcmp(argv[1], "-f") == 0) { + if (argc < 4) { + show_usage(); + } + file = argv[2]; + argv += 2; + argc -= 2; + } + + while (code->name != 0) { + if (strcmp(code->name, argv[1]) == 0) + break; + code++; + } + + if (code->name == 0) { + error_msg("unrecognized opcode %s.", argv[1]); + return EXIT_FAILURE; + } + + op.mt_op = code->value; + if (argc >= 3) + op.mt_count = atoi(argv[2]); + else + op.mt_count = 1; /* One, not zero, right? */ + + switch (code->value) { + case MTWEOF: + case MTERASE: + case MTWSM: + case MTSETDRVBUFFER: + mode = O_WRONLY; + break; + + default: + mode = O_RDONLY; + break; + } + + if ((fd = open(file, mode, 0)) < 0) + perror_msg_and_die("%s", file); + + switch (code->value) { + case MTTELL: + if (ioctl(fd, MTIOCPOS, &position) < 0) + perror_msg_and_die("%s", file); + printf ("At block %d.\n", (int) position.mt_blkno); + break; + + default: + if (ioctl(fd, MTIOCTOP, &op) != 0) + perror_msg_and_die("%s", file); + break; + } + + return EXIT_SUCCESS; +} diff --git a/mv.c b/mv.c new file mode 100644 index 000000000..b890abf6e --- /dev/null +++ b/mv.c @@ -0,0 +1,168 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini mv implementation for busybox + * + * + * Copyright (C) 2000 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 + * + */ + +#include +#include +#include +#include +#include +#include + +#include "busybox.h" + +static int flags; + +static int manual_rename(const char *source, const char *dest) +{ + struct stat source_stat; + struct stat dest_stat; + int source_exists = 1; + int dest_exists = 1; + + if (stat(source, &source_stat) < 0) { + if (errno != ENOENT) { + perror_msg("unable to stat `%s'", source); + return -1; + } + source_exists = 0; + } + + if (stat(dest, &dest_stat) < 0) { + if (errno != ENOENT) { + perror_msg("unable to stat `%s'", dest); + return -1; + } + dest_exists = 0; + } + + if (dest_exists) { + if (S_ISDIR(dest_stat.st_mode) && + (!source_exists || !S_ISDIR(source_stat.st_mode))) { + error_msg("cannot overwrite directory with non-directory"); + return -1; + } + + if (!S_ISDIR(dest_stat.st_mode) && source_exists && + S_ISDIR(source_stat.st_mode)) { + error_msg("cannot overwrite non-directory with directory"); + return -1; + } + + if (unlink(dest) < 0) { + perror_msg("cannot remove `%s'", dest); + return -1; + } + } + + if (copy_file(source, dest, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS | + FILEUTILS_PRESERVE_SYMLINKS) < 0) + return -1; + + if (remove_file(source, FILEUTILS_RECUR | FILEUTILS_FORCE) < 0) + return -1; + + return 0; +} + +static int move_file(const char *source, const char *dest) +{ + struct stat dest_stat; + int dest_exists = 1; + + if (stat(dest, &dest_stat) < 0) { + if (errno != ENOENT) { + perror_msg("unable to stat `%s'", dest); + return -1; + } + dest_exists = 0; + } + + if (dest_exists && !(flags & FILEUTILS_FORCE) && + ((access(dest, W_OK) < 0 && isatty(0)) || + (flags & FILEUTILS_INTERACTIVE))) { + fprintf(stderr, "mv: overwrite `%s'? ", dest); + if (!ask_confirmation()) + return 0; + } + + if (rename(source, dest) < 0) { + if (errno == EXDEV) + return manual_rename(source, dest); + + perror_msg("unable to rename `%s'", source); + return -1; + } + + return 0; +} + +extern int mv_main(int argc, char **argv) +{ + int status = 0; + int opt; + int i; + + while ((opt = getopt(argc, argv, "fi")) != -1) + switch (opt) { + case 'f': + flags &= ~FILEUTILS_INTERACTIVE; + flags |= FILEUTILS_FORCE; + break; + case 'i': + flags &= ~FILEUTILS_FORCE; + flags |= FILEUTILS_INTERACTIVE; + break; + default: + show_usage(); + } + + if (optind + 2 > argc) + show_usage(); + + if (optind + 2 == argc) { + struct stat dest_stat; + int dest_exists = 1; + + if (stat(argv[optind + 1], &dest_stat) < 0) { + if (errno != ENOENT) + perror_msg_and_die("unable to stat `%s'", argv[optind + 1]); + dest_exists = 0; + } + + if (!dest_exists || !S_ISDIR(dest_stat.st_mode)) { + if (move_file(argv[optind], argv[optind + 1]) < 0) + status = 1; + return status; + } + } + + for (i = optind; i < argc - 1; i++) { + char *dest = concat_path_file(argv[argc - 1], + get_last_path_component(argv[i])); + if (move_file(argv[i], dest) < 0) + status = 1; + free(dest); + } + + return status; +} diff --git a/nc.c b/nc.c new file mode 100644 index 000000000..87e67e4cb --- /dev/null +++ b/nc.c @@ -0,0 +1,171 @@ +/* vi: set sw=4 ts=4: */ +/* nc: mini-netcat - built from the ground up for LRP + Copyright (C) 1998 Charles P. Wright + + 0.0.1 6K It works. + 0.0.2 5K Smaller and you can also check the exit condition if you wish. + 0.0.3 Uses select() + + 19980918 Busy Boxed! Dave Cinege + 19990512 Uses Select. Charles P. Wright + 19990513 Fixes stdin stupidity and uses buffers. Charles P. Wright + + 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 +#include +#include "busybox.h" + +#define GAPING_SECURITY_HOLE + +int nc_main(int argc, char **argv) +{ + int do_listen = 0, lport = 0, tmpfd, opt, sfd, x; + char buf[BUFSIZ]; +#ifdef GAPING_SECURITY_HOLE + char * pr00gie = NULL; +#endif + + struct sockaddr_in address; + struct hostent *hostinfo; + + fd_set readfds, testfds; + + while ((opt = getopt(argc, argv, "lp:")) > 0) { + switch (opt) { + case 'l': + do_listen++; + break; + case 'p': + lport = atoi(optarg); + break; +#ifdef GAPING_SECURITY_HOLE + case 'e': + pr00gie = optarg; + break; +#endif + default: + show_usage(); + } + } + +#ifdef GAPING_SECURITY_HOLE + if (pr00gie) { + /* won't need stdin */ + close (fileno(stdin)); + } +#endif /* GAPING_SECURITY_HOLE */ + + + if ((do_listen && optind != argc) || (!do_listen && optind + 2 != argc)) + show_usage(); + + if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + perror_msg_and_die("socket"); + x = 1; + if (setsockopt (sfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1) + perror_msg_and_die ("reuseaddr failed"); + address.sin_family = AF_INET; + + if (lport != 0) { + memset(&address.sin_addr, 0, sizeof(address.sin_addr)); + address.sin_port = htons(lport); + + if (bind(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) + perror_msg_and_die("bind"); + } + + if (do_listen) { + socklen_t addrlen = sizeof(address); + + if (listen(sfd, 1) < 0) + perror_msg_and_die("listen"); + + if ((tmpfd = accept(sfd, (struct sockaddr *) &address, &addrlen)) < 0) + perror_msg_and_die("accept"); + + close(sfd); + sfd = tmpfd; + } else { + hostinfo = xgethostbyname(argv[optind]); + + address.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; + address.sin_port = htons(atoi(argv[optind+1])); + + if (connect(sfd, (struct sockaddr *) &address, sizeof(address)) < 0) + perror_msg_and_die("connect"); + } + +#ifdef GAPING_SECURITY_HOLE + /* -e given? */ + if (pr00gie) { + dup2(sfd, 0); + close(sfd); + dup2 (0, 1); + dup2 (0, 2); + execl (pr00gie, pr00gie, NULL); + /* Don't print stuff or it will go over the wire.... */ + _exit(-1); + } +#endif /* GAPING_SECURITY_HOLE */ + + + FD_ZERO(&readfds); + FD_SET(sfd, &readfds); + FD_SET(STDIN_FILENO, &readfds); + + while (1) { + int fd; + int ofd; + int nread; + + testfds = readfds; + + if (select(FD_SETSIZE, &testfds, NULL, NULL, NULL) < 0) + perror_msg_and_die("select"); + + for (fd = 0; fd < FD_SETSIZE; fd++) { + if (FD_ISSET(fd, &testfds)) { + if ((nread = safe_read(fd, buf, sizeof(buf))) < 0) + perror_msg_and_die("read"); + + if (fd == sfd) { + if (nread == 0) + exit(0); + ofd = STDOUT_FILENO; + } else { + if (nread == 0) + shutdown(sfd, 1); + ofd = sfd; + } + + if (full_write(ofd, buf, nread) < 0) + perror_msg_and_die("write"); + } + } + } +} diff --git a/nfsmount.c b/nfsmount.c new file mode 100644 index 000000000..cd722acc3 --- /dev/null +++ b/nfsmount.c @@ -0,0 +1,977 @@ +/* vi: set sw=4 ts=4: */ +/* + * nfsmount.c -- Linux NFS mount + * Copyright (C) 1993 Rick Sladkey + * + * 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. + * + * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port + * numbers to be specified on the command line. + * + * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler : + * Omit the call to connect() for Linux version 1.3.11 or later. + * + * Wed Oct 1 23:55:28 1997: Dick Streefland + * Implemented the "bg", "fg" and "retry" mount options for NFS. + * + * 1999-02-22 Arkadiusz Mi¶kiewicz + * - added Native Language Support + * + * Modified by Olaf Kirch and Trond Myklebust for new NFS code, + * plus NFSv3 stuff. + */ + +/* + * nfsmount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" +#undef TRUE +#undef FALSE +#include +#include +#include +#include /* For the kernels nfs stuff */ +#include "nfsmount.h" + +#ifndef NFS_FHSIZE +static const int NFS_FHSIZE = 32; +#endif +#ifndef NFS_PORT +static const int NFS_PORT = 2049; +#endif + +/* Disable the nls stuff */ +# undef bindtextdomain +# define bindtextdomain(Domain, Directory) /* empty */ +# undef textdomain +# define textdomain(Domain) /* empty */ +# define _(Text) (Text) +# define N_(Text) (Text) + +static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */ +static const int MS_RDONLY = 1; /* Mount read-only */ +static const int MS_NOSUID = 2; /* Ignore suid and sgid bits */ +static const int MS_NODEV = 4; /* Disallow access to device special files */ +static const int MS_NOEXEC = 8; /* Disallow program execution */ +static const int MS_SYNCHRONOUS = 16; /* Writes are synced at once */ +static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS */ +static const int MS_MANDLOCK = 64; /* Allow mandatory locks on an FS */ +static const int S_QUOTA = 128; /* Quota initialized for file/directory/symlink */ +static const int S_APPEND = 256; /* Append-only file */ +static const int S_IMMUTABLE = 512; /* Immutable file */ +static const int MS_NOATIME = 1024; /* Do not update access times. */ +static const int MS_NODIRATIME = 2048; /* Do not update directory access times */ + + +/* + * We want to be able to compile mount on old kernels in such a way + * that the binary will work well on more recent kernels. + * Thus, if necessary we teach nfsmount.c the structure of new fields + * that will come later. + * + * Moreover, the new kernel includes conflict with glibc includes + * so it is easiest to ignore the kernel altogether (at compile time). + */ + +/* NOTE: Do not make this into a 'static const int' because the pre-processor + * needs to test this value in some #if statements. */ +#define NFS_MOUNT_VERSION 4 + +struct nfs2_fh { + char data[32]; +}; +struct nfs3_fh { + unsigned short size; + unsigned char data[64]; +}; + +struct nfs_mount_data { + int version; /* 1 */ + int fd; /* 1 */ + struct nfs2_fh old_root; /* 1 */ + int flags; /* 1 */ + int rsize; /* 1 */ + int wsize; /* 1 */ + int timeo; /* 1 */ + int retrans; /* 1 */ + int acregmin; /* 1 */ + int acregmax; /* 1 */ + int acdirmin; /* 1 */ + int acdirmax; /* 1 */ + struct sockaddr_in addr; /* 1 */ + char hostname[256]; /* 1 */ + int namlen; /* 2 */ + unsigned int bsize; /* 3 */ + struct nfs3_fh root; /* 4 */ +}; + +/* bits in the flags field */ + +static const int NFS_MOUNT_SOFT = 0x0001; /* 1 */ +static const int NFS_MOUNT_INTR = 0x0002; /* 1 */ +static const int NFS_MOUNT_SECURE = 0x0004; /* 1 */ +static const int NFS_MOUNT_POSIX = 0x0008; /* 1 */ +static const int NFS_MOUNT_NOCTO = 0x0010; /* 1 */ +static const int NFS_MOUNT_NOAC = 0x0020; /* 1 */ +static const int NFS_MOUNT_TCP = 0x0040; /* 2 */ +static const int NFS_MOUNT_VER3 = 0x0080; /* 3 */ +static const int NFS_MOUNT_KERBEROS = 0x0100; /* 3 */ +static const int NFS_MOUNT_NONLM = 0x0200; /* 3 */ + + +#define UTIL_LINUX_VERSION "2.10m" +#define util_linux_version "util-linux-2.10m" + +#define HAVE_inet_aton +#define HAVE_scsi_h +#define HAVE_blkpg_h +#define HAVE_kd_h +#define HAVE_termcap +#define HAVE_locale_h +#define HAVE_libintl_h +#define ENABLE_NLS +#define HAVE_langinfo_h +#define HAVE_progname +#define HAVE_openpty +#define HAVE_nanosleep +#define HAVE_personality +#define HAVE_tm_gmtoff + +static char *nfs_strerror(int status); + +#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r)) +#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2) + +static const int EX_FAIL = 32; /* mount failure */ +static const int EX_BG = 256; /* retry in background (internal only) */ + + +/* + * nfs_mount_version according to the sources seen at compile time. + */ +static int nfs_mount_version; + +/* + * Unfortunately, the kernel prints annoying console messages + * in case of an unexpected nfs mount version (instead of + * just returning some error). Therefore we'll have to try + * and figure out what version the kernel expects. + * + * Variables: + * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time + * NFS_MOUNT_VERSION: these nfsmount sources at compile time + * nfs_mount_version: version this source and running kernel can handle + */ +static void +find_kernel_nfs_mount_version(void) +{ + static int kernel_version = 0; + + if (kernel_version) + return; + + nfs_mount_version = NFS_MOUNT_VERSION; /* default */ + + kernel_version = get_kernel_revision(); + if (kernel_version) { + if (kernel_version < MAKE_VERSION(2,1,32)) + nfs_mount_version = 1; + else if (kernel_version < MAKE_VERSION(2,2,18) || + (kernel_version >= MAKE_VERSION(2,3,0) && + kernel_version < MAKE_VERSION(2,3,99))) + nfs_mount_version = 3; + else + nfs_mount_version = 4; /* since 2.3.99pre4 */ + } + if (nfs_mount_version > NFS_MOUNT_VERSION) + nfs_mount_version = NFS_MOUNT_VERSION; +} + +static struct pmap * +get_mountport(struct sockaddr_in *server_addr, + long unsigned prog, + long unsigned version, + long unsigned proto, + long unsigned port) +{ +struct pmaplist *pmap; +static struct pmap p = {0, 0, 0, 0}; + +server_addr->sin_port = PMAPPORT; +pmap = pmap_getmaps(server_addr); + +if (version > MAX_NFSPROT) + version = MAX_NFSPROT; +if (!prog) + prog = MOUNTPROG; +p.pm_prog = prog; +p.pm_vers = version; +p.pm_prot = proto; +p.pm_port = port; + +while (pmap) { + if (pmap->pml_map.pm_prog != prog) + goto next; + if (!version && p.pm_vers > pmap->pml_map.pm_vers) + goto next; + if (version > 2 && pmap->pml_map.pm_vers != version) + goto next; + if (version && version <= 2 && pmap->pml_map.pm_vers > 2) + goto next; + if (pmap->pml_map.pm_vers > MAX_NFSPROT || + (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) || + (port && pmap->pml_map.pm_port != port)) + goto next; + memcpy(&p, &pmap->pml_map, sizeof(p)); +next: + pmap = pmap->pml_next; +} +if (!p.pm_vers) + p.pm_vers = MOUNTVERS; +if (!p.pm_port) + p.pm_port = MOUNTPORT; +if (!p.pm_prot) + p.pm_prot = IPPROTO_TCP; +return &p; +} + +int nfsmount(const char *spec, const char *node, int *flags, + char **extra_opts, char **mount_opts, int running_bg) +{ + static char *prev_bg_host; + char hostdir[1024]; + CLIENT *mclient; + char *hostname; + char *pathname; + char *old_opts; + char *mounthost=NULL; + char new_opts[1024]; + struct timeval total_timeout; + enum clnt_stat clnt_stat; + static struct nfs_mount_data data; + char *opt, *opteq; + int val; + struct hostent *hp; + struct sockaddr_in server_addr; + struct sockaddr_in mount_server_addr; + struct pmap* pm_mnt; + int msock, fsock; + struct timeval retry_timeout; + union { + struct fhstatus nfsv2; + struct mountres3 nfsv3; + } status; + struct stat statbuf; + char *s; + int port; + int mountport; + int proto; + int bg; + int soft; + int intr; + int posix; + int nocto; + int noac; + int nolock; + int retry; + int tcp; + int mountprog; + int mountvers; + int nfsprog; + int nfsvers; + int retval; + time_t t; + time_t prevt; + time_t timeout; + + find_kernel_nfs_mount_version(); + + retval = EX_FAIL; + msock = fsock = -1; + mclient = NULL; + if (strlen(spec) >= sizeof(hostdir)) { + error_msg("excessively long host:dir argument"); + goto fail; + } + strcpy(hostdir, spec); + if ((s = strchr(hostdir, ':'))) { + hostname = hostdir; + pathname = s + 1; + *s = '\0'; + /* Ignore all but first hostname in replicated mounts + until they can be fully supported. (mack@sgi.com) */ + if ((s = strchr(hostdir, ','))) { + *s = '\0'; + error_msg("warning: multiple hostnames not supported"); + } + } else { + error_msg("directory to mount not in host:dir format"); + goto fail; + } + + server_addr.sin_family = AF_INET; +#ifdef HAVE_inet_aton + if (!inet_aton(hostname, &server_addr.sin_addr)) +#endif + { + if ((hp = gethostbyname(hostname)) == NULL) { + herror_msg("%s", hostname); + goto fail; + } else { + if (hp->h_length > sizeof(struct in_addr)) { + error_msg("got bad hp->h_length"); + hp->h_length = sizeof(struct in_addr); + } + memcpy(&server_addr.sin_addr, + hp->h_addr, hp->h_length); + } + } + + memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr)); + + /* add IP address to mtab options for use when unmounting */ + + s = inet_ntoa(server_addr.sin_addr); + old_opts = *extra_opts; + if (!old_opts) + old_opts = ""; + if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) { + error_msg("excessively long option argument"); + goto fail; + } + sprintf(new_opts, "%s%saddr=%s", + old_opts, *old_opts ? "," : "", s); + *extra_opts = xstrdup(new_opts); + + /* Set default options. + * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to + * let the kernel decide. + * timeo is filled in after we know whether it'll be TCP or UDP. */ + memset(&data, 0, sizeof(data)); + data.retrans = 3; + data.acregmin = 3; + data.acregmax = 60; + data.acdirmin = 30; + data.acdirmax = 60; +#if NFS_MOUNT_VERSION >= 2 + data.namlen = NAME_MAX; +#endif + + bg = 0; + soft = 0; + intr = 0; + posix = 0; + nocto = 0; + nolock = 0; + noac = 0; + retry = 10000; /* 10000 minutes ~ 1 week */ + tcp = 0; + + mountprog = MOUNTPROG; + mountvers = 0; + port = 0; + mountport = 0; + nfsprog = NFS_PROGRAM; + nfsvers = 0; + + /* parse options */ + + for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) { + if ((opteq = strchr(opt, '='))) { + val = atoi(opteq + 1); + *opteq = '\0'; + if (!strcmp(opt, "rsize")) + data.rsize = val; + else if (!strcmp(opt, "wsize")) + data.wsize = val; + else if (!strcmp(opt, "timeo")) + data.timeo = val; + else if (!strcmp(opt, "retrans")) + data.retrans = val; + else if (!strcmp(opt, "acregmin")) + data.acregmin = val; + else if (!strcmp(opt, "acregmax")) + data.acregmax = val; + else if (!strcmp(opt, "acdirmin")) + data.acdirmin = val; + else if (!strcmp(opt, "acdirmax")) + data.acdirmax = val; + else if (!strcmp(opt, "actimeo")) { + data.acregmin = val; + data.acregmax = val; + data.acdirmin = val; + data.acdirmax = val; + } + else if (!strcmp(opt, "retry")) + retry = val; + else if (!strcmp(opt, "port")) + port = val; + else if (!strcmp(opt, "mountport")) + mountport = val; + else if (!strcmp(opt, "mounthost")) + mounthost=xstrndup(opteq+1, + strcspn(opteq+1," \t\n\r,")); + else if (!strcmp(opt, "mountprog")) + mountprog = val; + else if (!strcmp(opt, "mountvers")) + mountvers = val; + else if (!strcmp(opt, "nfsprog")) + nfsprog = val; + else if (!strcmp(opt, "nfsvers") || + !strcmp(opt, "vers")) + nfsvers = val; + else if (!strcmp(opt, "proto")) { + if (!strncmp(opteq+1, "tcp", 3)) + tcp = 1; + else if (!strncmp(opteq+1, "udp", 3)) + tcp = 0; + else + printf(_("Warning: Unrecognized proto= option.\n")); + } else if (!strcmp(opt, "namlen")) { +#if NFS_MOUNT_VERSION >= 2 + if (nfs_mount_version >= 2) + data.namlen = val; + else +#endif + printf(_("Warning: Option namlen is not supported.\n")); + } else if (!strcmp(opt, "addr")) + /* ignore */; + else { + printf(_("unknown nfs mount parameter: " + "%s=%d\n"), opt, val); + goto fail; + } + } + else { + val = 1; + if (!strncmp(opt, "no", 2)) { + val = 0; + opt += 2; + } + if (!strcmp(opt, "bg")) + bg = val; + else if (!strcmp(opt, "fg")) + bg = !val; + else if (!strcmp(opt, "soft")) + soft = val; + else if (!strcmp(opt, "hard")) + soft = !val; + else if (!strcmp(opt, "intr")) + intr = val; + else if (!strcmp(opt, "posix")) + posix = val; + else if (!strcmp(opt, "cto")) + nocto = !val; + else if (!strcmp(opt, "ac")) + noac = !val; + else if (!strcmp(opt, "tcp")) + tcp = val; + else if (!strcmp(opt, "udp")) + tcp = !val; + else if (!strcmp(opt, "lock")) { + if (nfs_mount_version >= 3) + nolock = !val; + else + printf(_("Warning: option nolock is not supported.\n")); + } else { + printf(_("unknown nfs mount option: " + "%s%s\n"), val ? "" : "no", opt); + goto fail; + } + } + } + proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP; + + data.flags = (soft ? NFS_MOUNT_SOFT : 0) + | (intr ? NFS_MOUNT_INTR : 0) + | (posix ? NFS_MOUNT_POSIX : 0) + | (nocto ? NFS_MOUNT_NOCTO : 0) + | (noac ? NFS_MOUNT_NOAC : 0); +#if NFS_MOUNT_VERSION >= 2 + if (nfs_mount_version >= 2) + data.flags |= (tcp ? NFS_MOUNT_TCP : 0); +#endif +#if NFS_MOUNT_VERSION >= 3 + if (nfs_mount_version >= 3) + data.flags |= (nolock ? NFS_MOUNT_NONLM : 0); +#endif + if (nfsvers > MAX_NFSPROT) { + error_msg("NFSv%d not supported!", nfsvers); + return 0; + } + if (mountvers > MAX_NFSPROT) { + error_msg("NFSv%d not supported!", nfsvers); + return 0; + } + if (nfsvers && !mountvers) + mountvers = (nfsvers < 3) ? 1 : nfsvers; + if (nfsvers && nfsvers < mountvers) { + mountvers = nfsvers; + } + + /* Adjust options if none specified */ + if (!data.timeo) + data.timeo = tcp ? 70 : 7; + +#ifdef NFS_MOUNT_DEBUG + printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n", + data.rsize, data.wsize, data.timeo, data.retrans); + printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n", + data.acregmin, data.acregmax, data.acdirmin, data.acdirmax); + printf("port = %d, bg = %d, retry = %d, flags = %.8x\n", + port, bg, retry, data.flags); + printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n", + mountprog, mountvers, nfsprog, nfsvers); + printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n", + (data.flags & NFS_MOUNT_SOFT) != 0, + (data.flags & NFS_MOUNT_INTR) != 0, + (data.flags & NFS_MOUNT_POSIX) != 0, + (data.flags & NFS_MOUNT_NOCTO) != 0, + (data.flags & NFS_MOUNT_NOAC) != 0); +#if NFS_MOUNT_VERSION >= 2 + printf("tcp = %d\n", + (data.flags & NFS_MOUNT_TCP) != 0); +#endif +#endif + + data.version = nfs_mount_version; + *mount_opts = (char *) &data; + + if (*flags & MS_REMOUNT) + return 0; + + /* + * If the previous mount operation on the same host was + * backgrounded, and the "bg" for this mount is also set, + * give up immediately, to avoid the initial timeout. + */ + if (bg && !running_bg && + prev_bg_host && strcmp(hostname, prev_bg_host) == 0) { + if (retry > 0) + retval = EX_BG; + return retval; + } + + /* create mount deamon client */ + /* See if the nfs host = mount host. */ + if (mounthost) { + if (mounthost[0] >= '0' && mounthost[0] <= '9') { + mount_server_addr.sin_family = AF_INET; + mount_server_addr.sin_addr.s_addr = inet_addr(hostname); + } else { + if ((hp = gethostbyname(mounthost)) == NULL) { + herror_msg("%s", mounthost); + goto fail; + } else { + if (hp->h_length > sizeof(struct in_addr)) { + error_msg("got bad hp->h_length?"); + hp->h_length = sizeof(struct in_addr); + } + mount_server_addr.sin_family = AF_INET; + memcpy(&mount_server_addr.sin_addr, + hp->h_addr, hp->h_length); + } + } + } + + /* + * The following loop implements the mount retries. On the first + * call, "running_bg" is 0. When the mount times out, and the + * "bg" option is set, the exit status EX_BG will be returned. + * For a backgrounded mount, there will be a second call by the + * child process with "running_bg" set to 1. + * + * The case where the mount point is not present and the "bg" + * option is set, is treated as a timeout. This is done to + * support nested mounts. + * + * The "retry" count specified by the user is the number of + * minutes to retry before giving up. + * + * Only the first error message will be displayed. + */ + retry_timeout.tv_sec = 3; + retry_timeout.tv_usec = 0; + total_timeout.tv_sec = 20; + total_timeout.tv_usec = 0; + timeout = time(NULL) + 60 * retry; + prevt = 0; + t = 30; + val = 1; + for (;;) { + if (bg && stat(node, &statbuf) == -1) { + if (running_bg) { + sleep(val); /* 1, 2, 4, 8, 16, 30, ... */ + val *= 2; + if (val > 30) + val = 30; + } + } else { + /* be careful not to use too many CPU cycles */ + if (t - prevt < 30) + sleep(30); + + pm_mnt = get_mountport(&mount_server_addr, + mountprog, + mountvers, + proto, + mountport); + + /* contact the mount daemon via TCP */ + mount_server_addr.sin_port = htons(pm_mnt->pm_port); + msock = RPC_ANYSOCK; + + switch (pm_mnt->pm_prot) { + case IPPROTO_UDP: + mclient = clntudp_create(&mount_server_addr, + pm_mnt->pm_prog, + pm_mnt->pm_vers, + retry_timeout, + &msock); + if (mclient) + break; + mount_server_addr.sin_port = htons(pm_mnt->pm_port); + msock = RPC_ANYSOCK; + case IPPROTO_TCP: + mclient = clnttcp_create(&mount_server_addr, + pm_mnt->pm_prog, + pm_mnt->pm_vers, + &msock, 0, 0); + break; + default: + mclient = 0; + } + if (mclient) { + /* try to mount hostname:pathname */ + mclient->cl_auth = authunix_create_default(); + + /* make pointers in xdr_mountres3 NULL so + * that xdr_array allocates memory for us + */ + memset(&status, 0, sizeof(status)); + + if (pm_mnt->pm_vers == 3) + clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT, + (xdrproc_t) xdr_dirpath, + (caddr_t) &pathname, + (xdrproc_t) xdr_mountres3, + (caddr_t) &status, + total_timeout); + else + clnt_stat = clnt_call(mclient, MOUNTPROC_MNT, + (xdrproc_t) xdr_dirpath, + (caddr_t) &pathname, + (xdrproc_t) xdr_fhstatus, + (caddr_t) &status, + total_timeout); + + if (clnt_stat == RPC_SUCCESS) + break; /* we're done */ + if (errno != ECONNREFUSED) { + clnt_perror(mclient, "mount"); + goto fail; /* don't retry */ + } + if (!running_bg && prevt == 0) + clnt_perror(mclient, "mount"); + auth_destroy(mclient->cl_auth); + clnt_destroy(mclient); + mclient = 0; + close(msock); + } else { + if (!running_bg && prevt == 0) + clnt_pcreateerror("mount"); + } + prevt = t; + } + if (!bg) + goto fail; + if (!running_bg) { + prev_bg_host = xstrdup(hostname); + if (retry > 0) + retval = EX_BG; + goto fail; + } + t = time(NULL); + if (t >= timeout) + goto fail; + } + nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers; + + if (nfsvers == 2) { + if (status.nfsv2.fhs_status != 0) { + error_msg("%s:%s failed, reason given by server: %s", + hostname, pathname, + nfs_strerror(status.nfsv2.fhs_status)); + goto fail; + } + memcpy(data.root.data, + (char *) status.nfsv2.fhstatus_u.fhs_fhandle, + NFS_FHSIZE); +#if NFS_MOUNT_VERSION >= 4 + data.root.size = NFS_FHSIZE; + memcpy(data.old_root.data, + (char *) status.nfsv2.fhstatus_u.fhs_fhandle, + NFS_FHSIZE); +#endif + } else { +#if NFS_MOUNT_VERSION >= 4 + fhandle3 *my_fhandle; + if (status.nfsv3.fhs_status != 0) { + error_msg("%s:%s failed, reason given by server: %s", + hostname, pathname, + nfs_strerror(status.nfsv3.fhs_status)); + goto fail; + } + my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle; + memset(data.old_root.data, 0, NFS_FHSIZE); + memset(&data.root, 0, sizeof(data.root)); + data.root.size = my_fhandle->fhandle3_len; + memcpy(data.root.data, + (char *) my_fhandle->fhandle3_val, + my_fhandle->fhandle3_len); + + data.flags |= NFS_MOUNT_VER3; +#endif + } + + /* create nfs socket for kernel */ + + if (tcp) { + if (nfs_mount_version < 3) { + printf(_("NFS over TCP is not supported.\n")); + goto fail; + } + fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + } else + fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (fsock < 0) { + perror(_("nfs socket")); + goto fail; + } + if (bindresvport(fsock, 0) < 0) { + perror(_("nfs bindresvport")); + goto fail; + } + if (port == 0) { + server_addr.sin_port = PMAPPORT; + port = pmap_getport(&server_addr, nfsprog, nfsvers, + tcp ? IPPROTO_TCP : IPPROTO_UDP); + if (port == 0) + port = NFS_PORT; +#ifdef NFS_MOUNT_DEBUG + else + printf(_("used portmapper to find NFS port\n")); +#endif + } +#ifdef NFS_MOUNT_DEBUG + printf(_("using port %d for nfs deamon\n"), port); +#endif + server_addr.sin_port = htons(port); + /* + * connect() the socket for kernels 1.3.10 and below only, + * to avoid problems with multihomed hosts. + * --Swen + */ + if (get_kernel_revision() <= 66314 + && connect(fsock, (struct sockaddr *) &server_addr, + sizeof (server_addr)) < 0) { + perror(_("nfs connect")); + goto fail; + } + + /* prepare data structure for kernel */ + + data.fd = fsock; + memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr)); + strncpy(data.hostname, hostname, sizeof(data.hostname)); + + /* clean up */ + + auth_destroy(mclient->cl_auth); + clnt_destroy(mclient); + close(msock); + return 0; + + /* abort */ + +fail: + if (msock != -1) { + if (mclient) { + auth_destroy(mclient->cl_auth); + clnt_destroy(mclient); + } + close(msock); + } + if (fsock != -1) + close(fsock); + return retval; +} + +/* + * We need to translate between nfs status return values and + * the local errno values which may not be the same. + * + * Andreas Schwab : change errno: + * "after #include the symbol errno is reserved for any use, + * it cannot even be used as a struct tag or field name". + */ + +#ifndef EDQUOT +#define EDQUOT ENOSPC +#endif + +static struct { + enum nfs_stat stat; + int errnum; +} nfs_errtbl[] = { + { NFS_OK, 0 }, + { NFSERR_PERM, EPERM }, + { NFSERR_NOENT, ENOENT }, + { NFSERR_IO, EIO }, + { NFSERR_NXIO, ENXIO }, + { NFSERR_ACCES, EACCES }, + { NFSERR_EXIST, EEXIST }, + { NFSERR_NODEV, ENODEV }, + { NFSERR_NOTDIR, ENOTDIR }, + { NFSERR_ISDIR, EISDIR }, +#ifdef NFSERR_INVAL + { NFSERR_INVAL, EINVAL }, /* that Sun forgot */ +#endif + { NFSERR_FBIG, EFBIG }, + { NFSERR_NOSPC, ENOSPC }, + { NFSERR_ROFS, EROFS }, + { NFSERR_NAMETOOLONG, ENAMETOOLONG }, + { NFSERR_NOTEMPTY, ENOTEMPTY }, + { NFSERR_DQUOT, EDQUOT }, + { NFSERR_STALE, ESTALE }, +#ifdef EWFLUSH + { NFSERR_WFLUSH, EWFLUSH }, +#endif + /* Throw in some NFSv3 values for even more fun (HP returns these) */ + { 71, EREMOTE }, + + { -1, EIO } +}; + +static char *nfs_strerror(int status) +{ + int i; + static char buf[256]; + + for (i = 0; nfs_errtbl[i].stat != -1; i++) { + if (nfs_errtbl[i].stat == status) + return strerror(nfs_errtbl[i].errnum); + } + sprintf(buf, _("unknown nfs status return value: %d"), status); + return buf; +} + +static bool_t +xdr_fhandle (XDR *xdrs, fhandle objp) +{ + //register int32_t *buf; + + if (!xdr_opaque (xdrs, objp, FHSIZE)) + return FALSE; + return TRUE; +} + +bool_t +xdr_fhstatus (XDR *xdrs, fhstatus *objp) +{ + //register int32_t *buf; + + if (!xdr_u_int (xdrs, &objp->fhs_status)) + return FALSE; + switch (objp->fhs_status) { + case 0: + if (!xdr_fhandle (xdrs, objp->fhstatus_u.fhs_fhandle)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_dirpath (XDR *xdrs, dirpath *objp) +{ + //register int32_t *buf; + + if (!xdr_string (xdrs, objp, MNTPATHLEN)) + return FALSE; + return TRUE; +} + +bool_t +xdr_fhandle3 (XDR *xdrs, fhandle3 *objp) +{ + //register int32_t *buf; + + if (!xdr_bytes (xdrs, (char **)&objp->fhandle3_val, (u_int *) &objp->fhandle3_len, FHSIZE3)) + return FALSE; + return TRUE; +} + +bool_t +xdr_mountres3_ok (XDR *xdrs, mountres3_ok *objp) +{ + //register int32_t *buf; + + if (!xdr_fhandle3 (xdrs, &objp->fhandle)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->auth_flavours.auth_flavours_val, (u_int *) &objp->auth_flavours.auth_flavours_len, ~0, + sizeof (int), (xdrproc_t) xdr_int)) + return FALSE; + return TRUE; +} + +bool_t +xdr_mountstat3 (XDR *xdrs, mountstat3 *objp) +{ + //register int32_t *buf; + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_mountres3 (XDR *xdrs, mountres3 *objp) +{ + //register int32_t *buf; + + if (!xdr_mountstat3 (xdrs, &objp->fhs_status)) + return FALSE; + switch (objp->fhs_status) { + case MNT_OK: + if (!xdr_mountres3_ok (xdrs, &objp->mountres3_u.mountinfo)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + diff --git a/nfsmount.h b/nfsmount.h new file mode 100644 index 000000000..b3d5a51e6 --- /dev/null +++ b/nfsmount.h @@ -0,0 +1,242 @@ +/* vi: set sw=4 ts=4: */ +/* + * This file was originally generated using rpcgen. + * But now we edit it by hand as needed to make it + * shut up... + */ + +#ifndef _NFSMOUNT_H_RPCGEN +#define _NFSMOUNT_H_RPCGEN + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user or with the express written consent of + * Sun Microsystems, Inc. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* + * Copyright (c) 1985, 1990 by Sun Microsystems, Inc. + */ + +/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */ +#ifndef _rpcsvc_mount_h +#define _rpcsvc_mount_h +#include +#define MOUNTPORT 635 +#define MNTPATHLEN 1024 +#define MNTNAMLEN 255 +#define FHSIZE 32 +#define FHSIZE3 64 + +typedef char fhandle[FHSIZE]; + +typedef struct { + u_int fhandle3_len; + char *fhandle3_val; +} fhandle3; + +enum mountstat3 { + MNT_OK = 0, + MNT3ERR_PERM = 1, + MNT3ERR_NOENT = 2, + MNT3ERR_IO = 5, + MNT3ERR_ACCES = 13, + MNT3ERR_NOTDIR = 20, + MNT3ERR_INVAL = 22, + MNT3ERR_NAMETOOLONG = 63, + MNT3ERR_NOTSUPP = 10004, + MNT3ERR_SERVERFAULT = 10006, +}; +typedef enum mountstat3 mountstat3; + +struct fhstatus { + u_int fhs_status; + union { + fhandle fhs_fhandle; + } fhstatus_u; +}; +typedef struct fhstatus fhstatus; + +struct mountres3_ok { + fhandle3 fhandle; + struct { + u_int auth_flavours_len; + int *auth_flavours_val; + } auth_flavours; +}; +typedef struct mountres3_ok mountres3_ok; + +struct mountres3 { + mountstat3 fhs_status; + union { + mountres3_ok mountinfo; + } mountres3_u; +}; +typedef struct mountres3 mountres3; + +typedef char *dirpath; + +typedef char *name; + +typedef struct mountbody *mountlist; + +struct mountbody { + name ml_hostname; + dirpath ml_directory; + mountlist ml_next; +}; +typedef struct mountbody mountbody; + +typedef struct groupnode *groups; + +struct groupnode { + name gr_name; + groups gr_next; +}; +typedef struct groupnode groupnode; + +typedef struct exportnode *exports; + +struct exportnode { + dirpath ex_dir; + groups ex_groups; + exports ex_next; +}; +typedef struct exportnode exportnode; + +struct ppathcnf { + int pc_link_max; + short pc_max_canon; + short pc_max_input; + short pc_name_max; + short pc_path_max; + short pc_pipe_buf; + u_char pc_vdisable; + char pc_xxx; + short pc_mask[2]; +}; +typedef struct ppathcnf ppathcnf; +#endif /*!_rpcsvc_mount_h*/ + +#define MOUNTPROG 100005 +#define MOUNTVERS 1 + +#define MOUNTPROC_NULL 0 +extern void * mountproc_null_1(void *, CLIENT *); +extern void * mountproc_null_1_svc(void *, struct svc_req *); +#define MOUNTPROC_MNT 1 +extern fhstatus * mountproc_mnt_1(dirpath *, CLIENT *); +extern fhstatus * mountproc_mnt_1_svc(dirpath *, struct svc_req *); +#define MOUNTPROC_DUMP 2 +extern mountlist * mountproc_dump_1(void *, CLIENT *); +extern mountlist * mountproc_dump_1_svc(void *, struct svc_req *); +#define MOUNTPROC_UMNT 3 +extern void * mountproc_umnt_1(dirpath *, CLIENT *); +extern void * mountproc_umnt_1_svc(dirpath *, struct svc_req *); +#define MOUNTPROC_UMNTALL 4 +extern void * mountproc_umntall_1(void *, CLIENT *); +extern void * mountproc_umntall_1_svc(void *, struct svc_req *); +#define MOUNTPROC_EXPORT 5 +extern exports * mountproc_export_1(void *, CLIENT *); +extern exports * mountproc_export_1_svc(void *, struct svc_req *); +#define MOUNTPROC_EXPORTALL 6 +extern exports * mountproc_exportall_1(void *, CLIENT *); +extern exports * mountproc_exportall_1_svc(void *, struct svc_req *); +extern int mountprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + +#define MOUNTVERS_POSIX 2 + +extern void * mountproc_null_2(void *, CLIENT *); +extern void * mountproc_null_2_svc(void *, struct svc_req *); +extern fhstatus * mountproc_mnt_2(dirpath *, CLIENT *); +extern fhstatus * mountproc_mnt_2_svc(dirpath *, struct svc_req *); +extern mountlist * mountproc_dump_2(void *, CLIENT *); +extern mountlist * mountproc_dump_2_svc(void *, struct svc_req *); +extern void * mountproc_umnt_2(dirpath *, CLIENT *); +extern void * mountproc_umnt_2_svc(dirpath *, struct svc_req *); +extern void * mountproc_umntall_2(void *, CLIENT *); +extern void * mountproc_umntall_2_svc(void *, struct svc_req *); +extern exports * mountproc_export_2(void *, CLIENT *); +extern exports * mountproc_export_2_svc(void *, struct svc_req *); +extern exports * mountproc_exportall_2(void *, CLIENT *); +extern exports * mountproc_exportall_2_svc(void *, struct svc_req *); +#define MOUNTPROC_PATHCONF 7 +extern ppathcnf * mountproc_pathconf_2(dirpath *, CLIENT *); +extern ppathcnf * mountproc_pathconf_2_svc(dirpath *, struct svc_req *); +extern int mountprog_2_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + +#define MOUNT_V3 3 + +#define MOUNTPROC3_NULL 0 +extern void * mountproc3_null_3(void *, CLIENT *); +extern void * mountproc3_null_3_svc(void *, struct svc_req *); +#define MOUNTPROC3_MNT 1 +extern mountres3 * mountproc3_mnt_3(dirpath *, CLIENT *); +extern mountres3 * mountproc3_mnt_3_svc(dirpath *, struct svc_req *); +#define MOUNTPROC3_DUMP 2 +extern mountlist * mountproc3_dump_3(void *, CLIENT *); +extern mountlist * mountproc3_dump_3_svc(void *, struct svc_req *); +#define MOUNTPROC3_UMNT 3 +extern void * mountproc3_umnt_3(dirpath *, CLIENT *); +extern void * mountproc3_umnt_3_svc(dirpath *, struct svc_req *); +#define MOUNTPROC3_UMNTALL 4 +extern void * mountproc3_umntall_3(void *, CLIENT *); +extern void * mountproc3_umntall_3_svc(void *, struct svc_req *); +#define MOUNTPROC3_EXPORT 5 +extern exports * mountproc3_export_3(void *, CLIENT *); +extern exports * mountproc3_export_3_svc(void *, struct svc_req *); +extern int mountprog_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + +/* the xdr functions */ + +static bool_t xdr_fhandle (XDR *, fhandle); +extern bool_t xdr_fhandle3 (XDR *, fhandle3*); +extern bool_t xdr_mountstat3 (XDR *, mountstat3*); +extern bool_t xdr_fhstatus (XDR *, fhstatus*); +extern bool_t xdr_mountres3_ok (XDR *, mountres3_ok*); +extern bool_t xdr_mountres3 (XDR *, mountres3*); +extern bool_t xdr_dirpath (XDR *, dirpath*); +extern bool_t xdr_name (XDR *, name*); +extern bool_t xdr_mountlist (XDR *, mountlist*); +extern bool_t xdr_mountbody (XDR *, mountbody*); +extern bool_t xdr_groups (XDR *, groups*); +extern bool_t xdr_groupnode (XDR *, groupnode*); +extern bool_t xdr_exports (XDR *, exports*); +extern bool_t xdr_exportnode (XDR *, exportnode*); +extern bool_t xdr_ppathcnf (XDR *, ppathcnf*); + +#ifdef __cplusplus +} +#endif + +#endif /* !_NFSMOUNT_H_RPCGEN */ diff --git a/nslookup.c b/nslookup.c new file mode 100644 index 000000000..2139afd7e --- /dev/null +++ b/nslookup.c @@ -0,0 +1,180 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini nslookup implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and John Beppu + * Copyright (C) 1999,2000,2001 by John Beppu + * + * 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 +#include +#include "busybox.h" + +/* + | I'm only implementing non-interactive mode; + | I totally forgot nslookup even had an interactive mode. + | + | [ TODO ] + | + find out how to use non-default name servers + */ + +/* only works for IPv4 */ +static int addr_fprint(char *addr) +{ + u_int8_t split[4]; + u_int32_t ip; + u_int32_t *x = (u_int32_t *) addr; + + ip = ntohl(*x); + split[0] = (ip & 0xff000000) >> 24; + split[1] = (ip & 0x00ff0000) >> 16; + split[2] = (ip & 0x0000ff00) >> 8; + split[3] = (ip & 0x000000ff); + printf("%d.%d.%d.%d", split[0], split[1], split[2], split[3]); + return 0; +} + +/* takes the NULL-terminated array h_addr_list, and + * prints its contents appropriately + */ +static int addr_list_fprint(char **h_addr_list) +{ + int i, j; + char *addr_string = (h_addr_list[1]) + ? "Addresses: " : "Address: "; + + printf("%s ", addr_string); + for (i = 0, j = 0; h_addr_list[i]; i++, j++) { + addr_fprint(h_addr_list[i]); + + /* real nslookup does this */ + if (j == 4) { + if (h_addr_list[i + 1]) { + printf("\n "); + } + j = 0; + } else { + if (h_addr_list[i + 1]) { + printf(", "); + } + } + + } + printf("\n"); + return 0; +} + +/* print the results as nslookup would */ +static struct hostent *hostent_fprint(struct hostent *host, int is_server) +{ + char *format; + if (is_server) { + format = "Server: "; + } else { + format = "Name: "; + } + if (host) { + printf("%s%s\n", format, host->h_name); + addr_list_fprint(host->h_addr_list); + } else { + printf("*** Unknown host\n"); + } + return host; +} + +/* changes a c-string matching the perl regex \d+\.\d+\.\d+\.\d+ + * into a u_int32_t + */ +static u_int32_t str_to_addr(const char *addr) +{ + u_int32_t split[4]; + u_int32_t ip; + + sscanf(addr, "%d.%d.%d.%d", + &split[0], &split[1], &split[2], &split[3]); + + /* assuming sscanf worked */ + ip = (split[0] << 24) | + (split[1] << 16) | (split[2] << 8) | (split[3]); + + return htonl(ip); +} + +/* gethostbyaddr wrapper */ +static struct hostent *gethostbyaddr_wrapper(const char *address) +{ + struct in_addr addr; + + addr.s_addr = str_to_addr(address); + return gethostbyaddr((char *) &addr, 4, AF_INET); /* IPv4 only for now */ +} + +/* lookup the default nameserver and display it */ +static inline void server_print(void) +{ + struct sockaddr_in def = _res.nsaddr_list[0]; + char *ip = inet_ntoa(def.sin_addr); + + hostent_fprint(gethostbyaddr_wrapper(ip), 1); + printf("\n"); +} + +/* naive function to check whether char *s is an ip address */ +static int is_ip_address(const char *s) +{ + while (*s) { + if ((isdigit(*s)) || (*s == '.')) { + s++; + continue; + } + return 0; + } + return 1; +} + +/* ________________________________________________________________________ */ +int nslookup_main(int argc, char **argv) +{ + struct hostent *host; + + if (argc < 2 || *argv[1]=='-') { + show_usage(); + } + + res_init(); + server_print(); + if (is_ip_address(argv[1])) { + host = gethostbyaddr_wrapper(argv[1]); + } else { + host = gethostbyname(argv[1]); + } + hostent_fprint(host, 0); + return EXIT_SUCCESS; +} + +/* $Id: nslookup.c,v 1.28 2002/04/27 04:03:59 andersen Exp $ */ diff --git a/pidof.c b/pidof.c new file mode 100644 index 000000000..c75571a01 --- /dev/null +++ b/pidof.c @@ -0,0 +1,79 @@ +/* vi: set sw=4 ts=4: */ +/* + * pidof implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999-2002 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 + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + + +extern int pidof_main(int argc, char **argv) +{ + int opt, n = 0; + + + /* do normal option parsing */ + while ((opt = getopt(argc, argv, "ne:f:")) > 0) { + switch (opt) { +#if 0 + case 'g': + break; + case 'e': + break; +#endif + default: + show_usage(); + } + } + + /* if we didn't get a process name, then we need to choke and die here */ + if (argv[optind] == NULL) + show_usage(); + + /* Looks like everything is set to go. */ + while(optind < argc) { + long* pidList; + + pidList = find_pid_by_name( argv[optind]); + if (!pidList || *pidList<=0) { + break; + } + + for(; pidList && *pidList!=0; pidList++) { + printf("%s%ld", (n++ ? " " : ""), (long)*pidList); + } + /* Note that we don't bother to free the memory + * allocated in find_pid_by_name(). It will be freed + * upon exit, so we can save a byte or two */ + optind++; + } + printf("\n"); + + return EXIT_SUCCESS; +} diff --git a/ping.c b/ping.c new file mode 100644 index 000000000..74ff614df --- /dev/null +++ b/ping.c @@ -0,0 +1,555 @@ +/* vi: set sw=4 ts=4: */ +/* + * $Id: ping.c,v 1.47 2002/09/17 07:56:26 andersen Exp $ + * Mini ping implementation for busybox + * + * Copyright (C) 1999 by Randolph Chung + * + * 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 + * + * This version of ping is adapted from the ping in netkit-base 0.10, + * which is: + * + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Muuss. + * + * Original copyright notice is retained at the end of this file. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + + +/* It turns out that libc5 doesn't have proper icmp support + * built into it header files, so we have to supplement it */ +#if __GNU_LIBRARY__ < 5 +static const int ICMP_MINLEN = 8; /* abs minimum */ + +struct icmp_ra_addr +{ + u_int32_t ira_addr; + u_int32_t ira_preference; +}; + + +struct icmp +{ + u_int8_t icmp_type; /* type of message, see below */ + u_int8_t icmp_code; /* type sub code */ + u_int16_t icmp_cksum; /* ones complement checksum of struct */ + union + { + u_char ih_pptr; /* ICMP_PARAMPROB */ + struct in_addr ih_gwaddr; /* gateway address */ + struct ih_idseq /* echo datagram */ + { + u_int16_t icd_id; + u_int16_t icd_seq; + } ih_idseq; + u_int32_t ih_void; + + /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ + struct ih_pmtu + { + u_int16_t ipm_void; + u_int16_t ipm_nextmtu; + } ih_pmtu; + + struct ih_rtradv + { + u_int8_t irt_num_addrs; + u_int8_t irt_wpa; + u_int16_t irt_lifetime; + } ih_rtradv; + } icmp_hun; +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu +#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs +#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa +#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime + union + { + struct + { + u_int32_t its_otime; + u_int32_t its_rtime; + u_int32_t its_ttime; + } id_ts; + struct + { + struct ip idi_ip; + /* options and then 64 bits of data */ + } id_ip; + struct icmp_ra_addr id_radv; + u_int32_t id_mask; + u_int8_t id_data[1]; + } icmp_dun; +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_radv icmp_dun.id_radv +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data +}; +#endif + +static const int DEFDATALEN = 56; +static const int MAXIPLEN = 60; +static const int MAXICMPLEN = 76; +static const int MAXPACKET = 65468; +#define MAX_DUP_CHK (8 * 128) +static const int MAXWAIT = 10; +static const int PINGINTERVAL = 1; /* second */ + +#define O_QUIET (1 << 0) + +#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ +#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ +#define SET(bit) (A(bit) |= B(bit)) +#define CLR(bit) (A(bit) &= (~B(bit))) +#define TST(bit) (A(bit) & B(bit)) + +static void ping(const char *host); + +/* common routines */ +static int in_cksum(unsigned short *buf, int sz) +{ + int nleft = sz; + int sum = 0; + unsigned short *w = buf; + unsigned short ans = 0; + + while (nleft > 1) { + sum += *w++; + nleft -= 2; + } + + if (nleft == 1) { + *(unsigned char *) (&ans) = *(unsigned char *) w; + sum += ans; + } + + sum = (sum >> 16) + (sum & 0xFFFF); + sum += (sum >> 16); + ans = ~sum; + return (ans); +} + +/* simple version */ +#ifndef BB_FEATURE_FANCY_PING +static char *hostname = NULL; + +static void noresp(int ign) +{ + printf("No response from %s\n", hostname); + exit(0); +} + +static void ping(const char *host) +{ + struct hostent *h; + struct sockaddr_in pingaddr; + struct icmp *pkt; + int pingsock, c; + char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; + + pingsock = create_icmp_socket(); + + memset(&pingaddr, 0, sizeof(struct sockaddr_in)); + + pingaddr.sin_family = AF_INET; + h = xgethostbyname(host); + memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr)); + hostname = h->h_name; + + pkt = (struct icmp *) packet; + memset(pkt, 0, sizeof(packet)); + pkt->icmp_type = ICMP_ECHO; + pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); + + c = sendto(pingsock, packet, sizeof(packet), 0, + (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in)); + + if (c < 0 || c != sizeof(packet)) + perror_msg_and_die("sendto"); + + signal(SIGALRM, noresp); + alarm(5); /* give the host 5000ms to respond */ + /* listen for replies */ + while (1) { + struct sockaddr_in from; + socklen_t fromlen = sizeof(from); + + if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, + (struct sockaddr *) &from, &fromlen)) < 0) { + if (errno == EINTR) + continue; + perror_msg("recvfrom"); + continue; + } + if (c >= 76) { /* ip + icmp */ + struct iphdr *iphdr = (struct iphdr *) packet; + + pkt = (struct icmp *) (packet + (iphdr->ihl << 2)); /* skip ip hdr */ + if (pkt->icmp_type == ICMP_ECHOREPLY) + break; + } + } + printf("%s is alive!\n", hostname); + return; +} + +extern int ping_main(int argc, char **argv) +{ + argc--; + argv++; + if (argc < 1) + show_usage(); + ping(*argv); + return EXIT_SUCCESS; +} + +#else /* ! BB_FEATURE_FANCY_PING */ +/* full(er) version */ +static char *hostname = NULL; +static struct sockaddr_in pingaddr; +static int pingsock = -1; +static int datalen; /* intentionally uninitialized to work around gcc bug */ + +static long ntransmitted = 0, nreceived = 0, nrepeats = 0, pingcount = 0; +static int myid = 0, options = 0; +static unsigned long tmin = ULONG_MAX, tmax = 0, tsum = 0; +static char rcvd_tbl[MAX_DUP_CHK / 8]; + +static void sendping(int); +static void pingstats(int); +static void unpack(char *, int, struct sockaddr_in *); + +/**************************************************************************/ + +static void pingstats(int junk) +{ + int status; + + signal(SIGINT, SIG_IGN); + + printf("\n--- %s ping statistics ---\n", hostname); + printf("%ld packets transmitted, ", ntransmitted); + printf("%ld packets received, ", nreceived); + if (nrepeats) + printf("%ld duplicates, ", nrepeats); + if (ntransmitted) + printf("%ld%% packet loss\n", + (ntransmitted - nreceived) * 100 / ntransmitted); + if (nreceived) + printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n", + tmin / 10, tmin % 10, + (tsum / (nreceived + nrepeats)) / 10, + (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10); + if (nreceived != 0) + status = EXIT_SUCCESS; + else + status = EXIT_FAILURE; + exit(status); +} + +static void sendping(int junk) +{ + struct icmp *pkt; + int i; + char packet[datalen + 8]; + + pkt = (struct icmp *) packet; + + pkt->icmp_type = ICMP_ECHO; + pkt->icmp_code = 0; + pkt->icmp_cksum = 0; + pkt->icmp_seq = ntransmitted++; + pkt->icmp_id = myid; + CLR(pkt->icmp_seq % MAX_DUP_CHK); + + gettimeofday((struct timeval *) &packet[8], NULL); + pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); + + i = sendto(pingsock, packet, sizeof(packet), 0, + (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in)); + + if (i < 0) + perror_msg_and_die("sendto"); + else if ((size_t)i != sizeof(packet)) + error_msg_and_die("ping wrote %d chars; %d expected", i, + (int)sizeof(packet)); + + signal(SIGALRM, sendping); + if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */ + alarm(PINGINTERVAL); + } else { /* done, wait for the last ping to come back */ + /* todo, don't necessarily need to wait so long... */ + signal(SIGALRM, pingstats); + alarm(MAXWAIT); + } +} + +static char *icmp_type_name (int id) +{ + switch (id) { + case ICMP_ECHOREPLY: return "Echo Reply"; + case ICMP_DEST_UNREACH: return "Destination Unreachable"; + case ICMP_SOURCE_QUENCH: return "Source Quench"; + case ICMP_REDIRECT: return "Redirect (change route)"; + case ICMP_ECHO: return "Echo Request"; + case ICMP_TIME_EXCEEDED: return "Time Exceeded"; + case ICMP_PARAMETERPROB: return "Parameter Problem"; + case ICMP_TIMESTAMP: return "Timestamp Request"; + case ICMP_TIMESTAMPREPLY: return "Timestamp Reply"; + case ICMP_INFO_REQUEST: return "Information Request"; + case ICMP_INFO_REPLY: return "Information Reply"; + case ICMP_ADDRESS: return "Address Mask Request"; + case ICMP_ADDRESSREPLY: return "Address Mask Reply"; + default: return "unknown ICMP type"; + } +} + +static void unpack(char *buf, int sz, struct sockaddr_in *from) +{ + struct icmp *icmppkt; + struct iphdr *iphdr; + struct timeval tv, *tp; + int hlen, dupflag; + unsigned long triptime; + + gettimeofday(&tv, NULL); + + /* check IP header */ + iphdr = (struct iphdr *) buf; + hlen = iphdr->ihl << 2; + /* discard if too short */ + if (sz < (datalen + ICMP_MINLEN)) + return; + + sz -= hlen; + icmppkt = (struct icmp *) (buf + hlen); + + if (icmppkt->icmp_id != myid) + return; /* not our ping */ + + if (icmppkt->icmp_type == ICMP_ECHOREPLY) { + ++nreceived; + tp = (struct timeval *) icmppkt->icmp_data; + + if ((tv.tv_usec -= tp->tv_usec) < 0) { + --tv.tv_sec; + tv.tv_usec += 1000000; + } + tv.tv_sec -= tp->tv_sec; + + triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100); + tsum += triptime; + if (triptime < tmin) + tmin = triptime; + if (triptime > tmax) + tmax = triptime; + + if (TST(icmppkt->icmp_seq % MAX_DUP_CHK)) { + ++nrepeats; + --nreceived; + dupflag = 1; + } else { + SET(icmppkt->icmp_seq % MAX_DUP_CHK); + dupflag = 0; + } + + if (options & O_QUIET) + return; + + printf("%d bytes from %s: icmp_seq=%u", sz, + inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr), + icmppkt->icmp_seq); + printf(" ttl=%d", iphdr->ttl); + printf(" time=%lu.%lu ms", triptime / 10, triptime % 10); + if (dupflag) + printf(" (DUP!)"); + printf("\n"); + } else + if (icmppkt->icmp_type != ICMP_ECHO) + error_msg("Warning: Got ICMP %d (%s)", + icmppkt->icmp_type, icmp_type_name (icmppkt->icmp_type)); +} + +static void ping(const char *host) +{ + struct hostent *h; + char buf[MAXHOSTNAMELEN]; + char packet[datalen + MAXIPLEN + MAXICMPLEN]; + int sockopt; + + pingsock = create_icmp_socket(); + + memset(&pingaddr, 0, sizeof(struct sockaddr_in)); + + pingaddr.sin_family = AF_INET; + h = xgethostbyname(host); + if (h->h_addrtype != AF_INET) + error_msg_and_die("unknown address type; only AF_INET is currently supported."); + + memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr)); + strncpy(buf, h->h_name, sizeof(buf) - 1); + hostname = buf; + + /* enable broadcast pings */ + sockopt = 1; + setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt, + sizeof(sockopt)); + + /* set recv buf for broadcast pings */ + sockopt = 48 * 1024; + setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt, + sizeof(sockopt)); + + printf("PING %s (%s): %d data bytes\n", + hostname, + inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr), + datalen); + + signal(SIGINT, pingstats); + + /* start the ping's going ... */ + sendping(0); + + /* listen for replies */ + while (1) { + struct sockaddr_in from; + socklen_t fromlen = (socklen_t) sizeof(from); + int c; + + if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, + (struct sockaddr *) &from, &fromlen)) < 0) { + if (errno == EINTR) + continue; + perror_msg("recvfrom"); + continue; + } + unpack(packet, c, &from); + if (pingcount > 0 && nreceived >= pingcount) + break; + } + pingstats(0); +} + +extern int ping_main(int argc, char **argv) +{ + char *thisarg; + + datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */ + + argc--; + argv++; + options = 0; + /* Parse any options */ + while (argc >= 1 && **argv == '-') { + thisarg = *argv; + thisarg++; + switch (*thisarg) { + case 'q': + options |= O_QUIET; + break; + case 'c': + if (--argc <= 0) + show_usage(); + argv++; + pingcount = atoi(*argv); + break; + case 's': + if (--argc <= 0) + show_usage(); + argv++; + datalen = atoi(*argv); + break; + default: + show_usage(); + } + argc--; + argv++; + } + if (argc < 1) + show_usage(); + + myid = getpid() & 0xFFFF; + ping(*argv); + return EXIT_SUCCESS; +} +#endif /* ! BB_FEATURE_FANCY_PING */ + +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Muuss. + * + * 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. + */ diff --git a/pivot_root.c b/pivot_root.c new file mode 100644 index 000000000..ba26b9c58 --- /dev/null +++ b/pivot_root.c @@ -0,0 +1,35 @@ +/* vi: set sw=4 ts=4: */ +/* + * pivot_root.c - Change root file system. Based on util-linux 2.10s + * + * busyboxed by Evin Robertson + * pivot_root syscall stubbed by Erik Andersen, so it will compile + * regardless of the kernel being used. + */ +#include +#include +#include +#include "busybox.h" + +extern int pivot_root(const char * new_root,const char * put_old); + +int pivot_root_main(int argc, char **argv) +{ + if (argc != 3) + show_usage(); + + if (pivot_root(argv[1],argv[2]) < 0) + perror_msg_and_die("pivot_root"); + + return EXIT_SUCCESS; + +} + + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/poweroff.c b/poweroff.c new file mode 100644 index 000000000..443b70fd1 --- /dev/null +++ b/poweroff.c @@ -0,0 +1,41 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini poweroff implementation for busybox + * + * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 1999-2002 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 + * + */ + +#include "busybox.h" +#include + +extern int poweroff_main(int argc, char **argv) +{ +#ifdef BB_FEATURE_LINUXRC + /* don't assume init's pid == 1 */ + long *pid = find_pid_by_name("init"); + if (!pid || *pid<=0) { + pid = find_pid_by_name("linuxrc"); + if (!pid || *pid<=0) + error_msg_and_die("no process killed"); + } + return(kill(*pid, SIGUSR2)); +#else + return(kill(1, SIGUSR2)); +#endif +} diff --git a/printf.c b/printf.c new file mode 100644 index 000000000..d579a9b4e --- /dev/null +++ b/printf.c @@ -0,0 +1,455 @@ +/* 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. + + 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. */ + +/* Usage: printf format [argument...] + + A front end to the printf function that lets it be used from the shell. + + Backslash escapes: + + \" = double quote + \\ = backslash + \a = alert (bell) + \b = backspace + \c = produce no further output + \f = form feed + \n = new line + \r = carriage return + \t = horizontal tab + \v = vertical tab + \0ooo = octal number (ooo is 0 to 3 digits) + \xhhh = hexadecimal number (hhh is 1 to 3 digits) + + Additional directive: + + %b = print an argument string, interpreting backslash escapes + + The `format' argument is re-used as many times as necessary + to convert all of the given arguments. + + David MacKenzie */ + + +// 19990508 Busy Boxed! Dave Cinege + +#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)); +static void verify __P((char *s, char *end)); + +/* The value to return to the calling program. */ +static int exit_status; + +int printf_main(int argc, char **argv) +{ + char *format; + int args_used; + + exit_status = 0; + if (argc <= 1 || **(argv + 1) == '-') { + show_usage(); + } + + format = argv[1]; + argc -= 2; + argv += 2; + + do { + args_used = print_formatted(format, argc, argv); + argc -= args_used; + argv += args_used; + } + while (args_used > 0 && argc > 0); + +/* + if (argc > 0) + fprintf(stderr, "excess args ignored"); +*/ + + return(exit_status); +} + +/* Print the text in FORMAT, using ARGV (with ARGC elements) for + arguments to any `%' directives. + Return the number of elements of ARGV used. */ + +static int print_formatted(char *format, int argc, 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) { + switch (*f) { + case '%': + direc_start = f++; + direc_length = 1; + field_width = precision = -1; + if (*f == '%') { + putchar('%'); + break; + } + if (*f == 'b') { + if (argc > 0) { + print_esc_string(*argv); + ++argv; + --argc; + } + break; + } + if (strchr("-+ #", *f)) { + ++f; + ++direc_length; + } + if (*f == '*') { + ++f; + ++direc_length; + if (argc > 0) { + field_width = xstrtoul(*argv); + ++argv; + --argc; + } else + field_width = 0; + } 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)) { + ++f; + ++direc_length; + } + } + if (*f == 'l' || *f == 'L' || *f == 'h') { + ++f; + ++direc_length; + } + /* + 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); + break; + + default: + putchar(*f); + } + } + + return save_argc - argc; +} + +/* 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) +{ + 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); + } + break; + } + + free(p); +} + +static unsigned long xstrtoul(char *s) +{ + char *end; + unsigned long val; + + errno = 0; + val = strtoul(s, &end, 0); + verify(s, end); + return val; +} + +static long xstrtol(char *s) +{ + char *end; + long val; + + errno = 0; + val = strtol(s, &end, 0); + verify(s, end); + return val; +} + +static double xstrtod(char *s) +{ + char *end; + double val; + + errno = 0; + val = strtod(s, &end); + verify(s, end); + return val; +} + +static void verify(char *s, char *end) +{ + if (errno) { + fprintf(stderr, "%s", s); + exit_status = 1; + } else if (*end) { + /* + if (s == end) + fprintf(stderr, "%s: expected numeric", s); + else + fprintf(stderr, "%s: not completely converted", s); + */ + exit_status = 1; + } +} diff --git a/pristine_setup.sh b/pristine_setup.sh new file mode 100755 index 000000000..62f3f3075 --- /dev/null +++ b/pristine_setup.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# +# To compile BusyBox without touching the original sources +# (as might be interesting for multi-target builds), create +# an empty directory, cd into it, and run this program by +# giving its explicit path (kind of like how you would run +# configure, if BusyBox had one). Then you should be ready +# to "make". Files in the build tree, in particular Config.h, +# will override those in the pristine source tree. +# +# If you use a ? in your path name, you lose, see sed command below. + +export LC_ALL=POSIX +export LC_CTYPE=POSIX + +DIR=${0%%/pristine_setup.sh} +if [ ! -d $DIR ]; then + echo "unexpected problem: $DIR is not a directory. Aborting pristine setup" + exit +fi + +echo " " + +if [ -e ./Config.h ]; then + echo "./Config.h already exists: not overwriting" + exit +fi + +if [ -e ./Makefile ]; then + echo "./Makefile already exists: not overwriting" +fi + +sed -e "s?BB_SRC_DIR =.*?BB_SRC_DIR = $DIR?" <$DIR/Makefile >Makefile || exit +cp $DIR/Config.h Config.h || exit +#mkdir -p pwd_grp + +echo " " +echo "You may now type 'make' to build busybox in this directory" +echo "($PWD) using the pristine sources in $DIR" +echo " " + diff --git a/ps.c b/ps.c new file mode 100644 index 000000000..d16d55b18 --- /dev/null +++ b/ps.c @@ -0,0 +1,384 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini ps implementation(s) for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen + * + * + * This contains _two_ implementations of ps for Linux. One uses the + * traditional /proc virtual filesystem, and the other use the devps kernel + * driver (written by Erik Andersen to avoid using /proc thereby saving 100k+). + * + * + * + * 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 +#include +#include "busybox.h" + +static const int TERMINAL_WIDTH = 79; /* not 80 in case terminal has linefold bug */ + + + +#if ! defined BB_FEATURE_USE_DEVPS_PATCH + +/* The following is the first ps implementation -- + * the one using the /proc virtual filesystem. + */ + +typedef struct proc_s { + char cmd[16]; /* basename of executable file in call to exec(2) */ + int ruid; /* real only (sorry) */ + int pid; /* process id */ + int ppid; /* pid of parent process */ + char state; /* single-char code for process state (S=sleeping) */ + unsigned int vmsize; /* size of process as far as the vm is concerned */ + char ttyname[9]; /* tty device */ +} proc_t; + + + +static int file2str(char *filename, char *ret, int cap) +{ + int fd, num_read; + + if ((fd = open(filename, O_RDONLY, 0)) == -1) + return -1; + if ((num_read = read(fd, ret, cap - 1)) <= 0) + return -1; + ret[num_read] = 0; + close(fd); + return num_read; +} + + +static char master[] = "pqrstuvwxyzabcde"; +#define MAJOR(x) ((x) >> 8) +#define MINOR(x) ((x) & 0xff) + +static void dev_to_name(dev_t dev, char *name) +{ + if (MAJOR(dev) == TTY_MAJOR) + if (MINOR(dev) < 64) + sprintf(name,"tty%d", (int)MINOR(dev)); + else + sprintf(name,"ttyS%d", (int)MINOR(dev)-64); + else if (MAJOR(dev) == PTY_SLAVE_MAJOR) + sprintf(name,"tty%c%x", master[MINOR(dev) / 16], (int)MINOR(dev) & 0xf); + else + strcpy(name, ""); +} + + +static void parse_proc_status(char *S, proc_t * P) +{ + char *tmp; + + memset(P->cmd, 0, sizeof P->cmd); + sscanf(S, "Name:\t%15c", P->cmd); + tmp = strchr(P->cmd, '\n'); + if (tmp) + *tmp = '\0'; + tmp = strstr(S, "State"); + sscanf(tmp, "State:\t%c", &P->state); + + P->vmsize = 0; + tmp = strstr(S, "Pid:"); + if (tmp) + sscanf(tmp, "Pid:\t%d\n" "PPid:\t%d\n", &P->pid, &P->ppid); + else + error_msg("Internal error!"); + + /* For busybox, ignoring effective, saved, etc. */ + tmp = strstr(S, "Uid:"); + if (tmp) + sscanf(tmp, "Uid:\t%d", &P->ruid); + else + error_msg("Internal error!"); + + P->vmsize = 0; + if ((tmp = strstr(S, "VmSize:")) != NULL) + sscanf(tmp, "VmSize:\t%d", &P->vmsize); + else if ((tmp = strstr(S, "Mem:")) != NULL) + sscanf(tmp, "MemSize:\t%d", &P->vmsize); +#if 0 + else + error_msg("Internal error!"); +#endif +} + + +static void parse_proc_stat(char *S, proc_t * P) +{ + char *tmp; + + /* pid (name) */ + tmp = strrchr(S, ')'); + /* state */ + tmp += 4; + /* ppid */ + tmp = strchr(tmp, ' ')+1; + /* pgrp */ + tmp = strchr(tmp, ' ')+1; + /* session */ + tmp = strchr(tmp, ' ')+1; + /* tty */ + dev_to_name(atoi(tmp), P->ttyname); + tmp = strchr(tmp, ' ')+1; + +#if 0 + /* tty_pgrp */ + tmp = strchr(tmp, ' ')+1; + /* flags */ + tmp = strchr(tmp, ' ')+1; + /* min_flt */ + tmp = strchr(tmp, ' ')+1; + /* cmin_flt */ + tmp = strchr(tmp, ' ')+1; + /* maj_flt */ + tmp = strchr(tmp, ' ')+1; + /* cmaj_flt */ + tmp = strchr(tmp, ' ')+1; + /* utime */ + tmp = strchr(tmp, ' ')+1; + /* stime */ + tmp = strchr(tmp, ' ')+1; + /* cutime */ + tmp = strchr(tmp, ' ')+1; + /* cstime */ + tmp = strchr(tmp, ' ')+1; + /* priority */ + tmp = strchr(tmp, ' ')+1; + /* nice */ + tmp = strchr(tmp, ' ')+1; + /* timeout */ + tmp = strchr(tmp, ' ')+1; + /* it_real_value */ + tmp = strchr(tmp, ' ')+1; + /* start_time */ + tmp = strchr(tmp, ' ')+1; + /* vsize */ + tmp = strchr(tmp, ' ')+1; + /* rss */ + tmp = strchr(tmp, ' ')+1; + /* rsslim*/ + tmp = strchr(tmp, ' ')+1; + /* start_code */ + tmp = strchr(tmp, ' ')+1; + /* end_code */ + tmp = strchr(tmp, ' ')+1; + /* start_stack */ + tmp = strchr(tmp, ' ')+1; + /* sp */ + tmp = strchr(tmp, ' ')+1; + /* ip */ + tmp = strchr(tmp, ' ')+1; + /* signal */ + tmp = strchr(tmp, ' ')+1; + /* blocked */ + tmp = strchr(tmp, ' ')+1; + /* sigignore */ + tmp = strchr(tmp, ' ')+1; + /* sigcatch */ + tmp = strchr(tmp, ' ')+1; + /* wchan */ + tmp = strchr(tmp, ' ')+1; + /* nswap */ + tmp = strchr(tmp, ' ')+1; + /* cnswap */ + tmp = strchr(tmp, ' ')+1; +#endif +} + + +extern int ps_main(int argc, char **argv) +{ + proc_t p; + DIR *dir; + FILE *file; + struct dirent *entry; + char path[32], sbuf[512]; + char uidName[9]; + int len, i, c; +#ifdef BB_FEATURE_AUTOWIDTH + struct winsize win = { 0, 0, 0, 0 }; + int terminal_width = TERMINAL_WIDTH; +#else +#define terminal_width TERMINAL_WIDTH +#endif + + + + dir = opendir("/proc"); + if (!dir) + error_msg_and_die("Can't open /proc"); + +#ifdef BB_FEATURE_AUTOWIDTH + ioctl(fileno(stdout), TIOCGWINSZ, &win); + if (win.ws_col > 0) + terminal_width = win.ws_col - 1; +#endif + + printf("%5s %-7s %-8s %6s %5s %s\n", "PID", "TTY", "Uid", + "Size", "State", "Command"); + while ((entry = readdir(dir)) != NULL) { + if (!isdigit(*entry->d_name)) + continue; + sprintf(path, "/proc/%s/status", entry->d_name); + if ((file2str(path, sbuf, sizeof sbuf)) != -1) { + parse_proc_status(sbuf, &p); + } + + sprintf(path, "/proc/%s/stat", entry->d_name); + if ((file2str(path, sbuf, sizeof sbuf)) != -1) { + parse_proc_stat(sbuf, &p); + } + + /* Make some adjustments as needed */ + my_getpwuid(uidName, p.ruid); + if (*uidName == '\0') + sprintf(uidName, "%d", p.ruid); + + sprintf(path, "/proc/%s/cmdline", entry->d_name); + file = fopen(path, "r"); + if (file == NULL) + continue; + i = 0; + len = printf("%5d %-7s %-8s %6d %c ", + p.pid, p.ttyname, uidName, p.vmsize, p.state); + while (((c = getc(file)) != EOF) && (i < (terminal_width-len))) { + i++; + if (c == '\0') + c = ' '; + putc(c, stdout); + } + fclose(file); + if (i == 0) + printf("[%s]", p.cmd); + putchar('\n'); + } + closedir(dir); + return EXIT_SUCCESS; +} + + +#else /* BB_FEATURE_USE_DEVPS_PATCH */ + + +/* The following is the second ps implementation -- + * this one uses the nifty new devps kernel device. + */ + +#include /* For Erik's nifty devps device driver */ + + +extern int ps_main(int argc, char **argv) +{ + char device[] = "/dev/ps"; + int i, j, len, fd; + pid_t num_pids; + pid_t* pid_array = NULL; + struct pid_info info; + char uidName[9]; +#ifdef BB_FEATURE_AUTOWIDTH + struct winsize win = { 0, 0, 0, 0 }; + int terminal_width = TERMINAL_WIDTH; +#else +#define terminal_width TERMINAL_WIDTH +#endif + + if (argc > 1 && **(argv + 1) == '-') + show_usage(); + + /* open device */ + fd = open(device, O_RDONLY); + if (fd < 0) + perror_msg_and_die( "open failed for `%s'", device); + + /* Find out how many processes there are */ + if (ioctl (fd, DEVPS_GET_NUM_PIDS, &num_pids)<0) + perror_msg_and_die( "\nDEVPS_GET_PID_LIST"); + + /* Allocate some memory -- grab a few extras just in case + * some new processes start up while we wait. The kernel will + * just ignore any extras if we give it too many, and will trunc. + * the list if we give it too few. */ + pid_array = (pid_t*) xcalloc( num_pids+10, sizeof(pid_t)); + pid_array[0] = num_pids+10; + + /* Now grab the pid list */ + if (ioctl (fd, DEVPS_GET_PID_LIST, pid_array)<0) + perror_msg_and_die("\nDEVPS_GET_PID_LIST"); + +#ifdef BB_FEATURE_AUTOWIDTH + ioctl(fileno(stdout), TIOCGWINSZ, &win); + if (win.ws_col > 0) + terminal_width = win.ws_col - 1; +#endif + + /* Print up a ps listing */ + printf(" PID Uid Stat Command\n"); + + for (i=1; i 1) { + for( j=0; j<(sizeof(info.command_line)-1) && j < (terminal_width-len); j++) { + if (*(info.command_line+j) == '\0' && *(info.command_line+j+1) != '\0') { + *(info.command_line+j) = ' '; + } + } + *(info.command_line+j) = '\0'; + puts(info.command_line); + } else { + printf("[%s]\n", info.name); + } + } + + /* Free memory */ + free( pid_array); + + /* close device */ + if (close (fd) != 0) + perror_msg_and_die("close failed for `%s'", device); + + exit (0); +} + +#endif /* BB_FEATURE_USE_DEVPS_PATCH */ + diff --git a/pwd.c b/pwd.c new file mode 100644 index 000000000..9c5d70cef --- /dev/null +++ b/pwd.c @@ -0,0 +1,43 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini pwd implementation for busybox + * + * 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 + * + */ + +/* getopt not needed */ + +#include +#include +#include +#include +#include +#include "busybox.h" + +extern int pwd_main(int argc, char **argv) +{ + static char *buf; + + buf = xgetcwd(buf); + + if (buf != NULL) { + puts(buf); + return EXIT_SUCCESS; + } + return EXIT_FAILURE; +} diff --git a/pwd_grp/.indent.pro b/pwd_grp/.indent.pro new file mode 100644 index 000000000..492ecf1c7 --- /dev/null +++ b/pwd_grp/.indent.pro @@ -0,0 +1,33 @@ +--blank-lines-after-declarations +--blank-lines-after-procedures +--break-before-boolean-operator +--no-blank-lines-after-commas +--braces-on-if-line +--braces-on-struct-decl-line +--comment-indentation25 +--declaration-comment-column25 +--no-comment-delimiters-on-blank-lines +--cuddle-else +--continuation-indentation4 +--case-indentation0 +--else-endif-column33 +--space-after-cast +--line-comments-indentation0 +--declaration-indentation1 +--dont-format-first-column-comments +--dont-format-comments +--honour-newlines +--indent-level4 +/* changed from 0 to 4 */ +--parameter-indentation4 +--line-length78 /* changed from 75 */ +--continue-at-parentheses +--no-space-after-function-call-names +--dont-break-procedure-type +--dont-star-comments +--leave-optional-blank-lines +--dont-space-special-semicolon +--tab-size4 +/* additions by Mark */ +--case-brace-indentation0 +--leave-preprocessor-space diff --git a/pwd_grp/__getgrent.c b/pwd_grp/__getgrent.c new file mode 100644 index 000000000..ffdfb7535 --- /dev/null +++ b/pwd_grp/__getgrent.c @@ -0,0 +1,162 @@ +/* + * __getgrent.c - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include "grp.h" +#include "config.h" + +/* + * This is the core group-file read function. It behaves exactly like + * getgrent() except that it is passed a file descriptor. getgrent() + * is just a wrapper for this function. + */ +struct group *__getgrent(int grp_fd) +{ +#ifndef GR_SCALE_DYNAMIC + static char line_buff[GR_MAX_LINE_LEN]; + static char *members[GR_MAX_MEMBERS]; +#else + static char *line_buff = NULL; + static char **members = NULL; + short line_index; + short buff_size; +#endif + static struct group group; + register char *ptr; + char *field_begin; + int member_num; + char *endptr; + int line_len; + + + /* We use the restart label to handle malformatted lines */ + restart: +#ifdef GR_SCALE_DYNAMIC + line_index = 0; + buff_size = 256; +#endif + +#ifndef GR_SCALE_DYNAMIC + /* Read the line into the static buffer */ + if ((line_len = read(grp_fd, line_buff, GR_MAX_LINE_LEN)) <= 0) + return NULL; + field_begin = strchr(line_buff, '\n'); + if (field_begin != NULL) + lseek(grp_fd, (long) (1 + field_begin - (line_buff + line_len)), + SEEK_CUR); + else { /* The line is too long - skip it :-\ */ + + do { + if ((line_len = read(grp_fd, line_buff, GR_MAX_LINE_LEN)) <= 0) + return NULL; + } while (!(field_begin = strchr(line_buff, '\n'))); + lseek(grp_fd, (long) ((field_begin - line_buff) - line_len + 1), + SEEK_CUR); + goto restart; + } + if (*line_buff == '#' || *line_buff == ' ' || *line_buff == '\n' || + *line_buff == '\t') + goto restart; + *field_begin = '\0'; + +#else /* !GR_SCALE_DYNAMIC */ + line_buff = realloc(line_buff, buff_size); + while (1) { + if ((line_len = read(grp_fd, line_buff + line_index, + buff_size - line_index)) <= 0) + return NULL; + field_begin = strchr(line_buff, '\n'); + if (field_begin != NULL) { + lseek(grp_fd, + (long) (1 + field_begin - + (line_len + line_index + line_buff)), SEEK_CUR); + *field_begin = '\0'; + if (*line_buff == '#' || *line_buff == ' ' + || *line_buff == '\n' || *line_buff == '\t') + goto restart; + break; + } else { /* Allocate some more space */ + + line_index = buff_size; + buff_size += 256; + line_buff = realloc(line_buff, buff_size); + } + } +#endif /* GR_SCALE_DYNAMIC */ + + /* Now parse the line */ + group.gr_name = line_buff; + ptr = strchr(line_buff, ':'); + if (ptr == NULL) + goto restart; + *ptr++ = '\0'; + + group.gr_passwd = ptr; + ptr = strchr(ptr, ':'); + if (ptr == NULL) + goto restart; + *ptr++ = '\0'; + + field_begin = ptr; + ptr = strchr(ptr, ':'); + if (ptr == NULL) + goto restart; + *ptr++ = '\0'; + + group.gr_gid = (gid_t) strtoul(field_begin, &endptr, 10); + if (*endptr != '\0') + goto restart; + + member_num = 0; + field_begin = ptr; + +#ifndef GR_SCALE_DYNAMIC + while ((ptr = strchr(ptr, ',')) != NULL) { + *ptr = '\0'; + ptr++; + members[member_num] = field_begin; + field_begin = ptr; + member_num++; + } + if (*field_begin == '\0') + members[member_num] = NULL; + else { + members[member_num] = field_begin; + members[member_num + 1] = NULL; + } +#else /* !GR_SCALE_DYNAMIC */ + if (members != NULL) + free(members); + members = (char **) malloc((member_num + 1) * sizeof(char *)); + for ( ; field_begin && *field_begin != '\0'; field_begin = ptr) { + if ((ptr = strchr(field_begin, ',')) != NULL) + *ptr++ = '\0'; + members[member_num++] = field_begin; + members = (char **) realloc(members, + (member_num + 1) * sizeof(char *)); + } + members[member_num] = NULL; +#endif /* GR_SCALE_DYNAMIC */ + + group.gr_mem = members; + return &group; +} diff --git a/pwd_grp/__getpwent.c b/pwd_grp/__getpwent.c new file mode 100644 index 000000000..f60bfec7c --- /dev/null +++ b/pwd_grp/__getpwent.c @@ -0,0 +1,113 @@ +/* + * __getpwent.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include "pwd.h" + +#define PWD_BUFFER_SIZE 256 + +/* This isn't as flash as my previous version -- it doesn't dynamically + scale down the gecos on too-long lines, but it also makes fewer syscalls, + so it's probably nicer. Write me if you want the old version. Maybe I + should include it as a build-time option... ? + -Nat */ + +struct passwd *__getpwent(int pwd_fd) +{ + static char line_buff[PWD_BUFFER_SIZE]; + static struct passwd passwd; + char *field_begin; + char *endptr; + char *gid_ptr=NULL; + char *uid_ptr=NULL; + int line_len; + int i; + + /* We use the restart label to handle malformatted lines */ + restart: + /* Read the passwd line into the static buffer using a minimal of + syscalls. */ + if ((line_len = read(pwd_fd, line_buff, PWD_BUFFER_SIZE)) <= 0) + return NULL; + field_begin = strchr(line_buff, '\n'); + if (field_begin != NULL) + lseek(pwd_fd, (long) (1 + field_begin - (line_buff + line_len)), + SEEK_CUR); + else { /* The line is too long - skip it. :-\ */ + + do { + if ((line_len = read(pwd_fd, line_buff, PWD_BUFFER_SIZE)) <= 0) + return NULL; + } while (!(field_begin = strchr(line_buff, '\n'))); + lseek(pwd_fd, (long) (field_begin - line_buff) - line_len + 1, + SEEK_CUR); + goto restart; + } + if (*line_buff == '#' || *line_buff == ' ' || *line_buff == '\n' || + *line_buff == '\t') + goto restart; + *field_begin = '\0'; + + /* We've read the line; now parse it. */ + field_begin = line_buff; + for (i = 0; i < 7; i++) { + switch (i) { + case 0: + passwd.pw_name = field_begin; + break; + case 1: + passwd.pw_passwd = field_begin; + break; + case 2: + uid_ptr = field_begin; + break; + case 3: + gid_ptr = field_begin; + break; + case 4: + passwd.pw_gecos = field_begin; + break; + case 5: + passwd.pw_dir = field_begin; + break; + case 6: + passwd.pw_shell = field_begin; + break; + } + if (i < 6) { + field_begin = strchr(field_begin, ':'); + if (field_begin == NULL) + goto restart; + *field_begin++ = '\0'; + } + } + passwd.pw_gid = (gid_t) strtoul(gid_ptr, &endptr, 10); + if (*endptr != '\0') + goto restart; + + passwd.pw_uid = (uid_t) strtoul(uid_ptr, &endptr, 10); + if (*endptr != '\0') + goto restart; + + return &passwd; +} diff --git a/pwd_grp/config.h b/pwd_grp/config.h new file mode 100644 index 000000000..eb029a31a --- /dev/null +++ b/pwd_grp/config.h @@ -0,0 +1,65 @@ +/* + * config.h - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +#ifndef _CONFIG_GRP_H +#define _CONFIG_GRP_H + +/* + * Define GR_SCALE_DYNAMIC if you want grp to dynamically scale its read buffer + * so that lines of any length can be used. On very very small systems, + * you may want to leave this undefined becasue it will make the grp functions + * somewhat larger (because of the inclusion of malloc and the code necessary). + * On larger systems, you will want to define this, because grp will _not_ + * deal with long lines gracefully (they will be skipped). + */ +#undef GR_SCALE_DYNAMIC + +#ifndef GR_SCALE_DYNAMIC +/* + * If scaling is not dynamic, the buffers will be statically allocated, and + * maximums must be chosen. GR_MAX_LINE_LEN is the maximum number of + * characters per line in the group file. GR_MAX_MEMBERS is the maximum + * number of members of any given group. + */ +#define GR_MAX_LINE_LEN 128 +/* GR_MAX_MEMBERS = (GR_MAX_LINE_LEN-(24+3+6))/9 */ +#define GR_MAX_MEMBERS 11 + +#endif /* !GR_SCALE_DYNAMIC */ + + +/* + * Define GR_DYNAMIC_GROUP_LIST to make initgroups() dynamically allocate + * space for it's GID array before calling setgroups(). This is probably + * unnecessary scalage, so it's undefined by default. + */ +#undef GR_DYNAMIC_GROUP_LIST + +#ifndef GR_DYNAMIC_GROUP_LIST +/* + * GR_MAX_GROUPS is the size of the static array initgroups() uses for + * its static GID array if GR_DYNAMIC_GROUP_LIST isn't defined. + */ +#define GR_MAX_GROUPS 64 + +#endif /* !GR_DYNAMIC_GROUP_LIST */ + +#endif /* !_CONFIG_GRP_H */ diff --git a/pwd_grp/fgetgrent.c b/pwd_grp/fgetgrent.c new file mode 100644 index 000000000..cefe6e7a1 --- /dev/null +++ b/pwd_grp/fgetgrent.c @@ -0,0 +1,33 @@ +/* + * fgetgrent.c - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include "grp.h" + +struct group *fgetgrent(FILE * file) +{ + if (file == NULL) { + errno = EINTR; + return NULL; + } + + return __getgrent(fileno(file)); +} diff --git a/pwd_grp/fgetpwent.c b/pwd_grp/fgetpwent.c new file mode 100644 index 000000000..294d334a0 --- /dev/null +++ b/pwd_grp/fgetpwent.c @@ -0,0 +1,33 @@ +/* + * fgetpwent.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include "pwd.h" + +struct passwd *fgetpwent(FILE * file) +{ + if (file == NULL) { + errno = EINTR; + return NULL; + } + + return __getpwent(fileno(file)); +} diff --git a/pwd_grp/getgrgid.c b/pwd_grp/getgrgid.c new file mode 100644 index 000000000..620a853cb --- /dev/null +++ b/pwd_grp/getgrgid.c @@ -0,0 +1,42 @@ +/* + * getgrgid.c - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include "grp.h" + +struct group *getgrgid(const gid_t gid) +{ + struct group *group; + int grp_fd; + + if ((grp_fd = open("/etc/group", O_RDONLY)) < 0) + return NULL; + + while ((group = __getgrent(grp_fd)) != NULL) + if (group->gr_gid == gid) { + close(grp_fd); + return group; + } + + close(grp_fd); + return NULL; +} diff --git a/pwd_grp/getgrnam.c b/pwd_grp/getgrnam.c new file mode 100644 index 000000000..55825b1a8 --- /dev/null +++ b/pwd_grp/getgrnam.c @@ -0,0 +1,48 @@ +/* + * getgrnam.c - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include "grp.h" + +struct group *getgrnam(const char *name) +{ + int grp_fd; + struct group *group; + + if (name == NULL) { + errno = EINVAL; + return NULL; + } + + if ((grp_fd = open("/etc/group", O_RDONLY)) < 0) + return NULL; + + while ((group = __getgrent(grp_fd)) != NULL) + if (!strcmp(group->gr_name, name)) { + close(grp_fd); + return group; + } + + close(grp_fd); + return NULL; +} diff --git a/pwd_grp/getpw.c b/pwd_grp/getpw.c new file mode 100644 index 000000000..dc33da235 --- /dev/null +++ b/pwd_grp/getpw.c @@ -0,0 +1,45 @@ +/* + * getpw.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include "pwd.h" + +int getpw(uid_t uid, char *buf) +{ + struct passwd *passwd; + + if (buf == NULL) { + errno = EINVAL; + return -1; + } + if ((passwd = getpwuid(uid)) == NULL) + return -1; + + if (sprintf (buf, "%s:%s:%u:%u:%s:%s:%s", passwd->pw_name, passwd->pw_passwd, + passwd->pw_gid, passwd->pw_uid, passwd->pw_gecos, passwd->pw_dir, + passwd->pw_shell) < 0) { + errno = ENOBUFS; + return -1; + } + + return 0; +} diff --git a/pwd_grp/getpwnam.c b/pwd_grp/getpwnam.c new file mode 100644 index 000000000..cdd165535 --- /dev/null +++ b/pwd_grp/getpwnam.c @@ -0,0 +1,49 @@ +/* + * getpwnam.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include "pwd.h" + + +struct passwd *getpwnam(const char *name) +{ + int passwd_fd; + struct passwd *passwd; + + if (name == NULL) { + errno = EINVAL; + return NULL; + } + + if ((passwd_fd = open("/etc/passwd", O_RDONLY)) < 0) + return NULL; + + while ((passwd = __getpwent(passwd_fd)) != NULL) + if (!strcmp(passwd->pw_name, name)) { + close(passwd_fd); + return passwd; + } + + close(passwd_fd); + return NULL; +} diff --git a/pwd_grp/getpwuid.c b/pwd_grp/getpwuid.c new file mode 100644 index 000000000..7182119a5 --- /dev/null +++ b/pwd_grp/getpwuid.c @@ -0,0 +1,42 @@ +/* + * getpwuid.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include "pwd.h" + +struct passwd *getpwuid(uid_t uid) +{ + int passwd_fd; + struct passwd *passwd; + + if ((passwd_fd = open("/etc/passwd", O_RDONLY)) < 0) + return NULL; + + while ((passwd = __getpwent(passwd_fd)) != NULL) + if (passwd->pw_uid == uid) { + close(passwd_fd); + return passwd; + } + + close(passwd_fd); + return NULL; +} diff --git a/pwd_grp/grent.c b/pwd_grp/grent.c new file mode 100644 index 000000000..7e162366c --- /dev/null +++ b/pwd_grp/grent.c @@ -0,0 +1,52 @@ +/* + * grent.c - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * setgrent(), endgrent(), and getgrent() are mutually-dependent functions, + * so they are all included in the same object file, and thus all linked + * in together. + */ + +#include +#include +#include "grp.h" + +static int grp_fd = -1; + +void setgrent(void) +{ + if (grp_fd != -1) + close(grp_fd); + grp_fd = open("/etc/group", O_RDONLY); +} + +void endgrent(void) +{ + if (grp_fd != -1) + close(grp_fd); + grp_fd = -1; +} + +struct group *getgrent(void) +{ + if (grp_fd == -1) + return NULL; + return __getgrent(grp_fd); +} diff --git a/pwd_grp/grp.h b/pwd_grp/grp.h new file mode 100644 index 000000000..87d4115ce --- /dev/null +++ b/pwd_grp/grp.h @@ -0,0 +1,37 @@ +#ifndef __BB_GRP_H +#define __BB_GRP_H + +#if defined USE_SYSTEM_PWD_GRP +#include +#else + +#include +#include +#include + +/* The group structure */ +struct group +{ + char *gr_name; /* Group name. */ + char *gr_passwd; /* Password. */ + gid_t gr_gid; /* Group ID. */ + char **gr_mem; /* Member list. */ +}; + +extern void setgrent __P ((void)); +extern void endgrent __P ((void)); +extern struct group * getgrent __P ((void)); + +extern struct group * getgrgid __P ((__const gid_t gid)); +extern struct group * getgrnam __P ((__const char * name)); + +extern struct group * fgetgrent __P ((FILE * file)); + +extern int setgroups __P ((size_t n, __const gid_t * groups)); +extern int initgroups __P ((__const char * user, gid_t gid)); + +extern struct group * __getgrent __P ((int grp_fd)); + +#endif /* USE_SYSTEM_PWD_GRP */ +#endif /* __BB_GRP_H */ + diff --git a/pwd_grp/initgroups.c b/pwd_grp/initgroups.c new file mode 100644 index 000000000..d45baddae --- /dev/null +++ b/pwd_grp/initgroups.c @@ -0,0 +1,74 @@ +/* + * initgroups.c - This file is part of the libc-8086/grp package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include "grp.h" +#include "config.h" + +int initgroups(__const char *user, gid_t gid) +{ + register struct group *group; + +#ifndef GR_DYNAMIC_GROUP_LIST + gid_t group_list[GR_MAX_GROUPS]; +#else + gid_t *group_list = NULL; +#endif + register char **tmp_mem; + int num_groups; + int grp_fd; + + + if ((grp_fd = open("/etc/group", O_RDONLY)) < 0) + return -1; + + num_groups = 0; +#ifdef GR_DYNAMIC_GROUP_LIST + group_list = (gid_t *) realloc(group_list, 1); +#endif + group_list[num_groups] = gid; +#ifndef GR_DYNAMIC_GROUP_LIST + while (num_groups < GR_MAX_GROUPS && + (group = __getgrent(grp_fd)) != NULL) +#else + while ((group = __getgrent(grp_fd)) != NULL) +#endif + { + if (group->gr_gid != gid) + { + tmp_mem = group->gr_mem; + while (*tmp_mem != NULL) { + if (!strcmp(*tmp_mem, user)) { + num_groups++; +#ifdef GR_DYNAMIC_GROUP_LIST + group_list = (gid_t *) realloc(group_list, num_groups * + sizeof(gid_t *)); +#endif + group_list[num_groups-1] = group->gr_gid; + } + tmp_mem++; + } + } + } + close(grp_fd); + return setgroups(num_groups, group_list); +} diff --git a/pwd_grp/putpwent.c b/pwd_grp/putpwent.c new file mode 100644 index 000000000..a54fde685 --- /dev/null +++ b/pwd_grp/putpwent.c @@ -0,0 +1,37 @@ +/* + * putpwent.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include "pwd.h" + +int putpwent(const struct passwd *passwd, FILE * f) +{ + if (passwd == NULL || f == NULL) { + errno = EINVAL; + return -1; + } + if (fprintf (f, "%s:%s:%u:%u:%s:%s:%s\n", passwd->pw_name, passwd->pw_passwd, + passwd->pw_uid, passwd->pw_gid, passwd->pw_gecos, passwd->pw_dir, + passwd->pw_shell) < 0) + return -1; + + return 0; +} diff --git a/pwd_grp/pwd.h b/pwd_grp/pwd.h new file mode 100644 index 000000000..e603a96e3 --- /dev/null +++ b/pwd_grp/pwd.h @@ -0,0 +1,40 @@ +#ifndef __BB_PWD_H +#define __BB_PWD_H + +#if defined USE_SYSTEM_PWD_GRP +#include +#else + +#include +#include +#include + +/* The passwd structure. */ +struct passwd +{ + char *pw_name; /* Username. */ + char *pw_passwd; /* Password. */ + uid_t pw_uid; /* User ID. */ + gid_t pw_gid; /* Group ID. */ + char *pw_gecos; /* Real name. */ + char *pw_dir; /* Home directory. */ + char *pw_shell; /* Shell program. */ +}; + +extern void setpwent __P ((void)); +extern void endpwent __P ((void)); +extern struct passwd * getpwent __P ((void)); + +extern int putpwent __P ((__const struct passwd * __p, FILE * __f)); +extern int getpw __P ((uid_t uid, char *buf)); + +extern struct passwd * fgetpwent __P ((FILE * file)); + +extern struct passwd * getpwuid __P ((__const uid_t)); +extern struct passwd * getpwnam __P ((__const char *)); + +extern struct passwd * __getpwent __P ((__const int passwd_fd)); + +#endif /* USE_SYSTEM_PWD_GRP */ +#endif /* __BB_PWD_H */ + diff --git a/pwd_grp/pwent.c b/pwd_grp/pwent.c new file mode 100644 index 000000000..e72e41d1e --- /dev/null +++ b/pwd_grp/pwent.c @@ -0,0 +1,56 @@ +/* + * pwent.c - This file is part of the libc-8086/pwd package for ELKS, + * Copyright (C) 1995, 1996 Nat Friedman . + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include "pwd.h" +#include + +/* + * setpwent(), endpwent(), and getpwent() are included in the same object + * file, since one cannot be used without the other two, so it makes sense to + * link them all in together. + */ + +/* file descriptor for the password file currently open */ +static int pw_fd = -1; + +void setpwent(void) +{ + if (pw_fd != -1) + close(pw_fd); + + pw_fd = open("/etc/passwd", O_RDONLY); +} + +void endpwent(void) +{ + if (pw_fd != -1) + close(pw_fd); + pw_fd = -1; +} + +struct passwd *getpwent(void) +{ + if (pw_fd != -1) + return (__getpwent(pw_fd)); + return NULL; +} diff --git a/pwd_grp/setgroups.c b/pwd_grp/setgroups.c new file mode 100644 index 000000000..e371cb892 --- /dev/null +++ b/pwd_grp/setgroups.c @@ -0,0 +1,43 @@ +/* vi: set sw=4 ts=4: */ +/* + * Taken from the set of syscalls for uClibc + * + * 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 Library 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 Library 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 "busybox.h" + +#include +#include +#include +#include +/* Kernel headers before 2.1.mumble need this on the Alpha to get + _syscall* defined. */ +#define __LIBRARY__ +#include +#include "grp_.h" + +#if __GNU_LIBRARY__ < 5 +//#define __NR_setgroups 81 +_syscall2(int, setgroups, size_t, size, const gid_t *, list); +#else +int setgroups(size_t size, const gid_t * list) +{ + return(syscall(__NR_setgroups, size, list)); +} +#endif diff --git a/rdate.c b/rdate.c new file mode 100644 index 000000000..50be4de8c --- /dev/null +++ b/rdate.c @@ -0,0 +1,116 @@ +/* vi: set sw=4 ts=4: */ +/* + * The Rdate command will ask a time server for the RFC 868 time + * and optionally set the system time. + * + * by Sterling Huxley + * + * 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 +#include +#include "busybox.h" + + +static const int RFC_868_BIAS = 2208988800UL; + +static time_t askremotedate(const char *host) +{ + struct hostent *h; + struct sockaddr_in s_in; + struct servent *tserv; + unsigned long int nett, localt; + int fd; + + h = xgethostbyname(host); /* get the IP addr */ + + if ((tserv = getservbyname("time", "tcp")) == NULL) /* find port # */ + perror_msg_and_die("time"); + + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) /* get net connection */ + perror_msg_and_die("socket"); + + memcpy(&s_in.sin_addr, h->h_addr, sizeof(s_in.sin_addr)); + s_in.sin_port= tserv->s_port; + s_in.sin_family = AF_INET; + + if (connect(fd, (struct sockaddr *)&s_in, sizeof(s_in)) < 0) /* connect to time server */ + perror_msg_and_die("%s", host); + + if (read(fd, (void *)&nett, 4) != 4) /* read time from server */ + error_msg_and_die("%s did not send the complete time", host); + + close(fd); + + /* convert from network byte order to local byte order. + * RFC 868 time is the number of seconds + * since 00:00 (midnight) 1 January 1900 GMT + * the RFC 868 time 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT + * Subtract the RFC 868 time to get Linux epoch + */ + localt= ntohl(nett) - RFC_868_BIAS; + + return(localt); +} + +int rdate_main(int argc, char **argv) +{ + time_t remote_time; + int opt; + int setdate = 1; + int printdate = 1; + + /* Interpret command line args */ + while ((opt = getopt(argc, argv, "sp")) > 0) { + switch (opt) { + case 's': + printdate = 0; + setdate = 1; + break; + case 'p': + printdate = 1; + setdate = 0; + break; + default: + show_usage(); + } + } + + if (optind == argc) + show_usage(); + + remote_time = askremotedate(argv[optind]); + + if (setdate) { + if (stime(&remote_time) < 0) + perror_msg_and_die("Could not set time of day"); + } + + if (printdate) + printf("%s", ctime(&remote_time)); + + return EXIT_SUCCESS; +} diff --git a/readlink.c b/readlink.c new file mode 100644 index 000000000..fc5b7c2e3 --- /dev/null +++ b/readlink.c @@ -0,0 +1,46 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini readlink implementation for busybox + * + * Copyright (C) 1999,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 + * + */ + +#include +#include +#include +#include "busybox.h" + +int readlink_main(int argc, char **argv) +{ + char *buf = NULL; + + /* no options, no getopt */ + + if (argc != 2) + show_usage(); + + buf = xreadlink(argv[1]); + if (!buf) + return EXIT_FAILURE; + puts(buf); +#ifdef BB_FEATURE_CLEAN_UP + free(buf); +#endif + + return EXIT_SUCCESS; +} diff --git a/reboot.c b/reboot.c new file mode 100644 index 000000000..456865eb6 --- /dev/null +++ b/reboot.c @@ -0,0 +1,116 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini reboot implementation for busybox + * + * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 1999-2002 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 + * + */ + +#include "busybox.h" +#include +#include +#include +#include + +#if (__GNU_LIBRARY__ > 5) || defined(__dietlibc__) + #include + #define init_reboot(magic) reboot(magic) +#else + #define init_reboot(magic) reboot(0xfee1dead, 672274793, magic) +#endif +#ifndef RB_ENABLE_CAD +static const int RB_ENABLE_CAD = 0x89abcdef; +static const int RB_AUTOBOOT = 0x01234567; +#endif + +extern int reboot_main(int argc, char **argv) +{ + int delay = 0; /* delay in seconds before rebooting */ + int rc; + + while ((rc = getopt(argc, argv, "d:")) > 0) { + switch (rc) { + case 'd': + delay = atoi(optarg); + break; + + default: + show_usage(); + break; + } + } + + if(delay > 0) + sleep(delay); + +#ifdef CONFIG_USER_INIT + /* Don't kill ourself */ + signal(SIGTERM,SIG_IGN); + signal(SIGHUP,SIG_IGN); + setpgrp(); + + /* Allow Ctrl-Alt-Del to reboot system. */ + init_reboot(RB_ENABLE_CAD); + + message(CONSOLE|LOG, "\n\rThe system is going down NOW !!\n"); + sync(); + + /* Send signals to every process _except_ pid 1 */ + message(CONSOLE|LOG, "\rSending SIGTERM to all processes.\n"); + kill(-1, SIGTERM); + sleep(1); + sync(); + + message(CONSOLE|LOG, "\rSending SIGKILL to all processes.\n"); + kill(-1, SIGKILL); + sleep(1); + + sync(); + if (kernelVersion > 0 && kernelVersion <= KERNEL_VERSION(2,2,11)) { + /* bdflush, kupdate not needed for kernels >2.2.11 */ + bdflush(1, 0); + sync(); + } + + init_reboot(RB_AUTOBOOT); + exit(0); /* Shrug */ +#else +#ifdef BB_FEATURE_LINUXRC + { + /* don't assume init's pid == 1 */ + long *pid = find_pid_by_name("init"); + if (!pid || *pid<=0) + pid = find_pid_by_name("linuxrc"); + if (!pid || *pid<=0) + error_msg_and_die("no process killed"); + fflush(stdout); + return(kill(*pid, SIGTERM)); + } +#else + return(kill(1, SIGTERM)); +#endif +#endif +} + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/renice.c b/renice.c new file mode 100644 index 000000000..ec35bdcde --- /dev/null +++ b/renice.c @@ -0,0 +1,54 @@ +/* + * Mini renice implementation for busybox + * + * + * Copyright (C) 2000 Dave 'Kill a Cop' Cinege + * + * 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 "busybox.h" + + +extern int renice_main(int argc, char **argv) +{ + int prio, status = EXIT_SUCCESS; + + if (argc < 3) show_usage(); + + prio = atoi(*++argv); + if (prio > 20) prio = 20; + if (prio < -20) prio = -20; + + while (*++argv) { + int ps = atoi(*argv); + int oldp = getpriority(PRIO_PROCESS, ps); + + if (setpriority(PRIO_PROCESS, ps, prio) == 0) { + printf("%d: old priority %d, new priority %d\n", ps, oldp, prio ); + } else { + perror_msg("%d: setpriority", ps); + status = EXIT_FAILURE; + } + } + + return status; +} diff --git a/reset.c b/reset.c new file mode 100644 index 000000000..76244ca13 --- /dev/null +++ b/reset.c @@ -0,0 +1,35 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini reset implementation for busybox + * + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen + * and Kent Robotti + * + * 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 "busybox.h" + +extern int reset_main(int argc, char **argv) +{ + printf("\033[?25h\033c\033[J"); + return EXIT_SUCCESS; +} + diff --git a/rm.c b/rm.c new file mode 100644 index 000000000..51c9f4ceb --- /dev/null +++ b/rm.c @@ -0,0 +1,77 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini rm implementation for busybox + * + * + * 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +extern int rm_main(int argc, char **argv) +{ + int status = 0; + int opt; + int flags = 0; + int i; + + while ((opt = getopt(argc, argv, "fiRr")) != -1) { + switch (opt) { + case 'f': + flags &= ~FILEUTILS_INTERACTIVE; + flags |= FILEUTILS_FORCE; + break; + case 'i': + flags &= ~FILEUTILS_FORCE; + flags |= FILEUTILS_INTERACTIVE; + break; + case 'R': + case 'r': + flags |= FILEUTILS_RECUR; + break; + } + } + + if (!(flags & FILEUTILS_FORCE) && optind == argc) + show_usage(); + + for (i = optind; i < argc; i++) { + char *base = get_last_path_component(argv[i]); + + if (strcmp(base, ".") == 0 || strcmp(base, "..") == 0) { + error_msg("cannot remove `.' or `..'"); + status = 1; + continue; + } + + if (remove_file(argv[i], flags) < 0) + status = 1; + } + + return status; +} diff --git a/rmdir.c b/rmdir.c new file mode 100644 index 000000000..4508ad48d --- /dev/null +++ b/rmdir.c @@ -0,0 +1,97 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini rmdir implementation for busybox + * + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include + +#include "busybox.h" + + +/* Return true if a path is composed of multiple components. */ + +static int +multiple_components_p (const char *path) +{ + const char *s = path; + + while (s[0] != '\0' && s[0] != '/') + s++; + + while (s[0] == '/') + s++; + + return (s[0] != '\0'); +} + + +/* Remove a directory. Returns 0 if successful, -1 on error. */ + +static int +remove_directory (char *path, int flags) +{ + if (!(flags & FILEUTILS_RECUR)) { + if (rmdir (path) < 0) { + perror_msg ("unable to remove `%s'", path); + return -1; + } + } else { + if (remove_directory (path, 0) < 0) + return -1; + + if (multiple_components_p (path)) + if (remove_directory (dirname (path), flags) < 0) + return -1; + } + + return 0; +} + + +extern int +rmdir_main (int argc, char **argv) +{ + int status = EXIT_SUCCESS; + int flags = 0; + int i, opt; + + while ((opt = getopt (argc, argv, "p")) != -1) + switch (opt) { + case 'p': + flags |= FILEUTILS_RECUR; + break; + + default: + show_usage (); + } + + if (optind == argc) + show_usage(); + + for (i = optind; i < argc; i++) + if (remove_directory (argv[i], flags) < 0) + status = EXIT_FAILURE; + + return status; +} diff --git a/rmmod.c b/rmmod.c new file mode 100644 index 000000000..affe975fa --- /dev/null +++ b/rmmod.c @@ -0,0 +1,62 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini rmmod implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include +#include +#include +#include "busybox.h" + +extern int delete_module(const char * name); + + +extern int rmmod_main(int argc, char **argv) +{ + int n, ret = EXIT_SUCCESS; + + /* Parse command line. */ + while ((n = getopt(argc, argv, "a")) != EOF) { + switch (n) { + case 'a': + /* Unload _all_ unused modules via NULL delete_module() call */ + if (delete_module(NULL)) + perror_msg_and_die("rmmod"); + return EXIT_SUCCESS; + default: + show_usage(); + } + } + + if (optind == argc) + show_usage(); + + for (n = optind; n < argc; n++) { + if (delete_module(argv[n]) < 0) { + perror_msg("%s", argv[n]); + ret = EXIT_FAILURE; + } + } + + return(ret); +} diff --git a/route.c b/route.c new file mode 100644 index 000000000..d18d4ae29 --- /dev/null +++ b/route.c @@ -0,0 +1,457 @@ +/* route + * + * Similar to the standard Unix route, but with only the necessary + * parts for AF_INET + * + * Bjorn Wesen, Axis Communications AB + * + * Author of the original route: + * Fred N. van Kempen, + * (derived from FvK's 'route.c 1.70 01/04/94') + * + * 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. + * + * displayroute() code added by Vladimir N. Oleynik + * adjustments by Larry Doolittle + */ + +#include +#include +#include +#include +#include // HZ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +#define _(x) x + +#define RTACTION_ADD 1 +#define RTACTION_DEL 2 +#define RTACTION_HELP 3 +#define RTACTION_FLUSH 4 +#define RTACTION_SHOW 5 + +#define E_NOTFOUND 8 +#define E_SOCK 7 +#define E_LOOKUP 6 +#define E_VERSION 5 +#define E_USAGE 4 +#define E_OPTERR 3 +#define E_INTERN 2 +#define E_NOSUPP 1 + +/* resolve XXX.YYY.ZZZ.QQQ -> binary */ + +static int +INET_resolve(char *name, struct sockaddr *sa) +{ + struct sockaddr_in *s_in = (struct sockaddr_in *)sa; + + s_in->sin_family = AF_INET; + s_in->sin_port = 0; + + /* Default is special, meaning 0.0.0.0. */ + if (strcmp(name, "default")==0) { + s_in->sin_addr.s_addr = INADDR_ANY; + return 1; + } + /* Look to see if it's a dotted quad. */ + if (inet_aton(name, &s_in->sin_addr)) { + return 0; + } + /* guess not.. */ + return -1; +} + +#if defined (SIOCADDRTOLD) || defined (RTF_IRTT) /* route */ +#define HAVE_NEW_ADDRT 1 +#endif +#ifdef RTF_IRTT /* route */ +#define HAVE_RTF_IRTT 1 +#endif +#ifdef RTF_REJECT /* route */ +#define HAVE_RTF_REJECT 1 +#endif + +#if HAVE_NEW_ADDRT +#define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr) +#define full_mask(x) (x) +#else +#define mask_in_addr(x) ((x).rt_genmask) +#define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr) +#endif + +/* add or delete a route depending on action */ + +static int +INET_setroute(int action, int options, char **args) +{ + struct rtentry rt; + char target[128], gateway[128] = "NONE", netmask[128] = "default"; + int xflag, isnet; + int skfd; + + xflag = 0; + + if (*args == NULL) + show_usage(); + if (strcmp(*args, "-net")==0) { + xflag = 1; + args++; + } else if (strcmp(*args, "-host")==0) { + xflag = 2; + args++; + } + safe_strncpy(target, *args++, (sizeof target)); + + /* Clean out the RTREQ structure. */ + memset((char *) &rt, 0, sizeof(struct rtentry)); + + + if ((isnet = INET_resolve(target, &rt.rt_dst)) < 0) { + error_msg(_("can't resolve %s"), target); + return EXIT_FAILURE; /* XXX change to E_something */ + } + + switch (xflag) { + case 1: + isnet = 1; + break; + + case 2: + isnet = 0; + break; + + default: + break; + } + + /* Fill in the other fields. */ + rt.rt_flags = (RTF_UP | RTF_HOST); + if (isnet) + rt.rt_flags &= ~RTF_HOST; + + while (*args) { + if (strcmp(*args, "metric")==0) { + int metric; + + args++; + if (!*args || !isdigit(**args)) + show_usage(); + metric = atoi(*args); +#if HAVE_NEW_ADDRT + rt.rt_metric = metric + 1; +#else + ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); /* XXX Fixme */ +#endif + args++; + continue; + } + + if (strcmp(*args, "netmask")==0) { + struct sockaddr mask; + + args++; + if (!*args || mask_in_addr(rt)) + show_usage(); + safe_strncpy(netmask, *args, (sizeof netmask)); + if ((isnet = INET_resolve(netmask, &mask)) < 0) { + error_msg(_("can't resolve netmask %s"), netmask); + return E_LOOKUP; + } + rt.rt_genmask = full_mask(mask); + args++; + continue; + } + + if (strcmp(*args, "gw")==0 || strcmp(*args, "gateway")==0) { + args++; + if (!*args) + show_usage(); + if (rt.rt_flags & RTF_GATEWAY) + show_usage(); + safe_strncpy(gateway, *args, (sizeof gateway)); + if ((isnet = INET_resolve(gateway, &rt.rt_gateway)) < 0) { + error_msg(_("can't resolve gw %s"), gateway); + return E_LOOKUP; + } + if (isnet) { + error_msg( + _("%s: cannot use a NETWORK as gateway!"), + gateway); + return E_OPTERR; + } + rt.rt_flags |= RTF_GATEWAY; + args++; + continue; + } + + if (strcmp(*args, "mss")==0) { + args++; + rt.rt_flags |= RTF_MSS; + if (!*args) + show_usage(); + rt.rt_mss = atoi(*args); + args++; + if (rt.rt_mss < 64 || rt.rt_mss > 32768) { + error_msg(_("Invalid MSS.")); + return E_OPTERR; + } + continue; + } + + if (strcmp(*args, "window")==0) { + args++; + if (!*args) + show_usage(); + rt.rt_flags |= RTF_WINDOW; + rt.rt_window = atoi(*args); + args++; + if (rt.rt_window < 128) { + error_msg(_("Invalid window.")); + return E_OPTERR; + } + continue; + } + + if (strcmp(*args, "irtt")==0) { + args++; + if (!*args) + show_usage(); + args++; +#if HAVE_RTF_IRTT + rt.rt_flags |= RTF_IRTT; + rt.rt_irtt = atoi(*(args - 1)); + rt.rt_irtt *= (HZ / 100); /* FIXME */ +#if 0 /* FIXME: do we need to check anything of this? */ + if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) { + error_msg(_("Invalid initial rtt.")); + return E_OPTERR; + } +#endif +#else + ENOSUPP("inet_setroute", "RTF_IRTT"); /* XXX Fixme */ +#endif + continue; + } + + if (strcmp(*args, "reject")==0) { + args++; +#if HAVE_RTF_REJECT + rt.rt_flags |= RTF_REJECT; +#else + ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */ +#endif + continue; + } + if (strcmp(*args, "mod")==0) { + args++; + rt.rt_flags |= RTF_MODIFIED; + continue; + } + if (strcmp(*args, "dyn")==0) { + args++; + rt.rt_flags |= RTF_DYNAMIC; + continue; + } + if (strcmp(*args, "reinstate")==0) { + args++; + rt.rt_flags |= RTF_REINSTATE; + continue; + } + if (strcmp(*args, "device")==0 || strcmp(*args, "dev")==0) { + args++; + if (rt.rt_dev || *args == NULL) + show_usage(); + rt.rt_dev = *args++; + continue; + } + /* nothing matches */ + if (!rt.rt_dev) { + rt.rt_dev = *args++; + if (*args) + show_usage(); /* must be last to catch typos */ + } else { + show_usage(); + } + } + +#if HAVE_RTF_REJECT + if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev) + rt.rt_dev = "lo"; +#endif + + /* sanity checks.. */ + if (mask_in_addr(rt)) { + unsigned long mask = mask_in_addr(rt); + mask = ~ntohl(mask); + if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) { + error_msg( + _("netmask %.8x doesn't make sense with host route"), + (unsigned int)mask); + return E_OPTERR; + } + if (mask & (mask + 1)) { + error_msg(_("bogus netmask %s"), netmask); + return E_OPTERR; + } + mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr; + if (mask & ~mask_in_addr(rt)) { + error_msg(_("netmask doesn't match route address")); + return E_OPTERR; + } + } + /* Fill out netmask if still unset */ + if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST) + mask_in_addr(rt) = 0xffffffff; + + /* Create a socket to the INET kernel. */ + if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("socket"); + return E_SOCK; + } + /* Tell the kernel to accept this route. */ + if (action == RTACTION_DEL) { + if (ioctl(skfd, SIOCDELRT, &rt) < 0) { + perror("SIOCDELRT"); + close(skfd); + return E_SOCK; + } + } else { + if (ioctl(skfd, SIOCADDRT, &rt) < 0) { + perror("SIOCADDRT"); + close(skfd); + return E_SOCK; + } + } + + /* Close the socket. */ + (void) close(skfd); + return EXIT_SUCCESS; +} + +#ifndef RTF_UP +/* Keep this in sync with /usr/src/linux/include/linux/route.h */ +#define RTF_UP 0x0001 /* route usable */ +#define RTF_GATEWAY 0x0002 /* destination is a gateway */ +#define RTF_HOST 0x0004 /* host entry (net otherwise) */ +#define RTF_REINSTATE 0x0008 /* reinstate route after tmout */ +#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */ +#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */ +#define RTF_MTU 0x0040 /* specific MTU for this route */ +#ifndef RTF_MSS +#define RTF_MSS RTF_MTU /* Compatibility :-( */ +#endif +#define RTF_WINDOW 0x0080 /* per route window clamping */ +#define RTF_IRTT 0x0100 /* Initial round trip time */ +#define RTF_REJECT 0x0200 /* Reject route */ +#endif + +static void displayroutes(int numeric) +{ + char buff[256]; + int nl = 0 ; + struct in_addr dest; + struct in_addr gw; + struct in_addr mask; + int flgs, ref, use, metric; + char flags[64]; + unsigned long int d,g,m; + + char sdest[16], sgw[16]; + + + FILE *fp = xfopen("/proc/net/route", "r"); + + while( fgets(buff, sizeof(buff), fp) != NULL ) { + if(nl) { + int ifl = 0; + while(buff[ifl]!=' ' && buff[ifl]!='\t' && buff[ifl]!='\0') + ifl++; + buff[ifl]=0; /* interface */ + if(sscanf(buff+ifl+1, "%lx%lx%X%d%d%d%lx", + &d, &g, &flgs, &ref, &use, &metric, &m)!=7) { + error_msg_and_die( "Unsuported kernel route format\n"); + } + if(nl==1) + printf("Kernel IP routing table\n" + "Destination Gateway Genmask Flags Metric Ref Use Iface\n"); + + ifl = 0; /* parse flags */ + if(flgs&RTF_UP) { + if(flgs&RTF_REJECT) + flags[ifl++]='!'; + else + flags[ifl++]='U'; + if(flgs&RTF_GATEWAY) + flags[ifl++]='G'; + if(flgs&RTF_HOST) + flags[ifl++]='H'; + if(flgs&RTF_REINSTATE) + flags[ifl++]='R'; + if(flgs&RTF_DYNAMIC) + flags[ifl++]='D'; + if(flgs&RTF_MODIFIED) + flags[ifl++]='M'; + flags[ifl]=0; + dest.s_addr = d; + gw.s_addr = g; + mask.s_addr = m; + strcpy(sdest, (numeric == 0 && dest.s_addr==0 ? "default" : + inet_ntoa(dest))); + strcpy(sgw, (numeric == 0 && gw.s_addr==0 ? "*" : + inet_ntoa(gw))); + printf("%-16s%-16s%-16s%-6s%-6d %-2d %7d %s\n", + sdest, sgw, + inet_ntoa(mask), + flags, metric, ref, use, buff); + } + } + nl++; + } +} + +int route_main(int argc, char **argv) +{ + int what = 0; + int numeric = 0; + + argc--; + argv++; + + if (argc>0 && strcmp(argv[0], "-n")==0) { + numeric = 1; + argc--; + argv++; + } + + if (*argv == NULL) { + displayroutes(numeric); + return EXIT_SUCCESS; + } else { + /* check verb */ + if (strcmp(*argv, "add")==0) + what = RTACTION_ADD; + else if (strcmp(*argv, "del")==0 || strcmp(*argv, "delete")==0) + what = RTACTION_DEL; + else if (strcmp(*argv, "flush")==0) + what = RTACTION_FLUSH; + else + show_usage(); + } + + return INET_setroute(what, 0, ++argv); +} diff --git a/rpm2cpio.c b/rpm2cpio.c new file mode 100644 index 000000000..8d639d6ad --- /dev/null +++ b/rpm2cpio.c @@ -0,0 +1,91 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini rpm2cpio implementation for busybox + * + * Copyright (C) 2001 by Laurence Anderson + * + * 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 "busybox.h" +#include /* For ntohl & htonl function */ +#include + +#define RPM_MAGIC "\355\253\356\333" +#define RPM_HEADER_MAGIC "\216\255\350" + +struct rpm_lead { + unsigned char magic[4]; + u_int8_t major, minor; + u_int16_t type; + u_int16_t archnum; + char name[66]; + u_int16_t osnum; + u_int16_t signature_type; + char reserved[16]; +}; + +struct rpm_header { + char magic[3]; /* 3 byte magic: 0x8e 0xad 0xe8 */ + u_int8_t version; /* 1 byte version number */ + u_int32_t reserved; /* 4 bytes reserved */ + u_int32_t entries; /* Number of entries in header (4 bytes) */ + u_int32_t size; /* Size of store (4 bytes) */ +}; + +void skip_header(FILE *rpmfile) +{ + struct rpm_header header; + + fread(&header, sizeof(struct rpm_header), 1, rpmfile); + if (strncmp((char *) &header.magic, RPM_HEADER_MAGIC, 3) != 0) error_msg_and_die("Invalid RPM header magic"); /* Invalid magic */ + if (header.version != 1) error_msg_and_die("Unsupported RPM header version"); /* This program only supports v1 headers */ + header.entries = ntohl(header.entries); + header.size = ntohl(header.size); + fseek (rpmfile, 16 * header.entries, SEEK_CUR); /* Seek past index entries */ + fseek (rpmfile, header.size, SEEK_CUR); /* Seek past store */ +} + +/* No getopt required */ +extern int rpm2cpio_main(int argc, char **argv) +{ + struct rpm_lead lead; + int gunzip_pid; + FILE *rpmfile, *cpiofile; + + if (argc == 1) { + rpmfile = stdin; + } else { + rpmfile = fopen(argv[1], "r"); + if (!rpmfile) perror_msg_and_die("Can't open rpm file"); + /* set the buffer size */ + setvbuf(rpmfile, NULL, _IOFBF, 0x8000); + } + + fread (&lead, sizeof(struct rpm_lead), 1, rpmfile); + if (strncmp((char *) &lead.magic, RPM_MAGIC, 4) != 0) error_msg_and_die("Invalid RPM magic"); /* Just check the magic, the rest is irrelevant */ + /* Skip the signature header */ + skip_header(rpmfile); + fseek(rpmfile, (8 - (ftell(rpmfile) % 8)) % 8, SEEK_CUR); /* Pad to 8 byte boundary */ + /* Skip the main header */ + skip_header(rpmfile); + + cpiofile = gz_open(rpmfile, &gunzip_pid); + + copyfd(fileno(cpiofile), fileno(stdout)); + gz_close(gunzip_pid); + fclose(rpmfile); + return 0; +} diff --git a/scripts/depmod.pl b/scripts/depmod.pl new file mode 100755 index 000000000..bd7767f19 --- /dev/null +++ b/scripts/depmod.pl @@ -0,0 +1,227 @@ +#!/usr/bin/perl -w +# vi: set ts=4: +# Copyright (c) 2001 David Schleef +# Copyright (c) 2001 Erik Andersen +# Copyright (c) 2001 Stuart Hughes +# This program is free software; you can redistribute it and/or modify it +# under the same terms as Perl itself. + +# TODO -- use strict mode... +#use strict; + +use Getopt::Long; +use File::Find; + + +# Set up some default values + +my $basedir=""; +my $kernel; +my $kernelsyms; +my $stdout=1; +my $verbose=0; + + +# get command-line options + +my %opt; + +GetOptions( + \%opt, + "help|h", + "basedir|b=s" => \$basedir, + "kernel|k=s" => \$kernel, + "kernelsyms|F=s" => \$kernelsyms, + "stdout|n" => \$stdout, + "verbose|v" => \$verbose, +); + +if (defined $opt{help}) { + print + "$0 [OPTION]... [basedir]\n", + "\t-h --help\t\tShow this help screen\n", + "\t-b --basedir\t\tModules base directory (defaults to /lib/modules)\n", + "\t-k --kernel\t\tKernel binary for the target\n", + "\t-F --kernelsyms\t\tKernel symbol file\n", + "\t-n --stdout\t\tWrite to stdout instead of modules.dep\n", + "\t-v --verbose\t\tPrint out lots of debugging stuff\n", + ; + exit 1; +} + +if($basedir !~ m-/lib/modules-) { + warn "WARNING: base directory does not match ..../lib/modules\n"; +} + +# Find the list of .o files living under $basedir +#if ($verbose) { printf "Locating all modules\n"; } +my($file) = ""; +my(@liblist) = (); +find sub { + if ( -f $_ && ! -d $_ ) { + $file = $File::Find::name; + if ( $file =~ /.o$/ ) { + push(@liblist, $file); + if ($verbose) { printf "$file\n"; } + } + } +}, $basedir; +if ($verbose) { printf "Finished locating modules\n"; } + +foreach $obj ( @liblist, $kernel ){ + # turn the input file name into a target tag name + # vmlinux is a special that is only used to resolve symbols + if($obj =~ /vmlinux/) { + $tgtname = "vmlinux"; + } else { + ($tgtname) = $obj =~ m-(/lib/modules/.*)$-; + } + + warn "MODULE = $tgtname\n" if $verbose; + + # get a list of symbols + @output=`nm $obj`; + $ksymtab=grep m/ __ksymtab/, @output; + + # gather the exported symbols + if($ksymtab){ + # explicitly exported + foreach ( @output ) { + / __ksymtab_(.*)$/ and do { + warn "sym = $1\n" if $verbose; + $exp->{$1} = $tgtname; + }; + } + } else { + # exporting all symbols + foreach ( @output) { + / [ABCDGRST] (.*)$/ and do { + warn "syma = $1\n" if $verbose; + $exp->{$1} = $tgtname; + }; + } + } + # gather the unresolved symbols + foreach ( @output ) { + !/ __this_module/ && / U (.*)$/ and do { + warn "und = $1\n" if $verbose; + push @{$dep->{$tgtname}}, $1; + }; + } +} + + +# reduce dependancies: remove unresolvable and resolved from vmlinux +# remove duplicates +foreach $module (keys %$dep) { + $mod->{$module} = {}; + foreach (@{$dep->{$module}}) { + if( $exp->{$_} ) { + warn "resolved symbol $_ in file $exp->{$_}\n" if $verbose; + next if $exp->{$_} =~ /vmlinux/; + $mod->{$module}{$exp->{$_}} = 1; + } else { + warn "unresolved symbol $_ in file $module\n"; + } + } +} + +# resolve the dependancies for each module +foreach $module ( keys %$mod ) { + print "$module:\t"; + @sorted = sort bydep keys %{$mod->{$module}}; + print join(" \\\n\t",@sorted); +# foreach $m (@sorted ) { +# print "\t$m\n"; +# } + print "\n\n"; +} + +sub bydep +{ + foreach my $f ( keys %{$mod->{$b}} ) { + if($f eq $a) { + return 1; + } + } + return -1; +} + + + +__END__ + +=head1 NAME + +depmod.pl - a cross platform script to generate kernel module dependency + lists which can then be used by modprobe. + +=head1 SYNOPSIS + +depmod.pl [OPTION]... [FILE]... + +Example: + + depmod.pl -F linux/System.map target/lib/modules + +=head1 DESCRIPTION + +The purpose of this script is to automagically generate a list of of kernel +module dependancies. This script produces dependancy lists that should be +identical to the depmod program from the modutils package. Unlike the depmod +binary, however, depmod.pl is designed to be run on your host system, not +on your target system. + +This script was written by David Schleef to be used in +conjunction with the BusyBox modprobe applet. + +=head1 OPTIONS + +=over 4 + +=item B<-h --help> + +This displays the help message. + +=item B<-b --basedir> + +The base directory uner which the target's modules will be found. This +defaults to the /lib/modules directory. + +=item B<-k --kernel> + +Kernel binary for the target. You must either supply a kernel binary +or a kernel symbol file (using the -F option). + +=item B<-F --kernelsyms> + +Kernel symbol file for the target. You must supply either a kernel symbol file +kernel binary for the target (using the -k option). + +=item B<-n --stdout> + +Write to stdout instead of modules.dep. This is currently hard coded... +kernel binary for the target (using the -k option). + +=item B<--verbose> + +Be verbose (not implemented) + +=back + +=head1 COPYRIGHT + +Copyright (c) 2001 David Schleef +Copyright (c) 2001 Erik Andersen +Copyright (c) 2001 Stuart Hughes +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 AUTHOR + +David Schleef + +=cut + +# $Id: depmod.pl,v 1.2 2001/11/19 23:57:54 andersen Exp $ + diff --git a/scripts/inittab b/scripts/inittab new file mode 100644 index 000000000..5716045b8 --- /dev/null +++ b/scripts/inittab @@ -0,0 +1,91 @@ +# /etc/inittab init(8) configuration for BusyBox +# +# Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen +# Copyright (C) 1999,2000,2001 by Erik Andersen +# +# +# Note, BusyBox init doesn't support runlevels. The runlevels field is +# completely ignored by BusyBox init. If you want runlevels, use sysvinit. +# +# +# Format for each entry: ::: +# +# : WARNING: This field has a non-traditional meaning for BusyBox init! +# +# The id field is used by BusyBox init to specify the controlling tty for +# the specified process to run on. The contents of this field are +# appended to "/dev/" and used as-is. There is no need for this field to +# be unique, although if it isn't you may have strange results. If this +# field is left blank, it is completely ignored. Also note that if +# BusyBox detects that a serial console is in use, then all entries +# containing non-empty id fields will _not_ be run. BusyBox init does +# nothing with utmp. We don't need no stinkin' utmp. +# +# : The runlevels field is completely ignored. +# +# : Valid actions include: sysinit, respawn, askfirst, wait, once, +# restart, ctrlaltdel, and shutdown. +# +# Note: askfirst acts just like respawn, but before running the specified +# process it displays the line "Please press Enter to activate this +# console." and then waits for the user to press enter before starting +# the specified process. +# +# Note: unrecognised actions (like initdefault) will cause init to emit +# an error message, and then go along with its business. +# +# : Specifies the process to be executed and it's command line. +# +# Note: BusyBox init works just fine without an inittab. If no inittab is +# found, it has the following default behavior: +# ::sysinit:/etc/init.d/rcS +# ::askfirst:/bin/sh +# ::ctrlaltdel:/sbin/reboot +# ::shutdown:/sbin/swapoff -a +# ::shutdown:/bin/umount -a -r +# ::restart:/sbin/init +# +# if it detects that /dev/console is _not_ a serial console, it will +# also run: +# tty2::askfirst:/bin/sh +# tty3::askfirst:/bin/sh +# tty4::askfirst:/bin/sh +# +# Boot-time system configuration/initialization script. +# This is run first except when booting in single-user mode. +# +::sysinit:/etc/init.d/rcS + +# /bin/sh invocations on selected ttys +# +# Note below that we prefix the shell commands with a "-" to indicate to the +# shell that it is supposed to be a login shell. Normally this is handled by +# login, but since we are bypassing login in this case, BusyBox lets you do +# this yourself... +# +# Start an "askfirst" shell on the console (whatever that may be) +::askfirst:-/bin/sh +# Start an "askfirst" shell on /dev/tty2-4 +tty2::askfirst:-/bin/sh +tty3::askfirst:-/bin/sh +tty4::askfirst:-/bin/sh + +# /sbin/getty invocations for selected ttys +tty4::respawn:/sbin/getty 38400 tty5 +tty5::respawn:/sbin/getty 38400 tty6 + +# Example of how to put a getty on a serial line (for a terminal) +#::respawn:/sbin/getty -L ttyS0 9600 vt100 +#::respawn:/sbin/getty -L ttyS1 9600 vt100 +# +# Example how to put a getty on a modem line. +#::respawn:/sbin/getty 57600 ttyS2 + +# Stuff to do when restarting the init process +::restart:/sbin/init + +# Stuff to do before rebooting +::ctrlaltdel:/sbin/reboot +::shutdown:/bin/umount -a -r +::shutdown:/sbin/swapoff -a + diff --git a/scripts/mk2knr.pl b/scripts/mk2knr.pl new file mode 100755 index 000000000..aaf4963b1 --- /dev/null +++ b/scripts/mk2knr.pl @@ -0,0 +1,84 @@ +#!/usr/bin/perl -w +# +# @(#) mk2knr.pl - generates a perl script that converts lexemes to K&R-style +# +# How to use this script: +# - In the busybox directory type 'scripts/mk2knr.pl files-you-want-to-convert' +# - Review the 'convertme.pl' script generated and remove / edit any of the +# substitutions in there (please especially check for false positives) +# - Type './convertme.pl same-files-as-before' +# - Compile and see if it works +# +# BUGS: This script does not ignore strings inside comments or strings inside +# quotes (it probably should). + +# set this to something else if you want +$convertme = 'convertme.pl'; + +# internal-use variables (don't touch) +$convert = 0; +%converted = (); + +# if no files were specified, print usage +die "usage: $0 file.c | file.h\n" if scalar(@ARGV) == 0; + +# prepare the "convert me" file +open(CM, ">$convertme") or die "convertme.pl $!"; +print CM "#!/usr/bin/perl -p -i\n\n"; + +# process each file passed on the cmd line +while (<>) { + + # if the line says "getopt" in it anywhere, we don't want to muck with it + # because option lists tend to include strings like "cxtzvOf:" which get + # matched by the "check for mixed case" regexps below + next if /getopt/; + + # tokenize the string into just the variables + while (/([a-zA-Z_][a-zA-Z0-9_]*)/g) { + $var = $1; + + # ignore the word "BusyBox" + next if ($var =~ /BusyBox/); + + # this checks for javaStyle or szHungarianNotation + $convert++ if ($var =~ /^[a-z]+[A-Z][a-z]+/); + + # this checks for PascalStyle + $convert++ if ($var =~ /^[A-Z][a-z]+[A-Z][a-z]+/); + + # if we want to add more checks, we can add 'em here, but the above + # checks catch "just enough" and not too much, so prolly not. + + if ($convert) { + $convert = 0; + + # skip ahead if we've already dealt with this one + next if ($converted{$var}); + + # record that we've dealt with this var + $converted{$var} = 1; + + print CM "s/\\b$var\\b/"; # more to come in just a minute + + # change the first letter to lower-case + $var = lcfirst($var); + + # put underscores before all remaining upper-case letters + $var =~ s/([A-Z])/_$1/g; + + # now change the remaining characters to lower-case + $var = lc($var); + + print CM "$var/g;\n"; + } + } +} + +# tidy up and make the $convertme script executable +close(CM); +chmod 0755, $convertme; + +# print a helpful help message +print "Done. Scheduled name changes are in $convertme.\n"; +print "Please review/modify it and then type ./$convertme to do the search & replace.\n"; diff --git a/scripts/undeb b/scripts/undeb new file mode 100644 index 000000000..a72e1e2ba --- /dev/null +++ b/scripts/undeb @@ -0,0 +1,53 @@ +#!/bin/sh +# +# This should work with the GNU version of tar and gzip! +# This should work with the bash or ash shell! +# Requires the programs (ar, tar, gzip, and the pager more or less). +# +usage() { +echo "Usage: undeb -c package.deb " +echo " undeb -l package.deb " +echo " undeb -x package.deb /foo/boo " +exit +} + +deb=$2 + +exist() { +if [ "$deb" = "" ]; then +usage +elif [ ! -s "$deb" ]; then +echo "Can't find $deb!" +exit +fi +} + +if [ "$1" = "" ]; then +usage +elif [ "$1" = "-l" ]; then +exist +type more >/dev/null 2>&1 && pager=more +type less >/dev/null 2>&1 && pager=less +[ "$pager" = "" ] && echo "No pager found!" && exit +(ar -p $deb control.tar.gz | tar -xzO *control ; echo -e "\nPress enter to scroll, q to Quit!\n" ; ar -p $deb data.tar.gz | tar -tzv) | $pager +exit +elif [ "$1" = "-c" ]; then +exist +ar -p $deb control.tar.gz | tar -xzO *control +exit +elif [ "$1" = "-x" ]; then +exist +if [ "$3" = "" ]; then +usage +elif [ ! -d "$3" ]; then +echo "No such directory $3!" +exit +fi +ar -p $deb data.tar.gz | tar -xzvpf - -C $3 || exit +echo +echo "Extracted $deb to $3!" +exit +else +usage +fi diff --git a/scripts/unrpm b/scripts/unrpm new file mode 100644 index 000000000..376286a6f --- /dev/null +++ b/scripts/unrpm @@ -0,0 +1,48 @@ +#!/bin/sh +# +# This should work with the GNU version of cpio and gzip! +# This should work with the bash or ash shell! +# Requires the programs (cpio, gzip, and the pager more or less). +# +usage() { +echo "Usage: unrpm -l package.rpm " +echo " unrpm -x package.rpm /foo/boo " +exit +} + +rpm=$2 + +exist() { +if [ "$rpm" = "" ]; then +usage +elif [ ! -s "$rpm" ]; then +echo "Can't find $rpm!" +exit +fi +} + +if [ "$1" = "" ]; then +usage +elif [ "$1" = "-l" ]; then +exist +type more >/dev/null 2>&1 && pager=more +type less >/dev/null 2>&1 && pager=less +[ "$pager" = "" ] && echo "No pager found!" && exit +(echo -e "\nPress enter to scroll, q to Quit!\n" ; rpm2cpio $rpm | cpio -tv --quiet) | $pager +exit +elif [ "$1" = "-x" ]; then +exist +if [ "$3" = "" ]; then +usage +elif [ ! -d "$3" ]; then +echo "No such directory $3!" +exit +fi +rpm2cpio $rpm | (umask 0 ; cd $3 ; cpio -idmuv) || exit +echo +echo "Extracted $rpm to $3!" +exit +else +usage +fi diff --git a/sed.c b/sed.c new file mode 100644 index 000000000..df6ccb228 --- /dev/null +++ b/sed.c @@ -0,0 +1,1215 @@ +/* vi: set sw=4 ts=4: */ +/* + * sed.c - very minimalist version of sed + * + * Copyright (C) 1999,2000,2001 by Lineo, inc. and Mark Whitley + * Copyright (C) 1999,2000,2001 by Mark Whitley + * Copyright (C) 2002 Matt Kraai + * Copyright (C) 2003 by 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 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 + * + */ + +/* Code overview. + + Files are laid out to avoid unnecessary function declarations. So for + example, every function add_cmd calls occurs before add_cmd in this file. + + add_cmd() is called on each line of sed command text (from a file or from + the command line). It calls get_address() and parse_cmd_args(). The + resulting sed_cmd_t structures are appended to a linked list + (sed_cmd_head/sed_cmd_tail). + + process_file() does actual sedding, reading data lines from an input FILE * + (which could be stdin) and applying the sed command list (sed_cmd_head) to + each of the resulting lines. + + sed_main() is where external code calls into this, with a command line. +*/ + + +/* + Supported features and commands in this version of sed: + + - comments ('#') + - address matching: num|/matchstr/[,num|/matchstr/|$]command + - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags) + - edit commands: (a)ppend, (i)nsert, (c)hange + - file commands: (r)ead + - backreferences in substitution expressions (\1, \2...\9) + - grouped commands: {cmd1;cmd2} + - transliteration (y/source-chars/dest-chars/) + - pattern space hold space storing / swapping (g, h, x) + - labels / branching (: label, b, t) + + (Note: Specifying an address (range) to match is *optional*; commands + default to the whole pattern space if no specific address match was + requested.) + + Unsupported features: + + - GNU extensions + - and more. + + Todo: + + - Create a wrapper around regex to make libc's regex conform with sed + - Fix bugs + + + Reference http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html +*/ + +#include +#include /* for getopt() */ +#include +#include /* for strdup() */ +#include +#include /* for isspace() */ +#include +#include "busybox.h" + +typedef struct sed_cmd_s { + /* Ordered by alignment requirements: currently 36 bytes on x86 */ + + /* address storage */ + regex_t *beg_match; /* sed -e '/match/cmd' */ + regex_t *end_match; /* sed -e '/match/,/end_match/cmd' */ + regex_t *sub_match; /* For 's/sub_match/string/' */ + int beg_line; /* 'sed 1p' 0 == apply commands to all lines */ + int end_line; /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */ + + FILE *file; /* File (sr) command writes to, -1 for none. */ + char *string; /* Data string for (saicytb) commands. */ + + unsigned short which_match; /* (s) Which match to replace (0 for all) */ + + /* Bitfields (gcc won't group them if we don't) */ + unsigned int invert:1; /* the '!' after the address */ + unsigned int in_match:1; /* Next line also included in match? */ + unsigned int no_newline:1; /* Last line written by (sr) had no '\n' */ + unsigned int sub_p:1; /* (s) print option */ + + + /* GENERAL FIELDS */ + char cmd; /* The command char: abcdDgGhHilnNpPqrstwxy:={} */ + struct sed_cmd_s *next; /* Next command (linked list, NULL terminated) */ +} sed_cmd_t; + +/* globals */ +/* options */ +static int be_quiet = 0; + +static const char bad_format_in_subst[] = + "bad format in substitution expression"; +const char *const semicolon_whitespace = "; \n\r\t\v"; + +regmatch_t regmatch[10]; +static regex_t *previous_regex_ptr = NULL; + +/* linked list of sed commands */ +static sed_cmd_t sed_cmd_head; +static sed_cmd_t *sed_cmd_tail = &sed_cmd_head; + +/* Linked list of append lines */ +struct append_list { + char *string; + struct append_list *next; +}; +struct append_list *append_head=NULL, *append_tail=NULL; + +/* If size is 0 copy until EOF */ +extern size_t bb_full_fd_action(int src_fd, int dst_fd, const size_t size, + ssize_t (*action)(int fd, const void *, size_t)) +{ + size_t read_total = 0; + RESERVE_BB_BUFFER(buffer,BUFSIZ); + + while ((size == 0) || (read_total < size)) { + size_t read_try; + ssize_t read_actual; + + if ((size == 0) || (size - read_total > BUFSIZ)) { + read_try = BUFSIZ; + } else { + read_try = size - read_total; + } + + read_actual = safe_read(src_fd, buffer, read_try); + if (read_actual > 0) { + if (action && (action(dst_fd, buffer, (size_t) read_actual) != read_actual)) { + perror_msg(write_error); /* match Read error below */ + break; + } + } + else if (read_actual == 0) { + if (size) { + error_msg("Unable to read all data"); + } + break; + } else { + /* read_actual < 0 */ + perror_msg("Read error"); + break; + } + + read_total += read_actual; + } + + RELEASE_BB_BUFFER(buffer); + + return(read_total); +} + +extern int bb_copyfd_eof(int fd1, int fd2) +{ + return(bb_full_fd_action(fd1, fd2, 0, full_write)); +} + +extern void bb_xprint_and_close_file(FILE *file) +{ + fflush(stdout); + /* Note: Do not use STDOUT_FILENO here, as this is a lib routine + * and the calling code may have reassigned stdout. */ + if (bb_copyfd_eof(fileno(file), fileno(stdout)) == -1) { + /* bb_copyfd outputs any needed messages, so just die. */ + exit(EXIT_FAILURE); + } + /* Note: Since we're reading, don't bother checking the return value + * of fclose(). The only possible failure is EINTR which + * should already have been taken care of. */ + fclose(file); +} + +#ifdef BB_FEATURE_CLEAN_UP +static void free_and_close_stuff(void) +{ + sed_cmd_t *sed_cmd = sed_cmd_head.next; + + while(append_head) { + append_tail=append_head->next; + free(append_head->string); + free(append_head); + append_head=append_tail; + } + + while (sed_cmd) { + sed_cmd_t *sed_cmd_next = sed_cmd->next; + + if(sed_cmd->file) + bb_xprint_and_close_file(sed_cmd->file); + + if (sed_cmd->beg_match) { + regfree(sed_cmd->beg_match); + free(sed_cmd->beg_match); + } + if (sed_cmd->end_match) { + regfree(sed_cmd->end_match); + free(sed_cmd->end_match); + } + if (sed_cmd->sub_match) { + regfree(sed_cmd->sub_match); + free(sed_cmd->sub_match); + } + free(sed_cmd->string); + free(sed_cmd); + sed_cmd = sed_cmd_next; + } +} +#endif + +/* strdup, replacing "\n" with '\n', and "\delimiter" with 'delimiter' */ + +static void parse_escapes(char *dest, const char *string, int len, char from, char to) +{ + int i=0; + + while(istring); + + /* determine the number of back references in the match string */ + /* Note: we compute this here rather than in the do_subst_command() + * function to save processor time, at the expense of a little more memory + * (4 bits) per sed_cmd */ + + /* process the flags */ + + sed_cmd->which_match=1; + while (substr[++idx]) { + /* Parse match number */ + if(isdigit(substr[idx])) { + if(match[0]!='^') { + /* Match 0 treated as all, multiple matches we take the last one. */ + char *pos=substr+idx; + sed_cmd->which_match=(unsigned short)strtol(substr+idx,&pos,10); + idx=pos-substr; + } + continue; + } + /* Skip spaces */ + if(isspace(substr[idx])) continue; + switch (substr[idx]) { + /* Replace all occurrences */ + case 'g': + if (match[0] != '^') sed_cmd->which_match = 0; + break; + /* Print pattern space */ + case 'p': + sed_cmd->sub_p = 1; + break; + case 'w': + { + char *temp; + idx+=parse_file_cmd(sed_cmd,substr+idx,&temp); + + break; + } + /* Ignore case (gnu exension) */ + case 'I': + cflags |= REG_ICASE; + break; + case ';': + case '}': + goto out; + default: + error_msg_and_die("bad option in substitution expression"); + } + } +out: + /* compile the match string into a regex */ + if (*match != '\0') { + /* If match is empty, we use last regex used at runtime */ + sed_cmd->sub_match = (regex_t *) xmalloc(sizeof(regex_t)); + xregcomp(sed_cmd->sub_match, match, cflags); + } + free(match); + + return idx; +} + +/* + * Process the commands arguments + */ +static char *parse_cmd_args(sed_cmd_t *sed_cmd, char *cmdstr) +{ + /* handle (s)ubstitution command */ + if (sed_cmd->cmd == 's') cmdstr += parse_subst_cmd(sed_cmd, cmdstr); + /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ + else if (strchr("aic", sed_cmd->cmd)) { + if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c') + error_msg_and_die + ("only a beginning address can be specified for edit commands"); + while(isspace(*cmdstr)) cmdstr++; + sed_cmd->string = xstrdup(cmdstr); + parse_escapes(sed_cmd->string,sed_cmd->string,strlen(cmdstr),0,0); + cmdstr += strlen(cmdstr); + /* handle file cmds: (r)ead */ + } else if(strchr("rw", sed_cmd->cmd)) { + if (sed_cmd->end_line || sed_cmd->end_match) + error_msg_and_die("Command only uses one address"); + cmdstr += parse_file_cmd(sed_cmd, cmdstr, &sed_cmd->string); + if(sed_cmd->cmd=='w') + sed_cmd->file=xfopen(sed_cmd->string,"w"); + /* handle branch commands */ + } else if (strchr(":bt", sed_cmd->cmd)) { + int length; + + while(isspace(*cmdstr)) cmdstr++; + length = strcspn(cmdstr, semicolon_whitespace); + if (length) { + sed_cmd->string = strndup(cmdstr, length); + cmdstr += length; + } + } + /* translation command */ + else if (sed_cmd->cmd == 'y') { + char *match, *replace; + int i=cmdstr[0]; + + cmdstr+=parse_regex_delim(cmdstr, &match, &replace)+1; + /* \n already parsed, but \delimiter needs unescaping. */ + parse_escapes(match,match,strlen(match),i,i); + parse_escapes(replace,replace,strlen(replace),i,i); + + sed_cmd->string = xcalloc(1, (strlen(match) + 1) * 2); + for (i = 0; match[i] && replace[i]; i++) { + sed_cmd->string[i * 2] = match[i]; + sed_cmd->string[(i * 2) + 1] = replace[i]; + } + free(match); + free(replace); + } + /* if it wasnt a single-letter command that takes no arguments + * then it must be an invalid command. + */ + else if (strchr("dDgGhHlnNpPqx={}", sed_cmd->cmd) == 0) { + error_msg_and_die("Unsupported command %c", sed_cmd->cmd); + } + + /* give back whatever's left over */ + return (cmdstr); +} + + +/* Parse address+command sets, skipping comment lines. */ + +void add_cmd(char *cmdstr) +{ + static char *add_cmd_line=NULL; + sed_cmd_t *sed_cmd; + int temp; + + /* Append this line to any unfinished line from last time. */ + if(add_cmd_line) { + int lastlen=strlen(add_cmd_line); + char *tmp=xmalloc(lastlen+strlen(cmdstr)+2); + + memcpy(tmp,add_cmd_line,lastlen); + tmp[lastlen]='\n'; + strcpy(tmp+lastlen+1,cmdstr); + free(add_cmd_line); + cmdstr=add_cmd_line=tmp; + } else add_cmd_line=NULL; + + /* If this line ends with backslash, request next line. */ + temp=strlen(cmdstr); + if(temp && cmdstr[temp-1]=='\\') { + if(!add_cmd_line) add_cmd_line=strdup(cmdstr); + add_cmd_line[temp-1]=0; + return; + } + + /* Loop parsing all commands in this line. */ + while(*cmdstr) { + /* Skip leading whitespace and semicolons */ + cmdstr += strspn(cmdstr, semicolon_whitespace); + + /* If no more commands, exit. */ + if(!*cmdstr) break; + + /* if this is a comment, jump past it and keep going */ + if (*cmdstr == '#') { + /* "#n" is the same as using -n on the command line */ + if (cmdstr[1] == 'n') be_quiet++; + if(!(cmdstr=strpbrk(cmdstr, "\n\r"))) break; + continue; + } + + /* parse the command + * format is: [addr][,addr][!]cmd + * |----||-----||-| + * part1 part2 part3 + */ + + sed_cmd = xcalloc(1, sizeof(sed_cmd_t)); + + /* first part (if present) is an address: either a '$', a number or a /regex/ */ + cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); + + /* second part (if present) will begin with a comma */ + if (*cmdstr == ',') { + int idx; + + cmdstr++; + idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match); + if (!idx) error_msg_and_die("get_address: no address found in string\n"); + cmdstr += idx; + } + + /* skip whitespace before the command */ + while (isspace(*cmdstr)) cmdstr++; + + /* Check for inversion flag */ + if (*cmdstr == '!') { + sed_cmd->invert = 1; + cmdstr++; + + /* skip whitespace before the command */ + while (isspace(*cmdstr)) cmdstr++; + } + + /* last part (mandatory) will be a command */ + if (!*cmdstr) error_msg_and_die("missing command"); + sed_cmd->cmd = *(cmdstr++); + cmdstr = parse_cmd_args(sed_cmd, cmdstr); + + /* Add the command to the command array */ + sed_cmd_tail->next = sed_cmd; + sed_cmd_tail = sed_cmd_tail->next; + } + + /* If we glued multiple lines together, free the memory. */ + if(add_cmd_line) { + free(add_cmd_line); + add_cmd_line=NULL; + } +} + +struct pipeline { + char *buf; /* Space to hold string */ + int idx; /* Space used */ + int len; /* Space allocated */ +} pipeline; + +#define PIPE_GROW 64 + +void pipe_putc(char c) +{ + if(pipeline.idx==pipeline.len) { + pipeline.buf = xrealloc(pipeline.buf, pipeline.len + PIPE_GROW); + pipeline.len+=PIPE_GROW; + } + pipeline.buf[pipeline.idx++] = (c); +} + +static void do_subst_w_backrefs(const char *line, const char *replace) +{ + int i,j; + + /* go through the replacement string */ + for (i = 0; replace[i]; i++) { + /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */ + if (replace[i] == '\\' && replace[i+1]>'0' && replace[i+1]<='9') { + int backref=replace[++i]-'0'; + + /* print out the text held in regmatch[backref] */ + if(regmatch[backref].rm_so != -1) + for (j = regmatch[backref].rm_so; j < regmatch[backref].rm_eo; j++) + pipe_putc(line[j]); + } + + /* if we find a backslash escaped character, print the character */ + else if (replace[i] == '\\') pipe_putc(replace[++i]); + + /* if we find an unescaped '&' print out the whole matched text. */ + else if (replace[i] == '&') + for (j = regmatch[0].rm_so; j < regmatch[0].rm_eo; j++) + pipe_putc(line[j]); + /* Otherwise just output the character. */ + else pipe_putc(replace[i]); + } +} + +static int do_subst_command(sed_cmd_t * sed_cmd, char **line) +{ + char *oldline = *line; + int altered = 0; + int match_count=0; + regex_t *current_regex; + + /* Handle empty regex. */ + if (sed_cmd->sub_match == NULL) { + current_regex = previous_regex_ptr; + if(!current_regex) + error_msg_and_die("No previous regexp."); + } else previous_regex_ptr = current_regex = sed_cmd->sub_match; + + /* Find the first match */ + if(REG_NOMATCH==regexec(current_regex, oldline, 10, regmatch, 0)) + return 0; + + /* Initialize temporary output buffer. */ + pipeline.buf=xmalloc(PIPE_GROW); + pipeline.len=PIPE_GROW; + pipeline.idx=0; + + /* Now loop through, substituting for matches */ + do { + int i; + + match_count++; + + /* If we aren't interested in this match, output old line to + end of match and continue */ + if(sed_cmd->which_match && sed_cmd->which_match!=match_count) { + for(i=0;istring); + + /* advance past the match */ + oldline += regmatch[0].rm_eo; + /* flag that something has changed */ + altered++; + + /* if we're not doing this globally, get out now */ + if (sed_cmd->which_match) break; + } while (*oldline && (regexec(current_regex, oldline, 10, regmatch, 0) != REG_NOMATCH)); + + /* Copy rest of string into output pipeline */ + + while(*oldline) pipe_putc(*(oldline++)); + pipe_putc(0); + + free(*line); + *line = pipeline.buf; + return altered; +} + +/* Set command pointer to point to this label. (Does not handle null label.) */ +static sed_cmd_t *branch_to(const char *label) +{ + sed_cmd_t *sed_cmd; + + for (sed_cmd = sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) { + if ((sed_cmd->cmd == ':') && (sed_cmd->string) && (strcmp(sed_cmd->string, label) == 0)) { + return (sed_cmd); + } + } + error_msg_and_die("Can't find label for jump to `%s'", label); +} + +/* Append copy of string to append buffer */ +static void append(char *s) +{ + struct append_list *temp=calloc(1,sizeof(struct append_list)); + + if(append_head) + append_tail=(append_tail->next=temp); + else append_head=append_tail=temp; + temp->string=strdup(s); +} + +static void flush_append(void) +{ + /* Output appended lines. */ + while(append_head) { + puts(append_head->string); + append_tail=append_head->next; + free(append_head->string); + free(append_head); + append_head=append_tail; + } + append_head=append_tail=NULL; +} + +/* Get next line of input, flushing append buffer and noting if we hit EOF + * without a newline on the last line. + */ +static char *get_next_line(FILE * file, int *no_newline) +{ + char *temp; + int len; + + flush_append(); + temp=get_line_from_file(file); + if(temp) { + len=strlen(temp); + if(len && temp[len-1]=='\n') temp[len-1]=0; + else *no_newline=1; + } + + return temp; +} + +/* Output line of text. missing_newline means the last line output did not + end with a newline. no_newline means this line does not end with a + newline. */ + +static int puts_maybe_newline(char *s, FILE *file, int missing_newline, int no_newline) +{ + if(missing_newline) fputc('\n',file); + fputs(s,file); + if(!no_newline) fputc('\n',file); + + return no_newline; +} + +#define sed_puts(s,n) missing_newline=puts_maybe_newline(s,stdout,missing_newline,n) + +static void process_file(FILE * file) +{ + char *pattern_space, *next_line, *hold_space=NULL; + static int linenum = 0, missing_newline=0; + int no_newline,next_no_newline=0; + + next_line = get_next_line(file,&next_no_newline); + + /* go through every line in the file */ + for(;;) { + sed_cmd_t *sed_cmd; + int substituted=0; + + /* Advance to next line. Stop if out of lines. */ + if(!(pattern_space=next_line)) break; + no_newline=next_no_newline; + + /* Read one line in advance so we can act on the last line, the '$' address */ + next_line = get_next_line(file,&next_no_newline); + linenum++; +restart: + /* for every line, go through all the commands */ + for (sed_cmd = sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) { + int old_matched, matched; + + old_matched = sed_cmd->in_match; + + /* Determine if this command matches this line: */ + + /* Are we continuing a previous multi-line match? */ + + sed_cmd->in_match = sed_cmd->in_match + + /* Or is no range necessary? */ + || (!sed_cmd->beg_line && !sed_cmd->end_line + && !sed_cmd->beg_match && !sed_cmd->end_match) + + /* Or did we match the start of a numerical range? */ + || (sed_cmd->beg_line > 0 && (sed_cmd->beg_line == linenum)) + + /* Or does this line match our begin address regex? */ + || (sed_cmd->beg_match && + !regexec(sed_cmd->beg_match, pattern_space, 0, NULL, 0)) + + /* Or did we match last line of input? */ + || (sed_cmd->beg_line == -1 && next_line == NULL); + + /* Snapshot the value */ + + matched = sed_cmd->in_match; + + /* Is this line the end of the current match? */ + + if(matched) { + sed_cmd->in_match = !( + /* has the ending line come, or is this a single address command? */ + (sed_cmd->end_line ? + sed_cmd->end_line==-1 ? + !next_line + : sed_cmd->end_line<=linenum + : !sed_cmd->end_match) + /* or does this line matches our last address regex */ + || (sed_cmd->end_match && old_matched && (regexec(sed_cmd->end_match, pattern_space, 0, NULL, 0) == 0)) + ); + } + + /* Skip blocks of commands we didn't match. */ + if (sed_cmd->cmd == '{') { + if(sed_cmd->invert ? matched : !matched) + while(sed_cmd && sed_cmd->cmd!='}') sed_cmd=sed_cmd->next; + if(!sed_cmd) error_msg_and_die("Unterminated {"); + continue; + } + + /* Okay, so did this line match? */ + if (sed_cmd->invert ? !matched : matched) { + /* Update last used regex in case a blank substitute BRE is found */ + if (sed_cmd->beg_match) { + previous_regex_ptr = sed_cmd->beg_match; + } + + /* actual sedding */ + switch (sed_cmd->cmd) { + + /* Print line number */ + case '=': + printf("%d\n", linenum); + break; + + /* Write the current pattern space up to the first newline */ + case 'P': + { + char *tmp = strchr(pattern_space, '\n'); + + if (tmp) { + *tmp = '\0'; + sed_puts(pattern_space,1); + *tmp = '\n'; + break; + } + /* Fall Through */ + } + + /* Write the current pattern space to output */ + case 'p': + sed_puts(pattern_space,no_newline); + break; + /* Delete up through first newline */ + case 'D': + { + char *tmp = strchr(pattern_space,'\n'); + + if(tmp) { + tmp=xstrdup(tmp+1); + free(pattern_space); + pattern_space=tmp; + goto restart; + } + } + /* discard this line. */ + case 'd': + goto discard_line; + + /* Substitute with regex */ + case 's': + if(do_subst_command(sed_cmd, &pattern_space)) { + substituted|=1; + + /* handle p option */ + if(sed_cmd->sub_p) + sed_puts(pattern_space,no_newline); + /* handle w option */ + if(sed_cmd->file) + sed_cmd->no_newline=puts_maybe_newline(pattern_space, sed_cmd->file, sed_cmd->no_newline, no_newline); + + } + break; + + /* Append line to linked list to be printed later */ + case 'a': + { + append(sed_cmd->string); + break; + } + + /* Insert text before this line */ + case 'i': + sed_puts(sed_cmd->string,1); + break; + + /* Cut and paste text (replace) */ + case 'c': + /* Only triggers on last line of a matching range. */ + if (!sed_cmd->in_match) sed_puts(sed_cmd->string,1); + goto discard_line; + + /* Read file, append contents to output */ + case 'r': + { + FILE *outfile; + + outfile = fopen(sed_cmd->string, "r"); + if (outfile) { + char *line; + + while ((line = get_chomped_line_from_file(outfile)) + != NULL) + append(line); + bb_xprint_and_close_file(outfile); + } + + break; + } + + /* Write pattern space to file. */ + case 'w': + sed_cmd->no_newline=puts_maybe_newline(pattern_space,sed_cmd->file, sed_cmd->no_newline,no_newline); + break; + + /* Read next line from input */ + case 'n': + if (!be_quiet) + sed_puts(pattern_space,no_newline); + if (next_line) { + free(pattern_space); + pattern_space = next_line; + no_newline=next_no_newline; + next_line = get_next_line(file,&next_no_newline); + linenum++; + break; + } + /* fall through */ + + /* Quit. End of script, end of input. */ + case 'q': + /* Exit the outer while loop */ + free(next_line); + next_line = NULL; + goto discard_commands; + + /* Append the next line to the current line */ + case 'N': + { + /* If no next line, jump to end of script and exit. */ + if (next_line == NULL) { + /* Jump to end of script and exit */ + free(next_line); + next_line = NULL; + goto discard_line; + /* append next_line, read new next_line. */ + } else { + int len=strlen(pattern_space); + + pattern_space = realloc(pattern_space, len + strlen(next_line) + 2); + pattern_space[len]='\n'; + strcpy(pattern_space+len+1, next_line); + no_newline=next_no_newline; + next_line = get_next_line(file,&next_no_newline); + linenum++; + } + break; + } + + /* Test if substition worked, branch if so. */ + case 't': + if (!substituted) break; + substituted=0; + /* Fall through */ + /* Branch to label */ + case 'b': + if (!sed_cmd->string) goto discard_commands; + else sed_cmd = branch_to(sed_cmd->string); + break; + /* Transliterate characters */ + case 'y': + { + int i; + + for (i = 0; pattern_space[i]; i++) { + int j; + + for (j = 0; sed_cmd->string[j]; j += 2) { + if (pattern_space[i] == sed_cmd->string[j]) { + pattern_space[i] = sed_cmd->string[j + 1]; + } + } + } + + break; + } + case 'g': /* Replace pattern space with hold space */ + free(pattern_space); + if (hold_space) { + pattern_space = strdup(hold_space); + no_newline=0; + } + break; + case 'G': /* Append newline and hold space to pattern space */ + { + int pattern_space_size = 2; + int hold_space_size = 0; + + if (pattern_space) + pattern_space_size += strlen(pattern_space); + if (hold_space) hold_space_size = strlen(hold_space); + pattern_space = xrealloc(pattern_space, pattern_space_size + hold_space_size); + if (pattern_space_size == 2) pattern_space[0]=0; + strcat(pattern_space, "\n"); + if (hold_space) strcat(pattern_space, hold_space); + no_newline=0; + + break; + } + case 'h': /* Replace hold space with pattern space */ + free(hold_space); + hold_space = strdup(pattern_space); + break; + case 'H': /* Append newline and pattern space to hold space */ + { + int hold_space_size = 2; + int pattern_space_size = 0; + + if (hold_space) hold_space_size += strlen(hold_space); + if (pattern_space) + pattern_space_size = strlen(pattern_space); + hold_space = xrealloc(hold_space, + hold_space_size + pattern_space_size); + + if (hold_space_size == 2) hold_space[0]=0; + strcat(hold_space, "\n"); + if (pattern_space) strcat(hold_space, pattern_space); + + break; + } + case 'x': /* Exchange hold and pattern space */ + { + char *tmp = pattern_space; + pattern_space = hold_space; + no_newline=0; + hold_space = tmp; + break; + } + } + } + } + + /* + * exit point from sedding... + */ +discard_commands: + /* we will print the line unless we were told to be quiet ('-n') + or if the line was suppressed (ala 'd'elete) */ + if (!be_quiet) sed_puts(pattern_space,no_newline); + + /* Delete and such jump here. */ +discard_line: + flush_append(); + free(pattern_space); + } +} + +/* It is possible to have a command line argument with embedded + newlines. This counts as multiple command lines. */ + +static void add_cmd_block(char *cmdstr) +{ + int go=1; + char *temp=xstrdup(cmdstr),*temp2=temp; + + while(go) { + int len=strcspn(temp2,"\n"); + if(!temp2[len]) go=0; + else temp2[len]=0; + add_cmd(temp2); + temp2+=len+1; + } + free(temp); +} + +extern int sed_main(int argc, char **argv) +{ + int opt, status = EXIT_SUCCESS; + +#ifdef BB_FEATURE_CLEAN_UP + /* destroy command strings on exit */ + if (atexit(free_and_close_stuff) == -1) + perror_msg_and_die("atexit"); +#endif + + /* do normal option parsing */ + while ((opt = getopt(argc, argv, "ne:f:")) > 0) { + switch (opt) { + case 'n': + be_quiet++; + break; + case 'e': + add_cmd_block(optarg); + break; + case 'f': + { + FILE *cmdfile; + char *line; + + cmdfile = xfopen(optarg, "r"); + + while ((line = get_chomped_line_from_file(cmdfile)) + != NULL) { + add_cmd(line); + free(line); + } + bb_xprint_and_close_file(cmdfile); + + break; + } + default: + show_usage(); + } + } + + /* if we didn't get a pattern from a -e and no command file was specified, + * argv[optind] should be the pattern. no pattern, no worky */ + if (sed_cmd_head.next == NULL) { + if (argv[optind] == NULL) + show_usage(); + else + add_cmd_block(argv[optind++]); + } + /* Flush any unfinished commands. */ + add_cmd(""); + + /* 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) { + process_file(stdin); + } else { + int i; + FILE *file; + + for (i = optind; i < argc; i++) { + if(!strcmp(argv[i], "-")) { + process_file(stdin); + } else { + file = wfopen(argv[i], "r"); + if (file) { + process_file(file); + fclose(file); + } else { + status = EXIT_FAILURE; + } + } + } + } + + return status; +} diff --git a/setkeycodes.c b/setkeycodes.c new file mode 100644 index 000000000..85612c8b1 --- /dev/null +++ b/setkeycodes.c @@ -0,0 +1,72 @@ +/* vi: set sw=4 ts=4: */ +/* + * setkeycodes + * + * Copyright (C) 1994-1998 Andries E. Brouwer + * + * Adjusted for BusyBox 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 + * + */ + +#include +#include +#include +#include +#include "busybox.h" + + +/* From */ +struct kbkeycode { + unsigned int scancode, keycode; +}; +static const int KDSETKEYCODE = 0x4B4D; /* write kernel keycode table entry */ + +extern int +setkeycodes_main(int argc, char** argv) +{ + char *ep; + int fd, sc; + struct kbkeycode a; + + if (argc % 2 != 1 || argc < 2) { + show_usage(); + } + + fd = get_console_fd(); + + while (argc > 2) { + a.keycode = atoi(argv[2]); + a.scancode = sc = strtol(argv[1], &ep, 16); + if (*ep) { + error_msg_and_die("error reading SCANCODE: '%s'", argv[1]); + } + if (a.scancode > 127) { + a.scancode -= 0xe000; + a.scancode += 128; + } + if (a.scancode > 255 || a.keycode > 127) { + error_msg_and_die("SCANCODE or KEYCODE outside bounds"); + } + if (ioctl(fd,KDSETKEYCODE,&a)) { + perror("KDSETKEYCODE"); + error_msg_and_die("failed to set SCANCODE %x to KEYCODE %d", sc, a.keycode); + } + argc -= 2; + argv += 2; + } + return EXIT_SUCCESS; +} diff --git a/sleep.c b/sleep.c new file mode 100644 index 000000000..7bc98d8e8 --- /dev/null +++ b/sleep.c @@ -0,0 +1,37 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini sleep implementation for busybox + * + * 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 + * + */ + +#include +#include +#include +#include "busybox.h" + +extern int sleep_main(int argc, char **argv) +{ + if ((argc < 2) || (**(argv + 1) == '-')) { + show_usage(); + } + + if (sleep(atoi(*(++argv))) != 0) + perror_msg_and_die("sleep"); + return EXIT_SUCCESS; +} diff --git a/sort.c b/sort.c new file mode 100644 index 000000000..4f4979cc5 --- /dev/null +++ b/sort.c @@ -0,0 +1,106 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini sort implementation for busybox + * + * + * Copyright (C) 2000 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 + * + */ + +#include +#include +#include +#include "busybox.h" + +static int compare_ascii(const void *x, const void *y) +{ + return strcmp(*(char **)x, *(char **)y); +} + +static int compare_numeric(const void *x, const void *y) +{ + int z = atoi(*(char **)x) - atoi(*(char **)y); + return z ? z : strcmp(*(char **)x, *(char **)y); +} + +int sort_main(int argc, char **argv) +{ + FILE *fp; + char *line, **lines = NULL; + int i, opt, nlines = 0; + int (*compare)(const void *, const void *) = compare_ascii; +#ifdef BB_FEATURE_SORT_REVERSE + int reverse = FALSE; +#endif +#ifdef BB_FEATURE_SORT_UNIQUE + int unique = FALSE; +#endif + + while ((opt = getopt(argc, argv, "nru")) != -1) { + switch (opt) { + case 'n': + compare = compare_numeric; + break; +#ifdef BB_FEATURE_SORT_REVERSE + case 'r': + reverse = TRUE; + break; +#endif +#ifdef BB_FEATURE_SORT_UNIQUE + case 'u': + unique = TRUE; + break; +#endif + default: + show_usage(); + } + } + + /* read the input */ + for (i = optind; i == optind || i < argc; i++) { + if (argv[i] == NULL) + fp = stdin; + else + fp = xfopen(argv[i], "r"); + + while ((line = get_line_from_file(fp)) != NULL) { + lines = xrealloc(lines, sizeof(char *) * (nlines + 1)); + chomp(line); + lines[nlines++] = line; + } + } + + /* sort it */ + qsort(lines, nlines, sizeof(char *), compare); + + /* print it */ +#ifdef BB_FEATURE_SORT_REVERSE + if (reverse) { + for (i = --nlines; 0 <= i; i--) +#ifdef BB_FEATURE_SORT_UNIQUE + if((!unique) || (i == nlines) || (strcmp(lines[i + 1], lines[i]))) +#endif + puts(lines[i]); + } else +#endif + for (i = 0; i < nlines; i++) +#ifdef BB_FEATURE_SORT_UNIQUE + if((!unique) || (!i) || (strcmp(lines[i - 1], lines[i]))) +#endif + puts(lines[i]); + return EXIT_SUCCESS; +} diff --git a/stty.c b/stty.c new file mode 100644 index 000000000..a67a17c0f --- /dev/null +++ b/stty.c @@ -0,0 +1,1395 @@ +/* vi: set sw=4 ts=4: */ +/* 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. */ + +/* Usage: stty [-ag] [-F device] [setting...] + + Options: + -a Write all current settings to stdout in human-readable form. + -g Write all current settings to stdout in stty-readable form. + -F Open and use the specified device instead of stdin + + If no args are given, write to stdout the baud rate and settings that + have been changed from their defaults. Mode reading and changes + are done on the specified device, or stdin if none was specified. + + David MacKenzie + + Special for busybox ported by Vladimir Oleynik 2001 + + */ + +//#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) + + +#ifndef _POSIX_VDISABLE +# define _POSIX_VDISABLE ((unsigned char) 0) +#endif + +#define Control(c) ((c) & 0x1f) +/* Canonical values for control characters. */ +#ifndef CINTR +# define CINTR Control ('c') +#endif +#ifndef CQUIT +# define CQUIT 28 +#endif +#ifndef CERASE +# define CERASE 127 +#endif +#ifndef CKILL +# define CKILL Control ('u') +#endif +#ifndef CEOF +# define CEOF Control ('d') +#endif +#ifndef CEOL +# define CEOL _POSIX_VDISABLE +#endif +#ifndef CSTART +# define CSTART Control ('q') +#endif +#ifndef CSTOP +# define CSTOP Control ('s') +#endif +#ifndef CSUSP +# 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. */ +#if defined(VSUSP) && !defined(VSWTCH) +# define VSWTCH VSUSP +# define CSWTCH CSUSP +#endif +#if defined(VSWTCH) && !defined(CSWTCH) +# 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__) +# undef CSWTCH +# define CSWTCH _POSIX_VDISABLE +#endif + +#if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */ +# define VWERASE VWERSE +#endif +#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') +#endif +#if defined(VWERASE) && !defined(CWERASE) +# define CWERASE Control ('w') +#endif +#if defined(VLNEXT) && !defined(CLNEXT) +# define CLNEXT Control ('v') +#endif +#if defined(VDISCARD) && !defined(VFLUSHO) +# define VFLUSHO VDISCARD +#endif +#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */ +# define VFLUSHO VFLUSH +#endif +#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */ +# define ECHOCTL CTLECH +#endif +#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */ +# define ECHOCTL TCTLECH +#endif +#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */ +# define ECHOKE CRTKIL +#endif +#if defined(VFLUSHO) && !defined(CFLUSHO) +# define CFLUSHO Control ('o') +#endif +#if defined(VSTATUS) && !defined(CSTATUS) +# define CSTATUS Control ('t') +#endif + +/* Which speeds to set. */ +enum speed_setting { + input_speed, output_speed, both_speeds +}; + +/* What to output and how. */ +enum output_type { + changed, all, recoverable /* Default, -a, -g. */ +}; + +/* Which member(s) of `struct termios' a mode uses. */ +enum mode_type { + control, input, output, local, combination +}; + + +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. */ +struct mode_info { + const char *name; /* Name given on command line. */ + enum mode_type type; /* Which structure element to change. */ + char flags; /* Setting and display options. */ + unsigned long bits; /* Bits to set for this mode. */ + unsigned long mask; /* Other bits to turn off for this mode. */ +}; + +static const struct mode_info mode_info[] = { + {"parenb", control, REV, PARENB, 0 }, + {"parodd", control, REV, PARODD, 0 }, + {"cs5", control, 0, CS5, CSIZE}, + {"cs6", control, 0, CS6, CSIZE}, + {"cs7", control, 0, CS7, CSIZE}, + {"cs8", control, 0, CS8, CSIZE}, + {"hupcl", control, REV, HUPCL, 0 }, + {"hup", control, REV | OMIT, HUPCL, 0 }, + {"cstopb", control, REV, CSTOPB, 0 }, + {"cread", control, SANE_SET | REV, CREAD, 0 }, + {"clocal", control, REV, CLOCAL, 0 }, +#ifdef CRTSCTS + {"crtscts", control, REV, CRTSCTS, 0 }, +#endif + {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 }, + {"brkint", input, SANE_SET | REV, BRKINT, 0 }, + {"ignpar", input, REV, IGNPAR, 0 }, + {"parmrk", input, REV, PARMRK, 0 }, + {"inpck", input, REV, INPCK, 0 }, + {"istrip", input, REV, ISTRIP, 0 }, + {"inlcr", input, SANE_UNSET | REV, INLCR, 0 }, + {"igncr", input, SANE_UNSET | REV, IGNCR, 0 }, + {"icrnl", input, SANE_SET | REV, ICRNL, 0 }, + {"ixon", input, REV, IXON, 0 }, + {"ixoff", input, SANE_UNSET | REV, IXOFF, 0 }, + {"tandem", input, REV | OMIT, IXOFF, 0 }, +#ifdef IUCLC + {"iuclc", input, SANE_UNSET | REV, IUCLC, 0 }, +#endif +#ifdef IXANY + {"ixany", input, SANE_UNSET | REV, IXANY, 0 }, +#endif +#ifdef IMAXBEL + {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0 }, +#endif + {"opost", output, SANE_SET | REV, OPOST, 0 }, +#ifdef OLCUC + {"olcuc", output, SANE_UNSET | REV, OLCUC, 0 }, +#endif +#ifdef OCRNL + {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0 }, +#endif +#ifdef ONLCR + {"onlcr", output, SANE_SET | REV, ONLCR, 0 }, +#endif +#ifdef ONOCR + {"onocr", output, SANE_UNSET | REV, ONOCR, 0 }, +#endif +#ifdef ONLRET + {"onlret", output, SANE_UNSET | REV, ONLRET, 0 }, +#endif +#ifdef OFILL + {"ofill", output, SANE_UNSET | REV, OFILL, 0 }, +#endif +#ifdef OFDEL + {"ofdel", output, SANE_UNSET | REV, OFDEL, 0 }, +#endif +#ifdef NLDLY + {"nl1", output, SANE_UNSET, NL1, NLDLY}, + {"nl0", output, SANE_SET, NL0, NLDLY}, +#endif +#ifdef CRDLY + {"cr3", output, SANE_UNSET, CR3, CRDLY}, + {"cr2", output, SANE_UNSET, CR2, CRDLY}, + {"cr1", output, SANE_UNSET, CR1, CRDLY}, + {"cr0", output, SANE_SET, CR0, CRDLY}, +#endif + +#ifdef TABDLY + {"tab3", output, SANE_UNSET, TAB3, TABDLY}, + {"tab2", output, SANE_UNSET, TAB2, TABDLY}, + {"tab1", output, SANE_UNSET, TAB1, TABDLY}, + {"tab0", output, SANE_SET, TAB0, TABDLY}, +#else +# ifdef OXTABS + {"tab3", output, SANE_UNSET, OXTABS, 0 }, +# endif +#endif + +#ifdef BSDLY + {"bs1", output, SANE_UNSET, BS1, BSDLY}, + {"bs0", output, SANE_SET, BS0, BSDLY}, +#endif +#ifdef VTDLY + {"vt1", output, SANE_UNSET, VT1, VTDLY}, + {"vt0", output, SANE_SET, VT0, VTDLY}, +#endif +#ifdef FFDLY + {"ff1", output, SANE_UNSET, FF1, FFDLY}, + {"ff0", output, SANE_SET, FF0, FFDLY}, +#endif + {"isig", local, SANE_SET | REV, ISIG, 0 }, + {"icanon", local, SANE_SET | REV, ICANON, 0 }, +#ifdef IEXTEN + {"iexten", local, SANE_SET | REV, IEXTEN, 0 }, +#endif + {"echo", local, SANE_SET | REV, ECHO, 0 }, + {"echoe", local, SANE_SET | REV, ECHOE, 0 }, + {"crterase", local, REV | OMIT, ECHOE, 0 }, + {"echok", local, SANE_SET | REV, ECHOK, 0 }, + {"echonl", local, SANE_UNSET | REV, ECHONL, 0 }, + {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0 }, +#ifdef XCASE + {"xcase", local, SANE_UNSET | REV, XCASE, 0 }, +#endif +#ifdef TOSTOP + {"tostop", local, SANE_UNSET | REV, TOSTOP, 0 }, +#endif +#ifdef ECHOPRT + {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 }, + {"prterase", local, REV | OMIT, ECHOPRT, 0 }, +#endif +#ifdef ECHOCTL + {"echoctl", local, SANE_SET | REV, ECHOCTL, 0 }, + {"ctlecho", local, REV | OMIT, ECHOCTL, 0 }, +#endif +#ifdef ECHOKE + {"echoke", local, SANE_SET | REV, ECHOKE, 0 }, + {"crtkill", local, REV | OMIT, ECHOKE, 0 }, +#endif + {evenp, combination, REV | OMIT, 0, 0 }, + {parity, combination, REV | OMIT, 0, 0 }, + {stty_oddp, combination, REV | OMIT, 0, 0 }, + {stty_nl, combination, REV | OMIT, 0, 0 }, + {stty_ek, combination, OMIT, 0, 0 }, + {stty_sane, combination, OMIT, 0, 0 }, + {cooked, combination, REV | OMIT, 0, 0 }, + {raw, combination, REV | OMIT, 0, 0 }, + {stty_pass8, combination, REV | OMIT, 0, 0 }, + {litout, combination, REV | OMIT, 0, 0 }, + {cbreak, combination, REV | OMIT, 0, 0 }, +#ifdef IXANY + {decctlq, combination, REV | OMIT, 0, 0 }, +#endif +#if defined (TABDLY) || defined (OXTABS) + {stty_tabs, combination, REV | OMIT, 0, 0 }, +#endif +#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) + {stty_lcase, combination, REV | OMIT, 0, 0 }, + {stty_LCASE, combination, REV | OMIT, 0, 0 }, +#endif + {stty_crt, combination, OMIT, 0, 0 }, + {stty_dec, combination, OMIT, 0, 0 }, +}; + +static const int NUM_mode_info = + + (sizeof(mode_info) / sizeof(struct mode_info)); + +/* Control character settings. */ +struct control_info { + const char *name; /* Name given on command line. */ + unsigned char saneval; /* Value to set for `stty sane'. */ + int 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}, +#ifdef VEOL2 + {"eol2", CEOL2, VEOL2}, +#endif +#ifdef VSWTCH + {stty_swtch, CSWTCH, VSWTCH}, +#endif + {"start", CSTART, VSTART}, + {"stop", CSTOP, VSTOP}, + {"susp", CSUSP, VSUSP}, +#ifdef VDSUSP + {"dsusp", CDSUSP, VDSUSP}, +#endif +#ifdef VREPRINT + {"rprnt", CRPRNT, VREPRINT}, +#endif +#ifdef VWERASE + {"werase", CWERASE, VWERASE}, +#endif +#ifdef VLNEXT + {"lnext", CLNEXT, VLNEXT}, +#endif +#ifdef VFLUSHO + {"flush", CFLUSHO, VFLUSHO}, +#endif +#ifdef VSTATUS + {"status", CSTATUS, VSTATUS}, +#endif + /* These must be last because of the display routines. */ + {stty_min, 1, VMIN}, + {stty_time, 0, VTIME}, +}; + +static const int NUM_control_info = + (sizeof(control_info) / sizeof(struct control_info)); + + +static const char * visible(unsigned int ch); +static unsigned long baud_to_value(speed_t speed); +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, + const char *device_name); +static void display_changed(struct termios *mode); +static void display_recoverable(struct termios *mode); +static void display_settings(enum output_type output_type, + struct termios *mode, int fd, + const char *device_name); +static void display_speed(struct termios *mode, int fancy); +static void display_window_size(int fancy, int fd, + const char *device_name); +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, + const char *device_name); + +/* The width of the screen, for output wrapping. */ +static int max_col; + +/* Current position, to know when to wrap. */ +static int current_col; + +/* Print format string MESSAGE and optional args. + Wrap to next line first if it won't fit. + Print a space first unless MESSAGE will start a new line. */ + +static void wrapf(const char *message, ...) +{ + va_list args; + char buf[1024]; /* Plenty long for our needs. */ + int buflen; + + va_start(args, message); + vsprintf(buf, message, args); + va_end(args); + buflen = strlen(buf); + if (current_col + (current_col > 0) + buflen >= max_col) { + putchar('\n'); + current_col = 0; + } + if (current_col > 0) { + putchar(' '); + current_col++; + } + fputs(buf, stdout); + current_col += buflen; +} + +static const struct suffix_mult stty_suffixes[] = { + {"b", 512 }, + {"k", 1024}, + {"B", 1024}, + {NULL, 0 } +}; + +#ifndef TEST +extern int stty_main(int argc, char **argv) +#else +extern int main(int argc, char **argv) +#endif +{ + struct termios mode; + enum output_type output_type; + 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; + const char *device_name; + + output_type = 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_type = all; + break; + + case 'g': + recoverable_output = 1; + output_type = recoverable; + break; + + case 'F': + if (file_name) + error_msg_and_die("only one device may be specified"); + file_name = optarg; + break; + + default: /* unrecognized option */ + noargs = 0; + break; + } + + if (noargs == 0) + break; + } + + if (optind < argc) + noargs = 0; + + /* Specifying both -a and -g gets an error. */ + if (verbose_output && recoverable_output) + error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive"); + + /* Specifying any other arguments with -a or -g gets an error. */ + if (!noargs && (verbose_output || recoverable_output)) + error_msg_and_die ("modes may not be set when specifying an output style"); + + /* FIXME: it'd be better not to open the file until we've verified + that all arguments are valid. Otherwise, we could end up doing + only some of the requested operations and then failing, probably + leaving things in an undesirable state. */ + + if (file_name) { + int fdflags; + + device_name = file_name; + fd = open(device_name, O_RDONLY | O_NONBLOCK); + if (fd < 0) + perror_msg_and_die("%s", device_name); + if ((fdflags = fcntl(fd, F_GETFL)) == -1 + || fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) + perror_msg_and_die("%s: couldn't reset non-blocking mode", + device_name); + } else { + fd = 0; + device_name = "standard input"; + } + + /* Initialize to all zeroes so there is no risk memcmp will report a + spurious difference in an uninitialized portion of the structure. */ + memset(&mode, 0, sizeof(mode)); + if (tcgetattr(fd, &mode)) + perror_msg_and_die("%s", device_name); + + if (verbose_output || recoverable_output || noargs) { + max_col = screen_columns(); + current_col = 0; + display_settings(output_type, &mode, fd, device_name); + return EXIT_SUCCESS; + } + + speed_was_set = 0; + require_set_attr = 0; + k = 0; + while (++k < argc) { + int match_found = 0; + int reversed = 0; + int i; + + if (argv[k][0] == '-') { + char *find_dev_opt; + + ++argv[k]; + + /* Handle "-a", "-ag", "-aF/dev/foo", "-aF /dev/foo", etc. + Find the options that have been parsed. This is really + gross, but it's needed because stty SETTINGS look like options to + getopt(), so we need to work around things in a really horrible + way. If any new options are ever added to stty, the short option + MUST NOT be a letter which is the first letter of one of the + possible stty settings. + */ + find_dev_opt = strchr(argv[k], 'F'); /* find -*F* */ + if(find_dev_opt) { + if(find_dev_opt[1]==0) /* -*F /dev/foo */ + k++; /* skip /dev/foo */ + continue; /* else -*F/dev/foo - no skip */ + } + if(argv[k][0]=='a' || argv[k][0]=='g') + continue; + /* Is not options - is reverse params */ + reversed = 1; + } + for (i = 0; i < NUM_mode_info; ++i) + if (STREQ(argv[k], mode_info[i].name)) { + match_found = set_mode(&mode_info[i], reversed, &mode); + require_set_attr = 1; + break; + } + + if (match_found == 0 && reversed) + 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) + error_msg_and_die("missing argument to `%s'", argv[k]); + match_found = 1; + ++k; + set_control_char(&control_info[i], argv[k], &mode); + require_set_attr = 1; + break; + } + + if (match_found == 0) { + if (STREQ(argv[k], "ispeed")) { + if (k == argc - 1) + 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) + 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) + error_msg_and_die("missing argument to `%s'", argv[k]); + ++k; + set_window_size((int) parse_number(argv[k], stty_suffixes), + -1, fd, device_name); + } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) { + if (k == argc - 1) + error_msg_and_die("missing argument to `%s'", argv[k]); + ++k; + set_window_size(-1, + (int) parse_number(argv[k], stty_suffixes), + fd, device_name); + } else if (STREQ(argv[k], "size")) { + max_col = screen_columns(); + current_col = 0; + display_window_size(0, fd, device_name); + } +#endif +#ifdef HAVE_C_LINE + else if (STREQ(argv[k], "line")) { + if (k == argc - 1) + error_msg_and_die("missing argument to `%s'", argv[k]); + ++k; + mode.c_line = parse_number(argv[k], stty_suffixes); + require_set_attr = 1; + } +#endif + else if (STREQ(argv[k], "speed")) { + max_col = screen_columns(); + display_speed(&mode, 0); + } else if (recover_mode(argv[k], &mode) == 1) + require_set_attr = 1; + else if (string_to_baud(argv[k]) != (speed_t) - 1) { + set_speed(both_speeds, argv[k], &mode); + speed_was_set = 1; + require_set_attr = 1; + } else + error_msg_and_die("invalid argument `%s'", argv[k]); + } + } + + if (require_set_attr) { + struct termios new_mode; + + if (tcsetattr(fd, TCSADRAIN, &mode)) + perror_msg_and_die("%s", device_name); + + /* POSIX (according to Zlotnick's book) tcsetattr returns zero if + it performs *any* of the requested operations. This means it + can report `success' when it has actually failed to perform + some proper subset of the requested operations. To detect + this partial failure, get the current terminal attributes and + compare them to the requested ones. */ + + /* Initialize to all zeroes so there is no risk memcmp will report a + spurious difference in an uninitialized portion of the structure. */ + memset(&new_mode, 0, sizeof(new_mode)); + if (tcgetattr(fd, &new_mode)) + perror_msg_and_die("%s", device_name); + + /* Normally, one shouldn't use memcmp to compare structures that + may have `holes' containing uninitialized data, but we have been + careful to initialize the storage of these two variables to all + zeroes. One might think it more efficient simply to compare the + modified fields, but that would require enumerating those fields -- + and not all systems have the same fields in this structure. */ + + if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) { +#ifdef CIBAUD + /* SunOS 4.1.3 (at least) has the problem that after this sequence, + tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2); + sometimes (m1 != m2). The only difference is in the four bits + of the c_cflag field corresponding to the baud rate. To save + Sun users a little confusion, don't report an error if this + happens. But suppress the error only if we haven't tried to + set the baud rate explicitly -- otherwise we'd never give an + error for a true failure to set the baud rate. */ + + new_mode.c_cflag &= (~CIBAUD); + if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0) +#endif + error_msg_and_die ("%s: unable to perform all requested operations", + device_name); + } + } + + return EXIT_SUCCESS; +} + +/* Return 0 if not applied because not reversible; otherwise return 1. */ + +static int +set_mode(const struct mode_info *info, int reversed, struct termios *mode) +{ + tcflag_t *bitsp; + + if (reversed && (info->flags & REV) == 0) + return 0; + + bitsp = mode_type_flag(info->type, mode); + + if (bitsp == NULL) { + /* Combination mode. */ + if (info->name == evenp || info->name == parity) { + if (reversed) + mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; + else + mode->c_cflag = + (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7; + } else if (info->name == stty_oddp) { + if (reversed) + mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; + else + mode->c_cflag = + (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB; + } else if (info->name == stty_nl) { + if (reversed) { + mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR; + mode->c_oflag = (mode->c_oflag +#ifdef ONLCR + | ONLCR +#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 & ~info->mask & ~info->bits; + else + *bitsp = (*bitsp & ~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 = parse_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 = parse_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 == input_speed || type == both_speeds) + cfsetispeed(mode, baud); + if (type == output_speed || type == both_speeds) + 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, const char *device_name) +{ + struct winsize win; + + if (get_win_size(fd, &win)) { + if (errno != EINVAL) + perror_msg_and_die("%s", device_name); + 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 = 1; + win.ws_col = 1; + + if (ioctl(fd, TIOCSWINSZ, (char *) &win)) + perror_msg_and_die("%s", device_name); + + if (ioctl(fd, TIOCSSIZE, (char *) &ttysz)) + perror_msg_and_die("%s", device_name); + return; + } +# endif + + if (ioctl(fd, TIOCSWINSZ, (char *) &win)) + perror_msg_and_die("%s", device_name); +} + +static void display_window_size(int fancy, int fd, const char *device_name) +{ + struct winsize win; + + if (get_win_size(fd, &win)) { + if (errno != EINVAL) + perror_msg_and_die("%s", device_name); + if (!fancy) + perror_msg_and_die("%s: no size information for this device", + device_name); + } else { + wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n", + win.ws_row, win.ws_col); + if (!fancy) + current_col = 0; + } +} +#endif + +static int screen_columns(void) +{ +#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 + + if (getenv("COLUMNS")) + return atoi(getenv("COLUMNS")); + return 80; +} + +static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode) +{ + switch (type) { + case control: + return &mode->c_cflag; + + case input: + return &mode->c_iflag; + + case output: + return &mode->c_oflag; + + case local: + return &mode->c_lflag; + + default: /* combination: */ + return NULL; + } +} + +static void +display_settings(enum output_type output_type, struct termios *mode, + int fd, const char *device_name) +{ + switch (output_type) { + case changed: + display_changed(mode); + break; + + case all: + display_all(mode, fd, device_name); + break; + + case recoverable: + display_recoverable(mode); + break; + } +} + +static void display_changed(struct termios *mode) +{ + int i; + int empty_line; + tcflag_t *bitsp; + unsigned long mask; + enum mode_type prev_type = control; + + display_speed(mode, 1); +#ifdef HAVE_C_LINE + wrapf("line = %d;", mode->c_line); +#endif + putchar('\n'); + current_col = 0; + + empty_line = 1; + for (i = 0; control_info[i].name != stty_min; ++i) { + if (mode->c_cc[control_info[i].offset] == control_info[i].saneval) + continue; + /* If swtch is the same as susp, don't print both. */ +#if VSWTCH == VSUSP + if (control_info[i].name == stty_swtch) + continue; +#endif + /* If eof uses the same slot as min, only print whichever applies. */ +#if VEOF == VMIN + if ((mode->c_lflag & ICANON) == 0 + && (control_info[i].name == stty_eof + || control_info[i].name == stty_eol)) continue; +#endif + + empty_line = 0; + wrapf("%s = %s;", control_info[i].name, + visible(mode->c_cc[control_info[i].offset])); + } + if ((mode->c_lflag & ICANON) == 0) { + wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN], + (int) mode->c_cc[VTIME]); + } else if (empty_line == 0) + putchar('\n'); + current_col = 0; + + empty_line = 1; + for (i = 0; i < NUM_mode_info; ++i) { + if (mode_info[i].flags & OMIT) + continue; + if (mode_info[i].type != prev_type) { + if (empty_line == 0) { + putchar('\n'); + current_col = 0; + empty_line = 1; + } + prev_type = mode_info[i].type; + } + + bitsp = mode_type_flag(mode_info[i].type, mode); + mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; + if ((*bitsp & mask) == mode_info[i].bits) { + if (mode_info[i].flags & SANE_UNSET) { + wrapf("%s", mode_info[i].name); + empty_line = 0; + } + } + else if ((mode_info[i].flags & (SANE_SET | REV)) == + (SANE_SET | REV)) { + wrapf("-%s", mode_info[i].name); + empty_line = 0; + } + } + if (empty_line == 0) + putchar('\n'); + current_col = 0; +} + +static void +display_all(struct termios *mode, int fd, const char *device_name) +{ + 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, device_name); +#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; +#endif + wrapf("%s = %s;", control_info[i].name, + visible(mode->c_cc[control_info[i].offset])); + } +#if VEOF == VMIN + if ((mode->c_lflag & ICANON) == 0) +#endif + wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]); + if (current_col != 0) + putchar('\n'); + current_col = 0; + + 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; + } + + 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) +{ + if (cfgetispeed(mode) == 0 || cfgetispeed(mode) == cfgetospeed(mode)) + wrapf(fancy ? "speed %lu baud;" : "%lu\n", + baud_to_value(cfgetospeed(mode))); + else + wrapf(fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n", + baud_to_value(cfgetispeed(mode)), + baud_to_value(cfgetospeed(mode))); + if (!fancy) + current_col = 0; +} + +static void display_recoverable(struct termios *mode) +{ + int i; + + printf("%lx:%lx:%lx:%lx", + (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag, + (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag); + for (i = 0; i < NCCS; ++i) + printf(":%x", (unsigned int) mode->c_cc[i]); + putchar('\n'); +} + +static int recover_mode(char *arg, struct termios *mode) +{ + int i, n; + unsigned int chr; + unsigned long iflag, oflag, cflag, lflag; + + /* Scan into temporaries since it is too much trouble to figure out + the right format for `tcflag_t'. */ + if (sscanf(arg, "%lx:%lx:%lx:%lx%n", + &iflag, &oflag, &cflag, &lflag, &n) != 4) + return 0; + mode->c_iflag = iflag; + mode->c_oflag = oflag; + mode->c_cflag = cflag; + mode->c_lflag = lflag; + arg += n; + for (i = 0; i < NCCS; ++i) { + if (sscanf(arg, ":%x%n", &chr, &n) != 1) + return 0; + mode->c_cc[i] = chr; + arg += n; + } + + /* Fail if there are too many fields. */ + if (*arg != '\0') + return 0; + + return 1; +} + +struct speed_map { + speed_t speed; /* Internal form. */ + unsigned long value; /* Numeric value. */ +}; + +static const struct speed_map speeds[] = { + {B0, 0}, + {B50, 50}, + {B75, 75}, + {B110, 110}, + {B134, 134}, + {B150, 150}, + {B200, 200}, + {B300, 300}, + {B600, 600}, + {B1200, 1200}, + {B1800, 1800}, + {B2400, 2400}, + {B4800, 4800}, + {B9600, 9600}, + {B19200, 19200}, + {B38400, 38400}, +#ifdef B57600 + {B57600, 57600}, +#endif +#ifdef B115200 + {B115200, 115200}, +#endif +#ifdef B230400 + {B230400, 230400}, +#endif +#ifdef B460800 + {B460800, 460800}, +#endif +}; + +static const int NUM_SPEEDS = (sizeof(speeds) / sizeof(struct speed_map)); + +static speed_t string_to_baud(const char *arg) +{ + int i; + + for (i = 0; i < NUM_SPEEDS; ++i) + if (parse_number(arg, 0) == speeds[i].value) + return speeds[i].speed; + return (speed_t) - 1; +} + +static unsigned long baud_to_value(speed_t speed) +{ + int i; + + for (i = 0; i < NUM_SPEEDS; ++i) + if (speed == speeds[i].speed) + return speeds[i].value; + return 0; +} + +static void sane_mode(struct termios *mode) +{ + int i; + tcflag_t *bitsp; + + for (i = 0; i < NUM_control_info; ++i) { +#if VMIN == VEOF + if (control_info[i].name == stty_min) + break; +#endif + mode->c_cc[control_info[i].offset] = control_info[i].saneval; + } + + 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 & ~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 & ~mode_info[i].mask & ~mode_info[i].bits; + } + } +} + +/* 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; + + if (ch == _POSIX_VDISABLE) + return ""; + + if (ch >= 32) { + if (ch < 127) + *bpout++ = ch; + else if (ch == 127) { + *bpout++ = '^'; + *bpout++ = '?'; + } else { + *bpout++ = 'M', *bpout++ = '-'; + if (ch >= 128 + 32) { + if (ch < 128 + 127) + *bpout++ = ch - 128; + else { + *bpout++ = '^'; + *bpout++ = '?'; + } + } else { + *bpout++ = '^'; + *bpout++ = ch - 128 + 64; + } + } + } else { + *bpout++ = '^'; + *bpout++ = ch + 64; + } + *bpout = '\0'; + return (const char *) buf; +} + +#ifdef TEST + +const char *applet_name = "stty"; + +#endif + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/swaponoff.c b/swaponoff.c new file mode 100644 index 000000000..a57dfe472 --- /dev/null +++ b/swaponoff.c @@ -0,0 +1,116 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini swapon/swapoff implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#if __GNU_LIBRARY__ < 5 +/* libc5 doesn't have sys/swap.h, define these here. */ +extern int swapon (__const char *__path, int __flags); +extern int swapoff (__const char *__path); +#else +#include +#endif + +#include "busybox.h" + +static int whichApp; /* default SWAPON_APP */ + +static const int SWAPON_APP = 0; +static const int SWAPOFF_APP = 1; + + +static int swap_enable_disable(const char *device) +{ + int status; + + if (whichApp == SWAPON_APP) + status = swapon(device, 0); + else + status = swapoff(device); + + if (status != 0) { + perror_msg("%s", device); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +static int do_em_all(void) +{ + struct mntent *m; + FILE *f = setmntent("/etc/fstab", "r"); + int err = 0; + + if (f == NULL) + perror_msg_and_die("/etc/fstab"); + while ((m = getmntent(f)) != NULL) { + if (strcmp(m->mnt_type, MNTTYPE_SWAP)==0) { + if(swap_enable_disable(m->mnt_fsname) == EXIT_FAILURE) + err++; + } + } + endmntent(f); + return err; +} + + +extern int swap_on_off_main(int argc, char **argv) +{ + if (applet_name[5] == 'f') { /* "swapoff" */ + whichApp = SWAPOFF_APP; + } + + if (argc != 2) { + goto usage_and_exit; + } + argc--; + argv++; + + /* Parse any options */ + while (**argv == '-') { + while (*++(*argv)) + switch (**argv) { + case 'a': + { + struct stat statBuf; + + if (stat("/etc/fstab", &statBuf) < 0) + error_msg_and_die("/etc/fstab file missing"); + } + return do_em_all(); + break; + default: + goto usage_and_exit; + } + } + return swap_enable_disable(*argv); + + usage_and_exit: + show_usage(); +} diff --git a/sync.c b/sync.c new file mode 100644 index 000000000..ee22ae109 --- /dev/null +++ b/sync.c @@ -0,0 +1,35 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini sync implementation for busybox + * + * + * 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 + * + */ + +#include +#include +#include +#include "busybox.h" + +extern int sync_main(int argc, char **argv) +{ + if (argc > 1 && **(argv + 1) == '-') + show_usage(); + sync(); + return(EXIT_SUCCESS); +} diff --git a/syslogd.c b/syslogd.c new file mode 100644 index 000000000..784337b0b --- /dev/null +++ b/syslogd.c @@ -0,0 +1,638 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini syslogd implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen + * + * Copyright (C) 2000 by Karl M. Hegbloom + * + * "circular buffer" Copyright (C) 2001 by Gennady Feldman + * + * Maintainer: Gennady Feldman as of Mar 12, 2001 + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "busybox.h" + +/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */ +#define SYSLOG_NAMES +#include +#include + +/* Path for the file where all log messages are written */ +#define __LOG_FILE "/var/log/messages" + +/* Path to the unix socket */ +static char lfile[MAXPATHLEN]; + +static char *logFilePath = __LOG_FILE; + +/* interval between marks in seconds */ +static int MarkInterval = 20 * 60; + +/* localhost's name */ +static char LocalHostName[64]; + +#ifdef BB_FEATURE_REMOTE_LOG +#include +/* udp socket for logging to remote host */ +static int remotefd = -1; +/* where do we log? */ +static char *RemoteHost; +/* what port to log to? */ +static int RemotePort = 514; +/* To remote log or not to remote log, that is the question. */ +static int doRemoteLog = FALSE; +static int local_logging = FALSE; +#endif + + +#define MAXLINE 1024 /* maximum line length */ + + +/* circular buffer variables/structures */ +#ifdef BB_FEATURE_IPC_SYSLOG +#if __GNU_LIBRARY__ < 5 +#error Sorry. Looks like you are using libc5. +#error libc5 shm support isnt good enough. +#error Please disable BB_FEATURE_IPC_SYSLOG +#endif + +#include +#include +#include + +/* our shared key */ +static const long KEY_ID = 0x414e4547; /*"GENA"*/ + +// Semaphore operation structures +static struct shbuf_ds { + int size; // size of data written + int head; // start of message list + int tail; // end of message list + char data[1]; // data/messages +} *buf = NULL; // shared memory pointer + +static struct sembuf SMwup[1] = {{1, -1, IPC_NOWAIT}}; // set SMwup +static struct sembuf SMwdn[3] = {{0, 0}, {1, 0}, {1, +1}}; // set SMwdn + +static int shmid = -1; // ipc shared memory id +static int s_semid = -1; // ipc semaphore id +int data_size = 16000; // data size +int shm_size = 16000 + sizeof(*buf); // our buffer size +static int circular_logging = FALSE; + +/* + * sem_up - up()'s a semaphore. + */ +static inline void sem_up(int semid) +{ + if ( semop(semid, SMwup, 1) == -1 ) + perror_msg_and_die("semop[SMwup]"); +} + +/* + * sem_down - down()'s a semaphore + */ +static inline void sem_down(int semid) +{ + if ( semop(semid, SMwdn, 3) == -1 ) + perror_msg_and_die("semop[SMwdn]"); +} + + +void ipcsyslog_cleanup(void){ + printf("Exiting Syslogd!\n"); + if (shmid != -1) + shmdt(buf); + + if (shmid != -1) + shmctl(shmid, IPC_RMID, NULL); + if (s_semid != -1) + semctl(s_semid, 0, IPC_RMID, 0); +} + +void ipcsyslog_init(void){ + if (buf == NULL){ + if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1) + perror_msg_and_die("shmget"); + + + if ((buf = shmat(shmid, NULL, 0)) == NULL) + perror_msg_and_die("shmat"); + + + buf->size=data_size; + buf->head=buf->tail=0; + + // we'll trust the OS to set initial semval to 0 (let's hope) + if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1){ + if (errno == EEXIST){ + if ((s_semid = semget(KEY_ID, 2, 0)) == -1) + perror_msg_and_die("semget"); + }else + perror_msg_and_die("semget"); + } + }else{ + printf("Buffer already allocated just grab the semaphore?"); + } +} + +/* write message to buffer */ +void circ_message(const char *msg){ + int l=strlen(msg)+1; /* count the whole message w/ '\0' included */ + + sem_down(s_semid); + + /* + * Circular Buffer Algorithm: + * -------------------------- + * + * Start-off w/ empty buffer of specific size SHM_SIZ + * Start filling it up w/ messages. I use '\0' as separator to break up messages. + * This is also very handy since we can do printf on message. + * + * Once the buffer is full we need to get rid of the first message in buffer and + * insert the new message. (Note: if the message being added is >1 message then + * we will need to "remove" >1 old message from the buffer). The way this is done + * is the following: + * When we reach the end of the buffer we set a mark and start from the beginning. + * Now what about the beginning and end of the buffer? Well we have the "head" + * index/pointer which is the starting point for the messages and we have "tail" + * index/pointer which is the ending point for the messages. When we "display" the + * messages we start from the beginning and continue until we reach "tail". If we + * reach end of buffer, then we just start from the beginning (offset 0). "head" and + * "tail" are actually offsets from the beginning of the buffer. + * + * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide + * a threasafe way of handling shared memory operations. + */ + if ( (buf->tail + l) < buf->size ){ + /* before we append the message we need to check the HEAD so that we won't + overwrite any of the message that we still need and adjust HEAD to point + to the next message! */ + if ( buf->tail < buf->head){ + if ( (buf->tail + l) >= buf->head ){ + /* we need to move the HEAD to point to the next message + * Theoretically we have enough room to add the whole message to the + * buffer, because of the first outer IF statement, so we don't have + * to worry about overflows here! + */ + int k= buf->tail + l - buf->head; /* we need to know how many bytes + we are overwriting to make + enough room */ + char *c=memchr(buf->data+buf->head + k,'\0',buf->size - (buf->head + k)); + if (c != NULL) {/* do a sanity check just in case! */ + buf->head = c - buf->data + 1; /* we need to convert pointer to + offset + skip the '\0' since + we need to point to the beginning + of the next message */ + /* Note: HEAD is only used to "retrieve" messages, it's not used + when writing messages into our buffer */ + }else{ /* show an error message to know we messed up? */ + printf("Weird! Can't find the terminator token??? \n"); + buf->head=0; + } + } + } /* in other cases no overflows have been done yet, so we don't care! */ + + /* we should be ok to append the message now */ + strncpy(buf->data + buf->tail,msg,l); /* append our message */ + buf->tail+=l; /* count full message w/ '\0' terminating char */ + }else{ + /* we need to break up the message and "circle" it around */ + char *c; + int k=buf->tail + l - buf->size; /* count # of bytes we don't fit */ + + /* We need to move HEAD! This is always the case since we are going + * to "circle" the message. + */ + c=memchr(buf->data + k ,'\0', buf->size - k); + + if (c != NULL) /* if we don't have '\0'??? weird!!! */{ + /* move head pointer*/ + buf->head=c-buf->data+1; + + /* now write the first part of the message */ + strncpy(buf->data + buf->tail, msg, l - k - 1); + + /* ALWAYS terminate end of buffer w/ '\0' */ + buf->data[buf->size-1]='\0'; + + /* now write out the rest of the string to the beginning of the buffer */ + strcpy(buf->data, &msg[l-k-1]); + + /* we need to place the TAIL at the end of the message */ + buf->tail = k + 1; + }else{ + printf("Weird! Can't find the terminator token from the beginning??? \n"); + buf->head = buf->tail = 0; /* reset buffer, since it's probably corrupted */ + } + + } + sem_up(s_semid); +} +#endif /* BB_FEATURE_IPC_SYSLOG */ + +/* Note: There is also a function called "message()" in init.c */ +/* Print a message to the log file. */ +static void message (char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +static void message (char *fmt, ...) +{ + int fd; + struct flock fl; + va_list arguments; + + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 1; + +#ifdef BB_FEATURE_IPC_SYSLOG + if ((circular_logging == TRUE) && (buf != NULL)){ + char b[1024]; + va_start (arguments, fmt); + vsnprintf (b, sizeof(b)-1, fmt, arguments); + va_end (arguments); + circ_message(b); + + }else +#endif + if ((fd = device_open (logFilePath, + O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND | + O_NONBLOCK)) >= 0) { + fl.l_type = F_WRLCK; + fcntl (fd, F_SETLKW, &fl); + va_start (arguments, fmt); + vdprintf (fd, fmt, arguments); + va_end (arguments); + fl.l_type = F_UNLCK; + fcntl (fd, F_SETLKW, &fl); + close (fd); + } else { + /* Always send console messages to /dev/console so people will see them. */ + if ((fd = device_open (_PATH_CONSOLE, + O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) { + va_start (arguments, fmt); + vdprintf (fd, fmt, arguments); + va_end (arguments); + close (fd); + } else { + fprintf (stderr, "Bummer, can't print: "); + va_start (arguments, fmt); + vfprintf (stderr, fmt, arguments); + fflush (stderr); + va_end (arguments); + } + } +} + +static void logMessage (int pri, char *msg) +{ + time_t now; + char *timestamp; + static char res[20] = ""; + CODE *c_pri, *c_fac; + + if (pri != 0) { + for (c_fac = facilitynames; + c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++); + for (c_pri = prioritynames; + c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++); + if (c_fac->c_name == NULL || c_pri->c_name == NULL) + snprintf(res, sizeof(res), "<%d>", pri); + else + snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name); + } + + if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' || + msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') { + time(&now); + timestamp = ctime(&now) + 4; + timestamp[15] = '\0'; + } else { + timestamp = msg; + timestamp[15] = '\0'; + msg += 16; + } + + /* todo: supress duplicates */ + +#ifdef BB_FEATURE_REMOTE_LOG + /* send message to remote logger */ + if ( -1 != remotefd){ +static const int IOV_COUNT = 2; + struct iovec iov[IOV_COUNT]; + struct iovec *v = iov; + + memset(&res, 0, sizeof(res)); + snprintf(res, sizeof(res), "<%d>", pri); + v->iov_base = res ; + v->iov_len = strlen(res); + v++; + + v->iov_base = msg; + v->iov_len = strlen(msg); +writev_retry: + if ( -1 == writev(remotefd,iov, IOV_COUNT)){ + if (errno == EINTR) goto writev_retry; + error_msg_and_die("cannot write to remote file handle on" + "%s:%d",RemoteHost,RemotePort); + } + } + if (local_logging == TRUE) +#endif + /* now spew out the message to wherever it is supposed to go */ + message("%s %s %s %s\n", timestamp, LocalHostName, res, msg); + + +} + +static void quit_signal(int sig) +{ + logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting."); + unlink(lfile); +#ifdef BB_FEATURE_IPC_SYSLOG + ipcsyslog_cleanup(); +#endif + + exit(TRUE); +} + +static void domark(int sig) +{ + if (MarkInterval > 0) { + logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --"); + alarm(MarkInterval); + } +} + +/* This must be a #define, since when DODEBUG and BUFFERS_GO_IN_BSS are + * enabled, we otherwise get a "storage size isn't constant error. */ +static int serveConnection (char* tmpbuf, int n_read) +{ + char *p = tmpbuf; + + while (p < tmpbuf + n_read) { + + int pri = (LOG_USER | LOG_NOTICE); + int num_lt = 0; + char line[ MAXLINE + 1 ]; + unsigned char c; + + char *q = line; + + while ( (c = *p) && q < &line[ sizeof (line) - 1 ]) { + if (c == '<' && num_lt == 0) { + /* Parse the magic priority number. */ + num_lt++; + pri = 0; + while (isdigit (*(++p))) { + pri = 10 * pri + (*p - '0'); + } + if (pri & ~(LOG_FACMASK | LOG_PRIMASK)){ + pri = (LOG_USER | LOG_NOTICE); + } + } else if (c == '\n') { + *q++ = ' '; + } else if (iscntrl (c) && (c < 0177)) { + *q++ = '^'; + *q++ = c ^ 0100; + } else { + *q++ = c; + } + p++; + } + *q = '\0'; + p++; + /* Now log it */ + logMessage (pri, line); + } + return n_read; +} + + +#ifdef BB_FEATURE_REMOTE_LOG +static void init_RemoteLog (void) +{ + + struct sockaddr_in remoteaddr; + struct hostent *hostinfo; + int len = sizeof(remoteaddr); + + memset(&remoteaddr, 0, len); + + remotefd = socket(AF_INET, SOCK_DGRAM, 0); + + if (remotefd < 0) { + error_msg_and_die("cannot create socket"); + } + + hostinfo = xgethostbyname(RemoteHost); + + remoteaddr.sin_family = AF_INET; + remoteaddr.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list; + remoteaddr.sin_port = htons(RemotePort); + + /* + Since we are using UDP sockets, connect just sets the default host and port + for future operations + */ + if ( 0 != (connect(remotefd, (struct sockaddr *) &remoteaddr, len))){ + error_msg_and_die("cannot connect to remote host %s:%d", RemoteHost, RemotePort); + } + +} +#endif + +static void doSyslogd (void) __attribute__ ((noreturn)); +static void doSyslogd (void) +{ + struct sockaddr_un sunx; + socklen_t addrLength; + + int sock_fd; + fd_set fds; + + /* Set up signal handlers. */ + signal (SIGINT, quit_signal); + signal (SIGTERM, quit_signal); + signal (SIGQUIT, quit_signal); + signal (SIGHUP, SIG_IGN); + signal (SIGCHLD, SIG_IGN); +#ifdef SIGCLD + signal (SIGCLD, SIG_IGN); +#endif + signal (SIGALRM, domark); + alarm (MarkInterval); + + /* Create the syslog file so realpath() can work. */ + if (realpath (_PATH_LOG, lfile) != NULL) + unlink (lfile); + + memset (&sunx, 0, sizeof (sunx)); + sunx.sun_family = AF_UNIX; + strncpy (sunx.sun_path, lfile, sizeof (sunx.sun_path)); + if ((sock_fd = socket (AF_UNIX, SOCK_DGRAM, 0)) < 0) + perror_msg_and_die ("Couldn't get file descriptor for socket " _PATH_LOG); + + addrLength = sizeof (sunx.sun_family) + strlen (sunx.sun_path); + if (bind(sock_fd, (struct sockaddr *) &sunx, addrLength) < 0) + perror_msg_and_die ("Could not connect to socket " _PATH_LOG); + + if (chmod (lfile, 0666) < 0) + perror_msg_and_die ("Could not set permission on " _PATH_LOG); + + +#ifdef BB_FEATURE_IPC_SYSLOG + if (circular_logging == TRUE ){ + ipcsyslog_init(); + } +#endif + +#ifdef BB_FEATURE_REMOTE_LOG + if (doRemoteLog == TRUE){ + init_RemoteLog(); + } +#endif + + logMessage (LOG_SYSLOG | LOG_INFO, "syslogd started: " BB_BANNER); + + for (;;) { + + FD_ZERO (&fds); + FD_SET (sock_fd, &fds); + + if (select (sock_fd+1, &fds, NULL, NULL, NULL) < 0) { + if (errno == EINTR) { + /* alarm may have happened. */ + continue; + } + perror_msg_and_die ("select error"); + } + + if (FD_ISSET (sock_fd, &fds)) { + int i; + RESERVE_BB_BUFFER(tmpbuf, MAXLINE + 1); + + memset(tmpbuf, '\0', MAXLINE+1); + if ( (i = recv(sock_fd, tmpbuf, MAXLINE, 0)) > 0) { + serveConnection(tmpbuf, i); + } else { + perror_msg_and_die ("UNIX socket error"); + } + RELEASE_BB_BUFFER (tmpbuf); + }/* FD_ISSET() */ + } /* for main loop */ +} + +extern int syslogd_main(int argc, char **argv) +{ + int opt; +#if ! defined(__uClinux__) + int doFork = TRUE; +#endif + + char *p; + + /* do normal option parsing */ + while ((opt = getopt(argc, argv, "m:nO:R:LC")) > 0) { + switch (opt) { + case 'm': + MarkInterval = atoi(optarg) * 60; + break; +#if ! defined(__uClinux__) + case 'n': + doFork = FALSE; + break; +#endif + case 'O': + logFilePath = xstrdup(optarg); + break; +#ifdef BB_FEATURE_REMOTE_LOG + case 'R': + RemoteHost = xstrdup(optarg); + if ( (p = strchr(RemoteHost, ':'))){ + RemotePort = atoi(p+1); + *p = '\0'; + } + doRemoteLog = TRUE; + break; + case 'L': + local_logging = TRUE; + break; +#endif +#ifdef BB_FEATURE_IPC_SYSLOG + case 'C': + circular_logging = TRUE; + break; +#endif + default: + show_usage(); + } + } + +#ifdef BB_FEATURE_REMOTE_LOG + /* If they have not specified remote logging, then log locally */ + if (doRemoteLog == FALSE) + local_logging = TRUE; +#endif + + + /* Store away localhost's name before the fork */ + gethostname(LocalHostName, sizeof(LocalHostName)); + if ((p = strchr(LocalHostName, '.'))) { + *p++ = '\0'; + } + + umask(0); + +#if ! defined(__uClinux__) + if (doFork == TRUE) { + if (daemon(0, 1) < 0) + perror_msg_and_die("daemon"); + } +#endif + doSyslogd(); + + return EXIT_SUCCESS; +} + +/* +Local Variables +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/tail.c b/tail.c new file mode 100644 index 000000000..5e572c582 --- /dev/null +++ b/tail.c @@ -0,0 +1,257 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini tail implementation for busybox + * + * + * 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 + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +static const struct suffix_mult tail_suffixes[] = { + { "b", 512 }, + { "k", 1024 }, + { "m", 1048576 }, + { NULL, 0 } +}; + +static const int BYTES = 0; +static const int LINES = 1; + +static char *tailbuf; +static int taillen; +static int newline; + +static void tailbuf_append(char *buf, int len) +{ + tailbuf = xrealloc(tailbuf, taillen + len); + memcpy(tailbuf + taillen, buf, len); + taillen += len; +} + +static void tailbuf_trunc(void) +{ + char *s; + s = memchr(tailbuf, '\n', taillen); + memmove(tailbuf, s + 1, taillen - ((s + 1) - tailbuf)); + taillen -= (s + 1) - tailbuf; + newline = 0; +} + +int tail_main(int argc, char **argv) +{ + int from_top = 0, units = LINES, count = 10, sleep_period = 1; + int show_headers = 0, hide_headers = 0, follow = 0; + int *fds, nfiles = 0, status = EXIT_SUCCESS, nread, nwrite, seen = 0; + char *s, *start, *end, buf[BUFSIZ]; + int i, opt; + + if (( argc >= 2 ) && ( argv [1][0] == '-' ) && isdigit ( argv [1][1] )) { + count = atoi ( &argv [1][1] ); + optind = 2; + } + + while ((opt = getopt(argc, argv, "c:fhn:q:s:v")) > 0) { + switch (opt) { + case 'f': + follow = 1; + break; +#ifdef BB_FEATURE_FANCY_TAIL + case 'c': + units = BYTES; + /* FALLS THROUGH */ +#endif + case 'n': + count = parse_number(optarg, tail_suffixes); + if (count < 0) + count = -count; + if (optarg[0] == '+') + from_top = 1; + break; +#ifdef BB_FEATURE_FANCY_TAIL + case 'q': + hide_headers = 1; + break; + case 's': + sleep_period = parse_number(optarg, 0); + break; + case 'v': + show_headers = 1; + break; +#endif + default: + show_usage(); + } + } + + /* open all the files */ + fds = (int *)xmalloc(sizeof(int) * (argc - optind + 1)); + if (argc == optind) { + fds[nfiles++] = STDIN_FILENO; + argv[optind] = "standard input"; + } else { + for (i = optind; i < argc; i++) { + if (strcmp(argv[i], "-") == 0) { + fds[nfiles++] = STDIN_FILENO; + argv[i] = "standard input"; + } else if ((fds[nfiles++] = open(argv[i], O_RDONLY)) < 0) { + perror_msg("%s", argv[i]); + status = EXIT_FAILURE; + } + } + } + +#ifdef BB_FEATURE_FANCY_TAIL + /* tail the files */ + if (!from_top && units == BYTES) + tailbuf = xmalloc(count); +#endif + + for (i = 0; i < nfiles; i++) { + if (fds[i] == -1) + continue; + if (!count) { + lseek(fds[i], 0, SEEK_END); + continue; + } + seen = 0; + if (show_headers || (!hide_headers && nfiles > 1)) + printf("%s==> %s <==\n", i == 0 ? "" : "\n", argv[optind + i]); + while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) { + if (from_top) { +#ifdef BB_FEATURE_FANCY_TAIL + if (units == BYTES) { + if (count - 1 <= seen) + nwrite = nread; + else if (count - 1 <= seen + nread) + nwrite = nread + seen - (count - 1); + else + nwrite = 0; + seen += nread; + } else { +#else + { +#endif + if (count - 1 <= seen) + nwrite = nread; + else { + nwrite = 0; + for (s = memchr(buf, '\n', nread); s != NULL; + s = memchr(s+1, '\n', nread - (s + 1 - buf))) { + if (count - 1 <= ++seen) { + nwrite = nread - (s + 1 - buf); + break; + } + } + } + } + if (full_write(STDOUT_FILENO, buf + nread - nwrite, + nwrite) < 0) { + perror_msg("write"); + status = EXIT_FAILURE; + break; + } + } else { +#ifdef BB_FEATURE_FANCY_TAIL + if (units == BYTES) { + if (nread < count) { + memmove(tailbuf, tailbuf + nread, count - nread); + memcpy(tailbuf + count - nread, buf, nread); + } else { + memcpy(tailbuf, buf + nread - count, count); + } + seen += nread; + } else { +#else + { +#endif + for (start = buf, end = memchr(buf, '\n', nread); + end != NULL; start = end+1, + end = memchr(start, '\n', nread - (start - buf))) { + if (newline && count <= seen) + tailbuf_trunc(); + tailbuf_append(start, end - start + 1); + seen++; + newline = 1; + } + if (newline && count <= seen && nread - (start - buf) > 0) + tailbuf_trunc(); + tailbuf_append(start, nread - (start - buf)); + } + } + } + + if (nread < 0) { + perror_msg("read"); + status = EXIT_FAILURE; + } + +#ifdef BB_FEATURE_FANCY_TAIL + if (!from_top && units == BYTES) { + if (count < seen) + seen = count; + if (full_write(STDOUT_FILENO, tailbuf + count - seen, seen) < 0) { + perror_msg("write"); + status = EXIT_FAILURE; + } + } +#endif + + if (!from_top && units == LINES) { + if (full_write(STDOUT_FILENO, tailbuf, taillen) < 0) { + perror_msg("write"); + status = EXIT_FAILURE; + } + } + + taillen = 0; + } + + while (follow) { + sleep(sleep_period); + + for (i = 0; i < nfiles; i++) { + if (fds[i] == -1) + continue; + + if ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0) { + if (show_headers || (!hide_headers && nfiles > 1)) + printf("\n==> %s <==\n", argv[optind + i]); + + do { + full_write(STDOUT_FILENO, buf, nread); + } while ((nread = safe_read(fds[i], buf, sizeof(buf))) > 0); + } + + if (nread < 0) { + perror_msg("read"); + status = EXIT_FAILURE; + } + } + } + + return status; +} diff --git a/tar.c b/tar.c new file mode 100644 index 000000000..60d9cf9f4 --- /dev/null +++ b/tar.c @@ -0,0 +1,1154 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini tar implementation for busybox + * + * Note, that as of BusyBox-0.43, tar has been completely rewritten from the + * ground up. It still has remnents of the old code lying about, but it is + * very different now (i.e., cleaner, less global variables, etc.) + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999-2002 by Erik Andersen + * + * Based in part in the tar implementation in sash + * Copyright (c) 1999 by David I. Bell + * Permission is granted to use, distribute, or modify this source, + * provided that this copyright notice remains intact. + * Permission to distribute sash derived code under the GPL has been granted. + * + * Based in part on the tar implementation from busybox-0.28 + * Copyright (C) 1995 Bruce Perens + * This is free software under the GNU General Public License. + * + * 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 +#include +#include +#include +#include +#include "busybox.h" + +/* Tar file constants */ +#ifndef MAJOR +#define MAJOR(dev) (((dev)>>8)&0xff) +#define MINOR(dev) ((dev)&0xff) +#endif + +enum { NAME_SIZE = 100 }; /* because gcc won't let me use 'static const int' */ + +/* POSIX tar Header Block, from POSIX 1003.1-1990 */ +struct TarHeader +{ + /* byte offset */ + char name[NAME_SIZE]; /* 0-99 */ + char mode[8]; /* 100-107 */ + char uid[8]; /* 108-115 */ + char gid[8]; /* 116-123 */ + char size[12]; /* 124-135 */ + char mtime[12]; /* 136-147 */ + char chksum[8]; /* 148-155 */ + char typeflag; /* 156-156 */ + char linkname[NAME_SIZE]; /* 157-256 */ + char magic[6]; /* 257-262 */ + char version[2]; /* 263-264 */ + char uname[32]; /* 265-296 */ + char gname[32]; /* 297-328 */ + char devmajor[8]; /* 329-336 */ + char devminor[8]; /* 337-344 */ + char prefix[155]; /* 345-499 */ + char padding[12]; /* 500-512 (pad to exactly the TAR_BLOCK_SIZE) */ +}; +typedef struct TarHeader TarHeader; + + +/* A few useful constants */ +#define TAR_MAGIC "ustar" /* ustar and a null */ +#define TAR_VERSION " " /* Be compatable with GNU tar format */ +static const int TAR_MAGIC_LEN = 6; +static const int TAR_VERSION_LEN = 2; +static const int TAR_BLOCK_SIZE = 512; + +/* A nice enum with all the possible tar file content types */ +enum TarFileType +{ + REGTYPE = '0', /* regular file */ + REGTYPE0 = '\0', /* regular file (ancient bug compat)*/ + LNKTYPE = '1', /* hard link */ + SYMTYPE = '2', /* symbolic link */ + CHRTYPE = '3', /* character special */ + BLKTYPE = '4', /* block special */ + DIRTYPE = '5', /* directory */ + FIFOTYPE = '6', /* FIFO special */ + CONTTYPE = '7', /* reserved */ + GNULONGLINK = 'K', /* GNU long (>100 chars) link name */ + GNULONGNAME = 'L', /* GNU long (>100 chars) file name */ +}; +typedef enum TarFileType TarFileType; + +/* This struct ignores magic, non-numeric user name, + * non-numeric group name, and the checksum, since + * these are all ignored by BusyBox tar. */ +struct TarInfo +{ + int tarFd; /* An open file descriptor for reading from the tarball */ + char * name; /* File name */ + mode_t mode; /* Unix mode, including device bits. */ + uid_t uid; /* Numeric UID */ + gid_t gid; /* Numeric GID */ + size_t size; /* Size of file */ + time_t mtime; /* Last-modified time */ + enum TarFileType type; /* Regular, directory, link, etc. */ + char * linkname; /* Name for symbolic and hard links */ + long devmajor; /* Major number for special device */ + long devminor; /* Minor number for special device */ +}; +typedef struct TarInfo TarInfo; + +/* Local procedures to restore files from a tar file. */ +static int readTarFile(int tarFd, int extractFlag, int listFlag, + int tostdoutFlag, int verboseFlag, char** extractList, + char** excludeList); + +#ifdef BB_FEATURE_TAR_CREATE +/* Local procedures to save files into a tar file. */ +static int writeTarFile(const char* tarName, int verboseFlag, char **argv, + char** excludeList); +#endif + +#if defined BB_FEATURE_TAR_EXCLUDE +static struct option longopts[] = { + { "exclude", 1, NULL, 'e' }, + { NULL, 0, NULL, 0 } +}; +#endif + +extern int tar_main(int argc, char **argv) +{ + char** excludeList=NULL; + char** extractList=NULL; + const char *tarName="-"; + const char *cwd=NULL; +#if defined BB_FEATURE_TAR_EXCLUDE + int excludeListSize=0; + FILE *fileList; + char file[256]; +#endif +#if defined BB_FEATURE_TAR_GZIP + FILE *comp_file = NULL; + int unzipFlag = FALSE; +#endif + int listFlag = FALSE; + int extractFlag = FALSE; + int createFlag = FALSE; + int verboseFlag = FALSE; + int tostdoutFlag = FALSE; + int status = FALSE; + int opt; +#if defined BB_FEATURE_TAR_GZIP + pid_t pid; +#endif + + if (argc <= 1) + show_usage(); + + if (argv[1][0] != '-') { + char *tmp = xmalloc(strlen(argv[1]) + 2); + tmp[0] = '-'; + strcpy(tmp + 1, argv[1]); + argv[1] = tmp; + } + + while ( +#ifndef BB_FEATURE_TAR_EXCLUDE + (opt = getopt(argc, argv, "cxtzvOf:pC:")) +#else + (opt = getopt_long(argc, argv, "cxtzvOf:X:pC:", longopts, NULL)) +#endif + > 0) { + switch (opt) { + case 'c': + if (extractFlag == TRUE || listFlag == TRUE) + goto flagError; + createFlag = TRUE; + break; + case 'x': + if (listFlag == TRUE || createFlag == TRUE) + goto flagError; + extractFlag = TRUE; + break; + case 't': + if (extractFlag == TRUE || createFlag == TRUE) + goto flagError; + listFlag = TRUE; + break; +#ifdef BB_FEATURE_TAR_GZIP + case 'z': + unzipFlag = TRUE; + break; +#endif + case 'v': + verboseFlag = TRUE; + break; + case 'O': + tostdoutFlag = TRUE; + break; + case 'f': + if (*tarName != '-') + error_msg_and_die( "Only one 'f' option allowed"); + tarName = optarg; + break; +#if defined BB_FEATURE_TAR_EXCLUDE + case 'e': + excludeList=xrealloc( excludeList, + sizeof(char *) * (excludeListSize+2)); + excludeList[excludeListSize] = optarg; + /* Tack a NULL onto the end of the list */ + excludeList[++excludeListSize] = NULL; + case 'X': + fileList = xfopen(optarg, "r"); + while (fgets(file, sizeof(file), fileList) != NULL) { + excludeList = xrealloc(excludeList, + sizeof(char *) * (excludeListSize+2)); + chomp(file); + excludeList[excludeListSize] = xstrdup(file); + /* Tack a NULL onto the end of the list */ + excludeList[++excludeListSize] = NULL; + } + fclose(fileList); + break; +#endif + case 'p': + break; + case 'C': + cwd = xgetcwd((char *)cwd); + if (chdir(optarg)) { + printf("cd: %s: %s\n", optarg, strerror(errno)); + return EXIT_FAILURE; + } + break; + default: + show_usage(); + } + } + + /* + * Do the correct type of action supplying the rest of the + * command line arguments as the list of files to process. + */ + if (createFlag == TRUE) { +#ifndef BB_FEATURE_TAR_CREATE + error_msg_and_die( "This version of tar was not compiled with tar creation support."); +#else +#ifdef BB_FEATURE_TAR_GZIP + if (unzipFlag==TRUE) + error_msg_and_die("Creation of compressed not internally support by tar, pipe to busybox gunzip"); +#endif + status = writeTarFile(tarName, verboseFlag, argv + optind, excludeList); +#endif + } + if (listFlag == TRUE || extractFlag == TRUE) { + int tarFd; + if (argv[optind]) + extractList = argv + optind; + /* Open the tar file for reading. */ + if (!strcmp(tarName, "-")) + tarFd = fileno(stdin); + else + tarFd = open(tarName, O_RDONLY); + if (tarFd < 0) + perror_msg_and_die("Error opening '%s'", tarName); + +#ifdef BB_FEATURE_TAR_GZIP + /* unzip tarFd in a seperate process */ + if (unzipFlag == TRUE) { + comp_file = fdopen(tarFd, "r"); + + /* set the buffer size */ + setvbuf(comp_file, NULL, _IOFBF, 0x8000); + + if ((tarFd = fileno(gz_open(comp_file, &pid))) == EXIT_FAILURE) { + error_msg_and_die("Couldnt unzip file"); + } + } +#endif + status = readTarFile(tarFd, extractFlag, listFlag, tostdoutFlag, + verboseFlag, extractList, excludeList); + close(tarFd); +#ifdef BB_FEATURE_TAR_GZIP + if (unzipFlag == TRUE) { + gz_close(pid); + fclose(comp_file); + } +#endif + } + + if (cwd) + chdir(cwd); + if (status == TRUE) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; + + flagError: + error_msg_and_die( "Exactly one of 'c', 'x' or 't' must be specified"); +} + +static void +fixUpPermissions(TarInfo *header) +{ + struct utimbuf t; + /* Now set permissions etc. for the new file */ + chown(header->name, header->uid, header->gid); + chmod(header->name, header->mode); + /* Reset the time */ + t.actime = time(0); + t.modtime = header->mtime; + utime(header->name, &t); +} + +static int +tarExtractRegularFile(TarInfo *header, int extractFlag, int tostdoutFlag) +{ + size_t writeSize; + size_t readSize; + size_t actualWriteSz; + char buffer[20 * TAR_BLOCK_SIZE]; + size_t size = header->size; + int outFd=fileno(stdout); + + /* Open the file to be written, if a file is supposed to be written */ + if (extractFlag==TRUE && tostdoutFlag==FALSE) { + /* Create the path to the file, just in case it isn't there... + * This should not screw up path permissions or anything. */ + char *buf, *dir; + buf = xstrdup (header->name); + dir = dirname (buf); + make_directory (dir, -1, FILEUTILS_RECUR); + free (buf); + if ((outFd=open(header->name, O_CREAT|O_TRUNC|O_WRONLY, + header->mode & ~S_IFMT)) < 0) { + error_msg(io_error, header->name, strerror(errno)); + return( FALSE); + } + } + + /* Write out the file, if we are supposed to be doing that */ + while ( size > 0 ) { + actualWriteSz=0; + if ( size > sizeof(buffer) ) + writeSize = readSize = sizeof(buffer); + else { + int mod = size % TAR_BLOCK_SIZE; + if ( mod != 0 ) + readSize = size + (TAR_BLOCK_SIZE - mod); + else + readSize = size; + writeSize = size; + } + if ( (readSize = full_read(header->tarFd, buffer, readSize)) <= 0 ) { + /* Tarball seems to have a problem */ + error_msg("Unexpected EOF in archive"); + return( FALSE); + } + if ( readSize < writeSize ) + writeSize = readSize; + + /* Write out the file, if we are supposed to be doing that */ + if (extractFlag==TRUE) { + + if ((actualWriteSz=full_write(outFd, buffer, writeSize)) != writeSize ) { + /* Output file seems to have a problem */ + error_msg(io_error, header->name, strerror(errno)); + return( FALSE); + } + } else { + actualWriteSz=writeSize; + } + + size -= actualWriteSz; + } + + /* Now we are done writing the file out, so try + * and fix up the permissions and whatnot */ + if (extractFlag==TRUE && tostdoutFlag==FALSE) { + close(outFd); + fixUpPermissions(header); + } + return( TRUE); +} + +static int +tarExtractDirectory(TarInfo *header, int extractFlag, int tostdoutFlag) +{ + if (extractFlag==FALSE || tostdoutFlag==TRUE) + return( TRUE); + + if (make_directory(header->name, header->mode, FILEUTILS_RECUR) < 0) + return( FALSE); + + fixUpPermissions(header); + return( TRUE); +} + +static int +tarExtractHardLink(TarInfo *header, int extractFlag, int tostdoutFlag) +{ + if (extractFlag==FALSE || tostdoutFlag==TRUE) + return( TRUE); + + if (link(header->linkname, header->name) < 0) { + perror_msg("%s: Cannot create hard link to '%s'", header->name, + header->linkname); + return( FALSE); + } + + /* Now set permissions etc. for the new directory */ + fixUpPermissions(header); + return( TRUE); +} + +static int +tarExtractSymLink(TarInfo *header, int extractFlag, int tostdoutFlag) +{ + if (extractFlag==FALSE || tostdoutFlag==TRUE) + return( TRUE); + +#ifdef S_ISLNK + if (symlink(header->linkname, header->name) < 0) { + perror_msg("%s: Cannot create symlink to '%s'", header->name, + header->linkname); + return( FALSE); + } + /* Try to change ownership of the symlink. + * If libs doesn't support that, don't bother. + * Changing the pointed-to-file is the Wrong Thing(tm). + */ +#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) + lchown(header->name, header->uid, header->gid); +#endif + + /* Do not change permissions or date on symlink, + * since it changes the pointed to file instead. duh. */ +#else + error_msg("%s: Cannot create symlink to '%s': %s", + header->name, header->linkname, + "symlinks not supported"); +#endif + return( TRUE); +} + +static int +tarExtractSpecial(TarInfo *header, int extractFlag, int tostdoutFlag) +{ + if (extractFlag==FALSE || tostdoutFlag==TRUE) + return( TRUE); + + if (S_ISCHR(header->mode) || S_ISBLK(header->mode) || S_ISSOCK(header->mode)) { + if (mknod(header->name, header->mode, makedev(header->devmajor, header->devminor)) < 0) { + perror_msg("%s: Cannot mknod", header->name); + return( FALSE); + } + } else if (S_ISFIFO(header->mode)) { + if (mkfifo(header->name, header->mode) < 0) { + perror_msg("%s: Cannot mkfifo", header->name); + return( FALSE); + } + } + + /* Now set permissions etc. for the new directory */ + fixUpPermissions(header); + return( TRUE); +} + +/* Parse the tar header and fill in the nice struct with the details */ +static int +readTarHeader(struct TarHeader *rawHeader, struct TarInfo *header) +{ + int i; + long chksum, sum=0; + unsigned char *s = (unsigned char *)rawHeader; + + header->name = rawHeader->name; + /* Check for and relativify any absolute paths */ + if ( *(header->name) == '/' ) { + static int alreadyWarned=FALSE; + + while (*(header->name) == '/') + header->name++; + + if (alreadyWarned == FALSE) { + error_msg("Removing leading '/' from member names"); + alreadyWarned = TRUE; + } + } + + header->mode = strtol(rawHeader->mode, NULL, 8); + header->uid = strtol(rawHeader->uid, NULL, 8); + header->gid = strtol(rawHeader->gid, NULL, 8); + header->size = strtol(rawHeader->size, NULL, 8); + header->mtime = strtol(rawHeader->mtime, NULL, 8); + chksum = strtol(rawHeader->chksum, NULL, 8); + header->type = rawHeader->typeflag; + header->linkname = rawHeader->linkname; + header->devmajor = strtol(rawHeader->devmajor, NULL, 8); + header->devminor = strtol(rawHeader->devminor, NULL, 8); + + /* Check the checksum */ + for (i = sizeof(*rawHeader); i-- != 0;) { + sum += *s++; + } + /* Remove the effects of the checksum field (replace + * with blanks for the purposes of the checksum) */ + s = rawHeader->chksum; + for (i = sizeof(rawHeader->chksum) ; i-- != 0;) { + sum -= *s++; + } + sum += ' ' * sizeof(rawHeader->chksum); + if (sum == chksum ) + return ( TRUE); + return( FALSE); +} + +#if defined BB_FEATURE_TAR_EXCLUDE +static int exclude_file(char **excluded_files, const char *file) +{ + int i; + + if (excluded_files == NULL) + return 0; + + for (i = 0; excluded_files[i] != NULL; i++) { + if (excluded_files[i][0] == '/') { + if (fnmatch(excluded_files[i], file, + FNM_PATHNAME | FNM_LEADING_DIR) == 0) + return 1; + } else { + const char *p; + + for (p = file; p[0] != '\0'; p++) { + if ((p == file || p[-1] == '/') && p[0] != '/' && + fnmatch(excluded_files[i], p, + FNM_PATHNAME | FNM_LEADING_DIR) == 0) + return 1; + } + } + } + + return 0; +} +#endif + +static int extract_file(char **extract_files, const char *file) +{ + int i; + + if (extract_files == NULL) + return 1; + + for (i = 0; extract_files[i] != NULL; i++) { + if (fnmatch(extract_files[i], file, FNM_LEADING_DIR) == 0) + return 1; + } + + return 0; +} + +/* + * Read a tar file and extract or list the specified files within it. + * If the list is empty than all files are extracted or listed. + */ +static int readTarFile(int tarFd, int extractFlag, int listFlag, + int tostdoutFlag, int verboseFlag, char** extractList, + char** excludeList) +{ + int status; + int errorFlag=FALSE; + int skipNextHeaderFlag=FALSE; + TarHeader rawHeader; + TarInfo header; + + /* Read the tar file, and iterate over it one file at a time */ + while ( (status = full_read(tarFd, (char*)&rawHeader, TAR_BLOCK_SIZE)) == TAR_BLOCK_SIZE ) { + + /* Try to read the header */ + if ( readTarHeader(&rawHeader, &header) == FALSE ) { + if ( *(header.name) == '\0' ) { + goto endgame; + } else { + errorFlag=TRUE; + error_msg("Bad tar header, skipping"); + continue; + } + } + if ( *(header.name) == '\0' ) + continue; + header.tarFd = tarFd; + + /* Skip funky extra GNU headers that precede long files */ + if ( (header.type == GNULONGNAME) || (header.type == GNULONGLINK) ) { + skipNextHeaderFlag=TRUE; + if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) + errorFlag = TRUE; + continue; + } + if ( skipNextHeaderFlag == TRUE ) { + skipNextHeaderFlag=FALSE; + error_msg(name_longer_than_foo, NAME_SIZE); + if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) + errorFlag = TRUE; + continue; + } + +#if defined BB_FEATURE_TAR_EXCLUDE + if (exclude_file(excludeList, header.name)) { + /* There are not the droids you're looking for, move along */ + /* If it is a regular file, pretend to extract it with + * the extractFlag set to FALSE, so the junk in the tarball + * is properly skipped over */ + if ( header.type==REGTYPE || header.type==REGTYPE0 ) { + if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) + errorFlag = TRUE; + } + continue; + } +#endif + + if (!extract_file(extractList, header.name)) { + /* There are not the droids you're looking for, move along */ + /* If it is a regular file, pretend to extract it with + * the extractFlag set to FALSE, so the junk in the tarball + * is properly skipped over */ + if ( header.type==REGTYPE || header.type==REGTYPE0 ) { + if (tarExtractRegularFile(&header, FALSE, FALSE) == FALSE) + errorFlag = TRUE; + } + continue; + } + + if (listFlag == TRUE) { + /* Special treatment if the list (-t) flag is on */ + if (verboseFlag == TRUE) { + int len, len1; + char buf[35]; + struct tm *tm = localtime (&(header.mtime)); + + len=printf("%s ", mode_string(header.mode)); + my_getpwuid(buf, header.uid); + if (! *buf) + len+=printf("%d", header.uid); + else + len+=printf("%s", buf); + my_getgrgid(buf, header.gid); + if (! *buf) + len+=printf("/%-d ", header.gid); + else + len+=printf("/%-s ", buf); + + if (header.type==CHRTYPE || header.type==BLKTYPE) { + len1=snprintf(buf, sizeof(buf), "%ld,%-ld ", + header.devmajor, header.devminor); + } else { + len1=snprintf(buf, sizeof(buf), "%lu ", (long)header.size); + } + /* Jump through some hoops to make the columns match up */ + for(;(len+len1)<31;len++) + printf(" "); + printf(buf); + + /* Use ISO 8610 time format */ + if (tm) { + printf ("%04d-%02d-%02d %02d:%02d:%02d ", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + } + } + printf("%s", header.name); + if (verboseFlag == TRUE) { + if (header.type==LNKTYPE) /* If this is a link, say so */ + printf(" link to %s", header.linkname); + else if (header.type==SYMTYPE) + printf(" -> %s", header.linkname); + } + printf("\n"); + } + + /* List contents if we are supposed to do that */ + if (verboseFlag == TRUE && extractFlag == TRUE) { + /* Now the normal listing */ + FILE *vbFd = stdout; + if (tostdoutFlag == TRUE) // If the archive goes to stdout, verbose to stderr + vbFd = stderr; + fprintf(vbFd, "%s\n", header.name); + } + + /* Remove files if we would overwrite them */ + if (extractFlag == TRUE && tostdoutFlag == FALSE) + unlink(header.name); + + /* If we got here, we can be certain we have a legitimate + * header to work with. So work with it. */ + switch ( header.type ) { + case REGTYPE: + case REGTYPE0: + /* If the name ends in a '/' then assume it is + * supposed to be a directory, and fall through */ + if (!last_char_is(header.name,'/')) { + if (tarExtractRegularFile(&header, extractFlag, tostdoutFlag)==FALSE) + errorFlag=TRUE; + break; + } + case DIRTYPE: + if (tarExtractDirectory( &header, extractFlag, tostdoutFlag)==FALSE) + errorFlag=TRUE; + break; + case LNKTYPE: + if (tarExtractHardLink( &header, extractFlag, tostdoutFlag)==FALSE) + errorFlag=TRUE; + break; + case SYMTYPE: + if (tarExtractSymLink( &header, extractFlag, tostdoutFlag)==FALSE) + errorFlag=TRUE; + break; + case CHRTYPE: + case BLKTYPE: + case FIFOTYPE: + if (tarExtractSpecial( &header, extractFlag, tostdoutFlag)==FALSE) + errorFlag=TRUE; + break; +#if 0 + /* Handled earlier */ + case GNULONGNAME: + case GNULONGLINK: + skipNextHeaderFlag=TRUE; + break; +#endif + default: + error_msg("Unknown file type '%c' in tar file", header.type); + close( tarFd); + return( FALSE); + } + } + close(tarFd); + if (status > 0) { + /* Bummer - we read a partial header */ + perror_msg("Error reading tar file"); + return ( FALSE); + } + else if (errorFlag==TRUE) { + error_msg( "Error exit delayed from previous errors"); + return( FALSE); + } else + return( status); + + /* Stuff to do when we are done */ +endgame: + close( tarFd); + if ( *(header.name) == '\0' ) { + if (errorFlag==TRUE) + error_msg( "Error exit delayed from previous errors"); + else + return( TRUE); + } + return( FALSE); +} + + +#ifdef BB_FEATURE_TAR_CREATE + +/* +** writeTarFile(), writeFileToTarball(), and writeTarHeader() are +** the only functions that deal with the HardLinkInfo structure. +** Even these functions use the xxxHardLinkInfo() functions. +*/ +typedef struct HardLinkInfo HardLinkInfo; +struct HardLinkInfo +{ + HardLinkInfo *next; /* Next entry in list */ + dev_t dev; /* Device number */ + ino_t ino; /* Inode number */ + short linkCount; /* (Hard) Link Count */ + char name[1]; /* Start of filename (must be last) */ +}; + +/* Some info to be carried along when creating a new tarball */ +struct TarBallInfo +{ + char* fileName; /* File name of the tarball */ + int tarFd; /* Open-for-write file descriptor + for the tarball */ + struct stat statBuf; /* Stat info for the tarball, letting + us know the inode and device that the + tarball lives, so we can avoid trying + to include the tarball into itself */ + int verboseFlag; /* Whether to print extra stuff or not */ + char** excludeList; /* List of files to not include */ + HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */ + HardLinkInfo *hlInfo; /* Hard Link Info for the current file */ +}; +typedef struct TarBallInfo TarBallInfo; + + +/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */ +static void +addHardLinkInfo (HardLinkInfo **hlInfoHeadPtr, dev_t dev, ino_t ino, + short linkCount, const char *name) +{ + /* Note: hlInfoHeadPtr can never be NULL! */ + HardLinkInfo *hlInfo; + + hlInfo = (HardLinkInfo *)xmalloc(sizeof(HardLinkInfo)+strlen(name)+1); + if (hlInfo) { + hlInfo->next = *hlInfoHeadPtr; + *hlInfoHeadPtr = hlInfo; + hlInfo->dev = dev; + hlInfo->ino = ino; + hlInfo->linkCount = linkCount; + strcpy(hlInfo->name, name); + } + return; +} + +static void +freeHardLinkInfo (HardLinkInfo **hlInfoHeadPtr) +{ + HardLinkInfo *hlInfo = NULL; + HardLinkInfo *hlInfoNext = NULL; + + if (hlInfoHeadPtr) { + hlInfo = *hlInfoHeadPtr; + while (hlInfo) { + hlInfoNext = hlInfo->next; + free(hlInfo); + hlInfo = hlInfoNext; + } + *hlInfoHeadPtr = NULL; + } + return; +} + +/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */ +static HardLinkInfo * +findHardLinkInfo (HardLinkInfo *hlInfo, dev_t dev, ino_t ino) +{ + while(hlInfo) { + if ((ino == hlInfo->ino) && (dev == hlInfo->dev)) + break; + hlInfo = hlInfo->next; + } + return(hlInfo); +} + +/* Put an octal string into the specified buffer. + * The number is zero and space padded and possibly null padded. + * Returns TRUE if successful. */ +static int putOctal (char *cp, int len, long value) +{ + int tempLength; + char tempBuffer[32]; + char *tempString = tempBuffer; + + /* Create a string of the specified length with an initial space, + * leading zeroes and the octal number, and a trailing null. */ + sprintf (tempString, "%0*lo", len - 1, value); + + /* If the string is too large, suppress the leading space. */ + tempLength = strlen (tempString) + 1; + if (tempLength > len) { + tempLength--; + tempString++; + } + + /* If the string is still too large, suppress the trailing null. */ + if (tempLength > len) + tempLength--; + + /* If the string is still too large, fail. */ + if (tempLength > len) + return FALSE; + + /* Copy the string to the field. */ + memcpy (cp, tempString, len); + + return TRUE; +} + +/* Write out a tar header for the specified file/directory/whatever */ +static int +writeTarHeader(struct TarBallInfo *tbInfo, const char *header_name, + const char *real_name, struct stat *statbuf) +{ + long chksum=0; + struct TarHeader header; + const unsigned char *cp = (const unsigned char *) &header; + ssize_t size = sizeof(struct TarHeader); + + memset( &header, 0, size); + + strncpy(header.name, header_name, sizeof(header.name)); + + putOctal(header.mode, sizeof(header.mode), statbuf->st_mode); + putOctal(header.uid, sizeof(header.uid), statbuf->st_uid); + putOctal(header.gid, sizeof(header.gid), statbuf->st_gid); + putOctal(header.size, sizeof(header.size), 0); /* Regular file size is handled later */ + putOctal(header.mtime, sizeof(header.mtime), statbuf->st_mtime); + strncpy(header.magic, TAR_MAGIC TAR_VERSION, + TAR_MAGIC_LEN + TAR_VERSION_LEN ); + + /* Enter the user and group names (default to root if it fails) */ + my_getpwuid(header.uname, statbuf->st_uid); + if (! *header.uname) + strcpy(header.uname, "root"); + my_getgrgid(header.gname, statbuf->st_gid); + if (! *header.uname) + strcpy(header.uname, "root"); + + if (tbInfo->hlInfo) { + /* This is a hard link */ + header.typeflag = LNKTYPE; + strncpy(header.linkname, tbInfo->hlInfo->name, sizeof(header.linkname)); + } else if (S_ISLNK(statbuf->st_mode)) { + char *lpath = xreadlink(real_name); + if (!lpath) /* Already printed err msg inside xreadlink() */ + return ( FALSE); + header.typeflag = SYMTYPE; + strncpy(header.linkname, lpath, sizeof(header.linkname)); + free(lpath); + } else if (S_ISDIR(statbuf->st_mode)) { + header.typeflag = DIRTYPE; + strncat(header.name, "/", sizeof(header.name)); + } else if (S_ISCHR(statbuf->st_mode)) { + header.typeflag = CHRTYPE; + putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev)); + putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev)); + } else if (S_ISBLK(statbuf->st_mode)) { + header.typeflag = BLKTYPE; + putOctal(header.devmajor, sizeof(header.devmajor), MAJOR(statbuf->st_rdev)); + putOctal(header.devminor, sizeof(header.devminor), MINOR(statbuf->st_rdev)); + } else if (S_ISFIFO(statbuf->st_mode)) { + header.typeflag = FIFOTYPE; + } else if (S_ISREG(statbuf->st_mode)) { + header.typeflag = REGTYPE; + putOctal(header.size, sizeof(header.size), statbuf->st_size); + } else { + error_msg("%s: Unknown file type", real_name); + return ( FALSE); + } + + /* Calculate and store the checksum (i.e., the sum of all of the bytes of + * the header). The checksum field must be filled with blanks for the + * calculation. The checksum field is formatted differently from the + * other fields: it has [6] digits, a null, then a space -- rather than + * digits, followed by a null like the other fields... */ + memset(header.chksum, ' ', sizeof(header.chksum)); + cp = (const unsigned char *) &header; + while (size-- > 0) + chksum += *cp++; + putOctal(header.chksum, 7, chksum); + + /* Now write the header out to disk */ + if ((size=full_write(tbInfo->tarFd, (char*)&header, sizeof(struct TarHeader))) < 0) { + error_msg(io_error, real_name, strerror(errno)); + return ( FALSE); + } + /* Pad the header up to the tar block size */ + for (; sizetarFd, "\0", 1); + } + /* Now do the verbose thing (or not) */ + if (tbInfo->verboseFlag==TRUE) { + FILE *vbFd = stdout; + if (tbInfo->tarFd == fileno(stdout)) // If the archive goes to stdout, verbose to stderr + vbFd = stderr; + fprintf(vbFd, "%s\n", header.name); + } + + return ( TRUE); +} + + +static int writeFileToTarball(const char *fileName, struct stat *statbuf, void* userData) +{ + struct TarBallInfo *tbInfo = (struct TarBallInfo *)userData; + const char *header_name; + + /* + ** Check to see if we are dealing with a hard link. + ** If so - + ** Treat the first occurance of a given dev/inode as a file while + ** treating any additional occurances as hard links. This is done + ** by adding the file information to the HardLinkInfo linked list. + */ + tbInfo->hlInfo = NULL; + if (statbuf->st_nlink > 1) { + tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf->st_dev, + statbuf->st_ino); + if (tbInfo->hlInfo == NULL) + addHardLinkInfo (&tbInfo->hlInfoHead, statbuf->st_dev, + statbuf->st_ino, statbuf->st_nlink, fileName); + } + + /* It is against the rules to archive a socket */ + if (S_ISSOCK(statbuf->st_mode)) { + error_msg("%s: socket ignored", fileName); + return( TRUE); + } + + /* It is a bad idea to store the archive we are in the process of creating, + * so check the device and inode to be sure that this particular file isn't + * the new tarball */ + if (tbInfo->statBuf.st_dev == statbuf->st_dev && + tbInfo->statBuf.st_ino == statbuf->st_ino) { + error_msg("%s: file is the archive; skipping", fileName); + return( TRUE); + } + + header_name = fileName; + while (header_name[0] == '/') { + static int alreadyWarned=FALSE; + if (alreadyWarned==FALSE) { + error_msg("Removing leading '/' from member names"); + alreadyWarned=TRUE; + } + header_name++; + } + + if (strlen(fileName) >= NAME_SIZE) { + error_msg(name_longer_than_foo, NAME_SIZE); + return ( TRUE); + } + + if (header_name[0] == '\0') + return TRUE; + +#if defined BB_FEATURE_TAR_EXCLUDE + if (exclude_file(tbInfo->excludeList, header_name)) { + return SKIP; + } +#endif + + if (writeTarHeader(tbInfo, header_name, fileName, statbuf)==FALSE) { + return( FALSE); + } + + /* Now, if the file is a regular file, copy it out to the tarball */ + if ((tbInfo->hlInfo == NULL) + && (S_ISREG(statbuf->st_mode))) { + int inputFileFd; + char buffer[BUFSIZ]; + ssize_t size=0, readSize=0; + + /* open the file we want to archive, and make sure all is well */ + if ((inputFileFd = open(fileName, O_RDONLY)) < 0) { + error_msg("%s: Cannot open: %s", fileName, strerror(errno)); + return( FALSE); + } + + /* write the file to the archive */ + while ( (size = full_read(inputFileFd, buffer, sizeof(buffer))) > 0 ) { + if (full_write(tbInfo->tarFd, buffer, size) != size ) { + /* Output file seems to have a problem */ + error_msg(io_error, fileName, strerror(errno)); + return( FALSE); + } + readSize+=size; + } + if (size == -1) { + error_msg(io_error, fileName, strerror(errno)); + return( FALSE); + } + /* Pad the file up to the tar block size */ + for (; (readSize%TAR_BLOCK_SIZE) != 0; readSize++) { + write(tbInfo->tarFd, "\0", 1); + } + close( inputFileFd); + } + + return( TRUE); +} + +static int writeTarFile(const char* tarName, int verboseFlag, char **argv, + char** excludeList) +{ + int tarFd=-1; + int errorFlag=FALSE; + ssize_t size; + struct TarBallInfo tbInfo; + tbInfo.verboseFlag = verboseFlag; + tbInfo.hlInfoHead = NULL; + + /* Make sure there is at least one file to tar up. */ + if (*argv == NULL) + error_msg_and_die("Cowardly refusing to create an empty archive"); + + /* Open the tar file for writing. */ + if (!strcmp(tarName, "-")) + tbInfo.tarFd = fileno(stdout); + else + tbInfo.tarFd = open (tarName, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (tbInfo.tarFd < 0) { + perror_msg( "Error opening '%s'", tarName); + freeHardLinkInfo(&tbInfo.hlInfoHead); + return ( FALSE); + } + tbInfo.excludeList=excludeList; + /* Store the stat info for the tarball's file, so + * can avoid including the tarball into itself.... */ + if (fstat(tbInfo.tarFd, &tbInfo.statBuf) < 0) + error_msg_and_die(io_error, tarName, strerror(errno)); + + /* Read the directory/files and iterate over them one at a time */ + while (*argv != NULL) { + if (recursive_action(*argv++, TRUE, FALSE, FALSE, + writeFileToTarball, writeFileToTarball, + (void*) &tbInfo) == FALSE) { + errorFlag = TRUE; + } + } + /* Write two empty blocks to the end of the archive */ + for (size=0; size<(2*TAR_BLOCK_SIZE); size++) { + write(tbInfo.tarFd, "\0", 1); + } + + /* To be pedantically correct, we would check if the tarball + * is smaller than 20 tar blocks, and pad it if it was smaller, + * but that isn't necessary for GNU tar interoperability, and + * so is considered a waste of space */ + + /* Hang up the tools, close up shop, head home */ + close(tarFd); + if (errorFlag == TRUE) { + error_msg("Error exit delayed from previous errors"); + freeHardLinkInfo(&tbInfo.hlInfoHead); + return(FALSE); + } + freeHardLinkInfo(&tbInfo.hlInfoHead); + return( TRUE); +} + + +#endif + diff --git a/tee.c b/tee.c new file mode 100644 index 000000000..0533dbd65 --- /dev/null +++ b/tee.c @@ -0,0 +1,67 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini tee implementation for busybox + * + * Copyright (C) 1999,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 + * + */ + +#include "busybox.h" +#include +#include + +int +tee_main(int argc, char **argv) +{ + char *mode = "w"; + int c, i, status = 0, nfiles = 0; + FILE **files; + + while ((c = getopt(argc, argv, "a")) != EOF) { + switch (c) { + case 'a': + mode = "a"; + break; + default: + show_usage(); + } + } + + files = (FILE **)xmalloc(sizeof(FILE *) * (argc - optind + 1)); + files[nfiles++] = stdout; + while (optind < argc) { + if ((files[nfiles++] = fopen(argv[optind++], mode)) == NULL) { + nfiles--; + perror_msg("%s", argv[optind-1]); + status = 1; + } + } + + while ((c = getchar()) != EOF) + for (i = 0; i < nfiles; i++) + putc(c, files[i]); + + return status; +} + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/telnet.c b/telnet.c new file mode 100644 index 000000000..cacb91fcb --- /dev/null +++ b/telnet.c @@ -0,0 +1,755 @@ +/* vi: set sw=4 ts=4: */ +/* + * telnet implementation for busybox + * + * Author: Tomi Ollila + * Copyright (C) 1994-2000 by Tomi Ollila + * + * Created: Thu Apr 7 13:29:41 1994 too + * Last modified: Fri Jun 9 14:34:24 2000 too + * + * 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 + * + * HISTORY + * Revision 3.1 1994/04/17 11:31:54 too + * initial revision + * Modified 2000/06/13 for inclusion in BusyBox by Erik Andersen + * Modified 2001/05/07 to add ability to pass TTYPE to remote host by Jim McQuillan + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +#ifdef BB_FEATURE_AUTOWIDTH +# include +#endif + +#if 0 +static const int DOTRACE = 1; +#endif + +#ifdef DOTRACE +#include /* for inet_ntoa()... */ +#define TRACE(x, y) do { if (x) printf y; } while (0) +#else +#define TRACE(x, y) +#endif + +#if 0 +#define USE_POLL +#include +#else +#include +#endif + +#define DATABUFSIZE 128 +#define IACBUFSIZE 128 + +static const int CHM_TRY = 0; +static const int CHM_ON = 1; +static const int CHM_OFF = 2; + +static const int UF_ECHO = 0x01; +static const int UF_SGA = 0x02; + +enum { + TS_0 = 1, + TS_IAC = 2, + TS_OPT = 3, + TS_SUB1 = 4, + TS_SUB2 = 5, +}; + +#define WriteCS(fd, str) write(fd, str, sizeof str -1) + +typedef unsigned char byte; + +/* use globals to reduce size ??? */ /* test this hypothesis later */ +static struct Globalvars { + int netfd; /* console fd:s are 0 and 1 (and 2) */ + /* same buffer used both for network and console read/write */ + char buf[DATABUFSIZE]; /* allocating so static size is smaller */ + byte telstate; /* telnet negotiation state from network input */ + byte telwish; /* DO, DONT, WILL, WONT */ + byte charmode; + byte telflags; + byte gotsig; + /* buffer to handle telnet negotiations */ + char iacbuf[IACBUFSIZE]; + short iaclen; /* could even use byte */ + struct termios termios_def; + struct termios termios_raw; +} G; + +#define xUSE_GLOBALVAR_PTR /* xUSE... -> don't use :D (makes smaller code) */ + +#ifdef USE_GLOBALVAR_PTR +struct Globalvars * Gptr; +#define G (*Gptr) +#else +static struct Globalvars G; +#endif + +static inline void iacflush() +{ + write(G.netfd, G.iacbuf, G.iaclen); + G.iaclen = 0; +} + +/* Function prototypes */ +static int getport(char * p); +static struct in_addr getserver(char * p); +static int create_socket(); +static void setup_sockaddr_in(struct sockaddr_in * addr, int port); +static int remote_connect(struct in_addr addr, int port); +static void rawmode(); +static void cookmode(); +static void do_linemode(); +static void will_charmode(); +static void telopt(byte c); +static int subneg(byte c); +#if 0 +static int local_bind(int port); +#endif + +/* Some globals */ +static int one = 1; + +#ifdef BB_FEATURE_TELNET_TTYPE +static char *ttype; +#endif + +#ifdef BB_FEATURE_AUTOWIDTH +static int win_width, win_height; +#endif + +static void doexit(int ev) +{ + cookmode(); + exit(ev); +} + +static void conescape() +{ + char b; + + if (G.gotsig) /* came from line mode... go raw */ + rawmode(); + + WriteCS(1, "\r\nConsole escape. Commands are:\r\n\n" + " l go to line mode\r\n" + " c go to character mode\r\n" + " z suspend telnet\r\n" + " e exit telnet\r\n"); + + if (read(0, &b, 1) <= 0) + doexit(1); + + switch (b) + { + case 'l': + if (!G.gotsig) + { + do_linemode(); + goto rrturn; + } + break; + case 'c': + if (G.gotsig) + { + will_charmode(); + goto rrturn; + } + break; + case 'z': + cookmode(); + kill(0, SIGTSTP); + rawmode(); + break; + case 'e': + doexit(0); + } + + WriteCS(1, "continuing...\r\n"); + + if (G.gotsig) + cookmode(); + + rrturn: + G.gotsig = 0; + +} +static void handlenetoutput(int len) +{ + /* here we could do smart tricks how to handle 0xFF:s in output + * stream like writing twice every sequence of FF:s (thus doing + * many write()s. But I think interactive telnet application does + * not need to be 100% 8-bit clean, so changing every 0xff:s to + * 0x7f:s + * + * 2002-mar-21, Przemyslaw Czerpak (druzus@polbox.com) + * I don't agree. + * first - I cannot use programs like sz/rz + * second - the 0x0D is sent as one character and if the next + * char is 0x0A then it's eaten by a server side. + * third - whay doy you have to make 'many write()s'? + * I don't understand. + * So I implemented it. It's realy useful for me. I hope that + * others people will find it interesting to. + */ + + int i, j; + byte * p = G.buf; + byte outbuf[4*DATABUFSIZE]; + + for (i = len, j = 0; i > 0; i--, p++) + { + if (*p == 0x1d) + { + conescape(); + return; + } + outbuf[j++] = *p; + if (*p == 0xff) + outbuf[j++] = 0xff; + else if (*p == 0x0d) + outbuf[j++] = 0x00; + } + if (j > 0 ) + write(G.netfd, outbuf, j); +} + + +static void handlenetinput(int len) +{ + int i; + int cstart = 0; + + for (i = 0; i < len; i++) + { + byte c = G.buf[i]; + + if (G.telstate == 0) /* most of the time state == 0 */ + { + if (c == IAC) + { + cstart = i; + G.telstate = TS_IAC; + } + } + else + switch (G.telstate) + { + case TS_0: + if (c == IAC) + G.telstate = TS_IAC; + else + G.buf[cstart++] = c; + break; + + case TS_IAC: + if (c == IAC) /* IAC IAC -> 0xFF */ + { + G.buf[cstart++] = c; + G.telstate = TS_0; + break; + } + /* else */ + switch (c) + { + case SB: + G.telstate = TS_SUB1; + break; + case DO: + case DONT: + case WILL: + case WONT: + G.telwish = c; + G.telstate = TS_OPT; + break; + default: + G.telstate = TS_0; /* DATA MARK must be added later */ + } + break; + case TS_OPT: /* WILL, WONT, DO, DONT */ + telopt(c); + G.telstate = TS_0; + break; + case TS_SUB1: /* Subnegotiation */ + case TS_SUB2: /* Subnegotiation */ + if (subneg(c) == TRUE) + G.telstate = TS_0; + break; + } + } + if (G.telstate) + { + if (G.iaclen) iacflush(); + if (G.telstate == TS_0) G.telstate = 0; + + len = cstart; + } + + if (len) + write(1, G.buf, len); +} + + +/* ******************************* */ + +static inline void putiac(int c) +{ + G.iacbuf[G.iaclen++] = c; +} + + +static void putiac2(byte wwdd, byte c) +{ + if (G.iaclen + 3 > IACBUFSIZE) + iacflush(); + + putiac(IAC); + putiac(wwdd); + putiac(c); +} + +#if 0 +static void putiac1(byte c) +{ + if (G.iaclen + 2 > IACBUFSIZE) + iacflush(); + + putiac(IAC); + putiac(c); +} +#endif + +#ifdef BB_FEATURE_TELNET_TTYPE +static void putiac_subopt(byte c, char *str) +{ + int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 ) + + if (G.iaclen + len > IACBUFSIZE) + iacflush(); + + putiac(IAC); + putiac(SB); + putiac(c); + putiac(0); + + while(*str) + putiac(*str++); + + putiac(IAC); + putiac(SE); +} +#endif + +#ifdef BB_FEATURE_AUTOWIDTH +static void putiac_naws(byte c, int x, int y) +{ + if (G.iaclen + 9 > IACBUFSIZE) + iacflush(); + + putiac(IAC); + putiac(SB); + putiac(c); + + putiac((x >> 8) & 0xff); + putiac(x & 0xff); + putiac((y >> 8) & 0xff); + putiac(y & 0xff); + + putiac(IAC); + putiac(SE); +} +#endif + +/* void putiacstring (subneg strings) */ + +/* ******************************* */ + +static char const escapecharis[] = "\r\nEscape character is "; + +static void setConMode() +{ + if (G.telflags & UF_ECHO) + { + if (G.charmode == CHM_TRY) { + G.charmode = CHM_ON; + printf("\r\nEntering character mode%s'^]'.\r\n", escapecharis); + rawmode(); + } + } + else + { + if (G.charmode != CHM_OFF) { + G.charmode = CHM_OFF; + printf("\r\nEntering line mode%s'^C'.\r\n", escapecharis); + cookmode(); + } + } +} + +/* ******************************* */ + +static void will_charmode() +{ + G.charmode = CHM_TRY; + G.telflags |= (UF_ECHO | UF_SGA); + setConMode(); + + putiac2(DO, TELOPT_ECHO); + putiac2(DO, TELOPT_SGA); + iacflush(); +} + +static void do_linemode() +{ + G.charmode = CHM_TRY; + G.telflags &= ~(UF_ECHO | UF_SGA); + setConMode(); + + putiac2(DONT, TELOPT_ECHO); + putiac2(DONT, TELOPT_SGA); + iacflush(); +} + +/* ******************************* */ + +static inline void to_notsup(char c) +{ + if (G.telwish == WILL) putiac2(DONT, c); + else if (G.telwish == DO) putiac2(WONT, c); +} + +static inline void to_echo(void) +{ + /* if server requests ECHO, don't agree */ + if (G.telwish == DO) { putiac2(WONT, TELOPT_ECHO); return; } + else if (G.telwish == DONT) return; + + if (G.telflags & UF_ECHO) + { + if (G.telwish == WILL) + return; + } + else + if (G.telwish == WONT) + return; + + if (G.charmode != CHM_OFF) + G.telflags ^= UF_ECHO; + + if (G.telflags & UF_ECHO) + putiac2(DO, TELOPT_ECHO); + else + putiac2(DONT, TELOPT_ECHO); + + setConMode(); + WriteCS(1, "\r\n"); /* sudden modec */ +} + +static inline void to_sga(void) +{ + /* daemon always sends will/wont, client do/dont */ + + if (G.telflags & UF_SGA) + { + if (G.telwish == WILL) + return; + } + else + if (G.telwish == WONT) + return; + + if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */ + putiac2(DO, TELOPT_SGA); + else + putiac2(DONT, TELOPT_SGA); + + return; +} + +#ifdef BB_FEATURE_TELNET_TTYPE +static inline void to_ttype(void) +{ + /* Tell server we will (or won't) do TTYPE */ + + if(ttype) + putiac2(WILL, TELOPT_TTYPE); + else + putiac2(WONT, TELOPT_TTYPE); + + return; +} +#endif + +#ifdef BB_FEATURE_AUTOWIDTH +static inline void to_naws(void) +{ + /* Tell server we will do NAWS */ + putiac2(WILL, TELOPT_NAWS); + return; +} +#endif + +static void telopt(byte c) +{ + switch (c) + { + case TELOPT_ECHO: to_echo(); break; + case TELOPT_SGA: to_sga(); break; +#ifdef BB_FEATURE_TELNET_TTYPE + case TELOPT_TTYPE: to_ttype(); break; +#endif +#ifdef BB_FEATURE_AUTOWIDTH + case TELOPT_NAWS: to_naws(); + putiac_naws(c, win_width, win_height); + break; +#endif + default: to_notsup(c); + break; + } +} + + +/* ******************************* */ + +/* subnegotiation -- ignore all (except TTYPE,NAWS) */ + +static int subneg(byte c) +{ + switch (G.telstate) + { + case TS_SUB1: + if (c == IAC) + G.telstate = TS_SUB2; +#ifdef BB_FEATURE_TELNET_TTYPE + else + if (c == TELOPT_TTYPE) + putiac_subopt(TELOPT_TTYPE,ttype); +#endif + break; + case TS_SUB2: + if (c == SE) + return TRUE; + G.telstate = TS_SUB1; + /* break; */ + } + return FALSE; +} + +/* ******************************* */ + +static void fgotsig(int sig) +{ + G.gotsig = sig; +} + + +static void rawmode() +{ + tcsetattr(0, TCSADRAIN, &G.termios_raw); +} + +static void cookmode() +{ + tcsetattr(0, TCSADRAIN, &G.termios_def); +} + +extern int telnet_main(int argc, char** argv) +{ + struct in_addr host; + int port; + int len; +#ifdef USE_POLL + struct pollfd ufds[2]; +#else + fd_set readfds; + int maxfd; +#endif + +#ifdef BB_FEATURE_AUTOWIDTH + struct winsize winp; + if( ioctl(0, TIOCGWINSZ, &winp) == 0 ) { + win_width = winp.ws_col; + win_height = winp.ws_row; + } +#endif + +#ifdef BB_FEATURE_TELNET_TTYPE + ttype = getenv("TERM"); +#endif + + memset(&G, 0, sizeof G); + + if (tcgetattr(0, &G.termios_def) < 0) + exit(1); + + G.termios_raw = G.termios_def; + cfmakeraw(&G.termios_raw); + + if (argc < 2) show_usage(); + port = (argc > 2)? getport(argv[2]): 23; + + host = getserver(argv[1]); + + G.netfd = remote_connect(host, port); + + signal(SIGINT, fgotsig); + +#ifdef USE_POLL + ufds[0].fd = 0; ufds[1].fd = G.netfd; + ufds[0].events = ufds[1].events = POLLIN; +#else + FD_ZERO(&readfds); + FD_SET(0, &readfds); + FD_SET(G.netfd, &readfds); + maxfd = G.netfd + 1; +#endif + + while (1) + { +#ifndef USE_POLL + fd_set rfds = readfds; + + switch (select(maxfd, &rfds, NULL, NULL, NULL)) +#else + switch (poll(ufds, 2, -1)) +#endif + { + case 0: + /* timeout */ + case -1: + /* error, ignore and/or log something, bay go to loop */ + if (G.gotsig) + conescape(); + else + sleep(1); + break; + default: + +#ifdef USE_POLL + if (ufds[0].revents) /* well, should check POLLIN, but ... */ +#else + if (FD_ISSET(0, &rfds)) +#endif + { + len = read(0, G.buf, DATABUFSIZE); + + if (len <= 0) + doexit(0); + + TRACE(0, ("Read con: %d\n", len)); + + handlenetoutput(len); + } + +#ifdef USE_POLL + if (ufds[1].revents) /* well, should check POLLIN, but ... */ +#else + if (FD_ISSET(G.netfd, &rfds)) +#endif + { + len = read(G.netfd, G.buf, DATABUFSIZE); + + if (len <= 0) + { + WriteCS(1, "Connection closed by foreign host.\r\n"); + doexit(1); + } + TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len)); + + handlenetinput(len); + } + } + } +} + +static int getport(char * p) +{ + unsigned int port = atoi(p); + + if ((unsigned)(port - 1 ) > 65534) + { + error_msg_and_die("%s: bad port number", p); + } + return port; +} + +static struct in_addr getserver(char * host) +{ + struct in_addr addr; + + struct hostent * he; + he = xgethostbyname(host); + memcpy(&addr, he->h_addr, sizeof addr); + + TRACE(1, ("addr: %s\n", inet_ntoa(addr))); + + return addr; +} + +static int create_socket() +{ + return socket(AF_INET, SOCK_STREAM, 0); +} + +static void setup_sockaddr_in(struct sockaddr_in * addr, int port) +{ + memset(addr, 0, sizeof(struct sockaddr_in)); + addr->sin_family = AF_INET; + addr->sin_port = htons(port); +} + +static int remote_connect(struct in_addr addr, int port) +{ + struct sockaddr_in s_addr; + int s = create_socket(); + + setup_sockaddr_in(&s_addr, port); + s_addr.sin_addr = addr; + + setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one); + + if (connect(s, (struct sockaddr *)&s_addr, sizeof s_addr) < 0) + { + perror_msg_and_die("Unable to connect to remote host"); + } + return s; +} + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ + diff --git a/test.c b/test.c new file mode 100644 index 000000000..9c66cbb87 --- /dev/null +++ b/test.c @@ -0,0 +1,579 @@ +/* vi: set sw=4 ts=4: */ +/* + * test implementation for busybox + * + * 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. + * + * 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 + * + * Original copyright notice states: + * "This program is in the Public Domain." + */ + +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +/* test(1) accepts the following grammar: + oexpr ::= aexpr | aexpr "-o" oexpr ; + aexpr ::= nexpr | nexpr "-a" aexpr ; + nexpr ::= primary | "!" primary + primary ::= unary-operator operand + | operand binary-operator operand + | operand + | "(" oexpr ")" + ; + 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"| + "-nt"|"-ot"|"-ef"; + operand ::= +*/ + +enum token { + 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 +}; + +enum token_types { + UNOP, + BINOP, + BUNOP, + BBINOP, + 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} +}; + +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(); +static int oexpr(); +static int aexpr(); +static int nexpr(); +static int binop(); +static int primary(); +static int filstat(); +static int getn(); +static int newerf(); +static int olderf(); +static int equalf(); +static void syntax(); +static int test_eaccess(); +static int is_a_group_member(); +static void initialize_group_array(); + +extern int +test_main(int argc, char** argv) +{ + int res; + + if (strcmp(applet_name, "[") == 0) { + if (strcmp(argv[--argc], "]")) + 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)); + + if (*t_wp != NULL && *++t_wp != NULL) + syntax(*t_wp, "unknown operand"); + + return( res); +} + +static void +syntax(op, msg) + char *op; + char *msg; +{ + if (op && *op) + error_msg_and_die("%s: %s", op, msg); + else + error_msg_and_die("%s", msg); +} + +static int +oexpr(n) + enum token n; +{ + int res; + + res = aexpr(n); + if (t_lex(*++t_wp) == BOR) + return oexpr(t_lex(*++t_wp)) || res; + t_wp--; + return res; +} + +static int +aexpr(n) + enum token n; +{ + int res; + + res = nexpr(n); + if (t_lex(*++t_wp) == BAND) + return aexpr(t_lex(*++t_wp)) && res; + t_wp--; + return res; +} + +static int +nexpr(n) + enum token n; /* token */ +{ + if (n == UNOT) + return !nexpr(t_lex(*++t_wp)); + return primary(n); +} + +static int +primary(n) + enum token n; +{ + int res; + + 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; + } + 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); + } + } + + if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) { + return binop(); + } + + return strlen(*t_wp) > 0; +} + +static int +binop() +{ + const char *opnd1, *opnd2; + struct t_op const *op; + + opnd1 = *t_wp; + (void) t_lex(*++t_wp); + op = t_wp_op; + + if ((opnd2 = *++t_wp) == (char *)0) + syntax(op->op_text, "argument expected"); + + 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); + } + /* NOTREACHED */ + return 1; +} + +static int +filstat(nm, mode) + char *nm; + enum token mode; +{ + struct stat s; + unsigned int i; + + if (mode == FILSYM) { +#ifdef S_IFLNK + if (lstat(nm, &s) == 0) { + i = S_IFLNK; + goto filetype; + } +#endif + return 0; + } + + 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: + 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: +#ifdef S_IFIFO + i = S_IFIFO; + goto filetype; +#else + return 0; +#endif + case FILSOCK: +#ifdef S_IFSOCK + i = S_IFSOCK; + goto filetype; +#else + 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: + return s.st_size > 0L; + case FILUID: + return s.st_uid == geteuid(); + case FILGID: + return s.st_gid == getegid(); + default: + return 1; + } + +filetype: + return ((s.st_mode & S_IFMT) == i); + +filebit: + return ((s.st_mode & i) != 0); +} + +static enum token +t_lex(s) + 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; + } + op++; + } + t_wp_op = (struct t_op *)0; + return OPERAND; +} + +/* atoi with error detection */ +static int +getn(s) + char *s; +{ + char *p; + long r; + + errno = 0; + r = strtol(s, &p, 10); + + if (errno != 0) + error_msg_and_die("%s: out of range", s); + + while (isspace(*p)) + p++; + + if (*p) + error_msg_and_die("%s: bad number", s); + + return (int) r; +} + +static int +newerf (f1, f2) +char *f1, *f2; +{ + struct stat b1, b2; + + return (stat (f1, &b1) == 0 && + stat (f2, &b2) == 0 && + b1.st_mtime > b2.st_mtime); +} + +static int +olderf (f1, f2) +char *f1, *f2; +{ + struct stat b1, b2; + + return (stat (f1, &b1) == 0 && + stat (f2, &b2) == 0 && + b1.st_mtime < b2.st_mtime); +} + +static int +equalf (f1, f2) +char *f1, *f2; +{ + struct stat b1, b2; + + return (stat (f1, &b1) == 0 && + stat (f2, &b2) == 0 && + b1.st_dev == b2.st_dev && + b1.st_ino == b2.st_ino); +} + +/* 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 (path, mode) +char *path; +int mode; +{ + struct stat st; + unsigned int euid = geteuid(); + + if (stat (path, &st) < 0) + return (-1); + + if (euid == 0) { + /* Root can read or write any file. */ + if (mode != X_OK) + return (0); + + /* 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); + } + + 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 void +initialize_group_array () +{ + ngroups = getgroups(0, NULL); + group_array = xrealloc(group_array, ngroups * sizeof(gid_t)); + getgroups(ngroups, group_array); +} + +/* Return non-zero if GID is one that we have in our groups list. */ +static int +is_a_group_member (gid) +gid_t gid; +{ + register 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); +} diff --git a/tests/.cvsignore b/tests/.cvsignore new file mode 100644 index 000000000..3645cf92f --- /dev/null +++ b/tests/.cvsignore @@ -0,0 +1,16 @@ +cp +cp_*.bb +cp_*.gnu +cp_tests +date +df +du +ln +ln_*.bb +ln_*.gnu +ln_tests +mv +mv_*.bb +mv_*.gnu +mv_tests +syslog_test diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 000000000..8ad304d86 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,34 @@ +# busybox/tests/Makefile - Run through all defined tests. +# ------------------------ +# Copyright (C) 2000 Karl M. Hegbloom GPL + +all:: message_header + +message_header: + @echo + @echo BusyBox Test Suite. + @echo + (cd ..; tests/busybox.REGRESS.sh) + +clean:: + +distclean: clean + +.PHONY: all clean distclean message_header + +include $(wildcard *_tests.mk) + +BBL := $(shell pushd .. >/dev/null && \ + ${MAKE} busybox.links >/dev/null && \ + popd >/dev/null && \ + cat ../busybox.links | \ + sed -e 's,.*/\(.*\)$$,\1,') + +../busybox: + cd .. && ${MAKE} busybox + +${BBL}: ../busybox + rm -f $@ + ln ../busybox $@ + +syslog_test: syslog_test.c diff --git a/tests/cp_tests.mk b/tests/cp_tests.mk new file mode 100644 index 000000000..b96c5cea6 --- /dev/null +++ b/tests/cp_tests.mk @@ -0,0 +1,360 @@ +# cp_tests.mk - Set of test cases for busybox cp +# ------------- +# Copyright (C) 2000 Karl M. Hegbloom GPL +# + +# GNU `cp' +GCP = /bin/cp +# BusyBox `cp' +BCP = $(shell pwd)/cp + +all:: cp_tests +clean:: cp_clean + +cp_clean: + - rm -rf cp_tests cp_*.{gnu,bb} cp + +# check_cp_dir_to_dir_wo_a removed from this list; see below +cp_tests: cp_clean cp check_exists check_simple_cp check_cp_symlnk \ + check_cp_symlink_w_a check_cp_files_to_dir check_cp_files_to_dir_w_d \ + check_cp_files_to_dir_w_p check_cp_files_to_dir_w_p_and_d \ + check_cp_dir_to_dir_w_a \ + check_cp_dir_to_dir_w_a_take_two + +check_exists: + @echo; + @echo "No output from diff means busybox cp is functioning properly."; + @echo "Some tests might show timestamp differences that are Ok."; + + @echo; + @echo Verify that busybox cp exists; + @echo ------------------------------; + [ -x ${BCP} ] || exit 0 + + @echo; + mkdir cp_tests; + +check_simple_cp: + @echo Copy a file to a copy of the file; + @echo ------------------------------; + cd cp_tests; \ + echo A file > afile; \ + ls -l afile > ../cp_afile_afilecopy.gnu; \ + ${GCP} afile afilecopy; \ + ls -l afile afilecopy >> ../cp_afile_afilecopy.gnu; + + @echo; + rm -rf cp_tests/*; + + @echo; + cd cp_tests; \ + echo A file > afile; \ + ls -l afile > ../cp_afile_afilecopy.bb; \ + ${BCP} afile afilecopy; \ + ls -l afile afilecopy >> ../cp_afile_afilecopy.bb; + + @echo; + @echo Might show timestamp differences. + -diff -u cp_afile_afilecopy.gnu cp_afile_afilecopy.bb; + + @echo; + rm -rf cp_tests/*; + +check_cp_symlnk: + @echo; echo Copy a file pointed to by a symlink; + @echo ------------------------------; + cd cp_tests; \ + mkdir here there; \ + echo A file > afile; \ + cd here; \ + ln -s ../afile .; \ + + @echo; + cd cp_tests; \ + ls -lR . > ../cp_symlink.gnu; \ + ${GCP} here/afile there; \ + ls -lR . >> ../cp_symlink.gnu; + + @echo; + rm -rf cp_tests/there/*; + + sleep 1; + + @echo; + cd cp_tests; \ + ls -lR . > ../cp_symlink.bb; \ + ${BCP} here/afile there; \ + ls -lR . >> ../cp_symlink.bb; + + @echo; + @echo Will show timestamp difference. + -diff -u cp_symlink.gnu cp_symlink.bb; + + @echo; + rm -rf cp_tests/* + +check_cp_symlink_w_a: + @echo; echo Copy a symlink, useing the -a switch.; + @echo ------------------------------; + cd cp_tests; \ + echo A file > afile; \ + mkdir here there; \ + cd here; \ + ln -s ../afile . + + cd cp_tests; \ + ls -lR . > ../cp_a_symlink.gnu; \ + ${GCP} -a here/afile there; \ + ls -lR . >> ../cp_a_symlink.gnu; + + @echo; + rm -rf cp_tests/there/*; + + sleep 1; + + @echo; + cd cp_tests; \ + echo A file > afile; \ + ls -lR . > ../cp_a_symlink.bb; \ + ${BCP} -a here/afile there; \ + ls -lR . >> ../cp_a_symlink.bb; + + @echo; + diff -u cp_a_symlink.gnu cp_a_symlink.bb; + + @echo; + rm -rf cp_tests/*; + + +check_cp_files_to_dir: + # Copy a set of files to a directory. + @echo; echo Copy a set of files to a directory.; + @echo ------------------------------; + cd cp_tests; \ + echo A file number one > afile1; \ + echo A file number two, blah. > afile2; \ + ln -s afile1 symlink1; \ + mkdir there; + + cd cp_tests; \ + ${GCP} afile1 afile2 symlink1 there/; \ + ls -lR > ../cp_files_dir.gnu; + + @echo; + rm -rf cp_tests/there/*; + + @echo; + cd cp_tests; \ + ${BCP} afile1 afile2 symlink1 there/; \ + ls -lR > ../cp_files_dir.bb; + + @echo; + diff -u cp_files_dir.gnu cp_files_dir.bb; + + @echo; + rm -rf cp_tests/*; + +check_cp_files_to_dir_w_d: + # Copy a set of files to a directory with the -d switch. + @echo; echo Copy a set of files to a directory with the -d switch.; + @echo ------------------------------; + cd cp_tests; \ + echo A file number one > afile1; \ + echo A file number two, blah. > afile2; \ + ln -s afile1 symlink1; \ + mkdir there1; \ + ${GCP} -d afile1 afile2 symlink1 there1/; \ + ls -lR > ../cp_d_files_dir.gnu; + + @echo; + rm -rf cp_tests/{afile{1,2},symlink1,there1}; + + @echo; + cd cp_tests; \ + echo A file number one > afile1; \ + echo A file number two, blah. > afile2; \ + ln -s afile1 symlink1; \ + mkdir there1; \ + ${BCP} -d afile1 afile2 symlink1 there1/; \ + ls -lR > ../cp_d_files_dir.bb; + + @echo; + diff -u cp_d_files_dir.gnu cp_d_files_dir.bb; + + @echo; + rm -rf cp_tests/{afile{1,2},symlink1,there1}; + +check_cp_files_to_dir_w_p: + # Copy a set of files to a directory with the -p switch. + @echo; echo Copy a set of files to a directory with the -p switch.; + @echo ------------------------------; + cd cp_tests; \ + echo A file number one > afile1; \ + echo A file number two, blah. > afile2; \ + touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \ + ln -s afile1 symlink1; \ + mkdir there1; \ + ${GCP} -p afile1 afile2 symlink1 there1/; \ + ls -lR > ../cp_p_files_dir.gnu; + + @echo; + rm -rf cp_tests/{afile{1,2},symlink1,there1}; + + @echo; + cd cp_tests; \ + echo A file number one > afile1; \ + echo A file number two, blah. > afile2; \ + touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \ + ln -s afile1 symlink1; \ + mkdir there1; \ + ${BCP} -p afile1 afile2 symlink1 there1/; \ + ls -lR > ../cp_p_files_dir.bb; + + @echo; + diff -u cp_p_files_dir.gnu cp_p_files_dir.bb; + + @echo; + rm -rf cp_tests/{afile{1,2},symlink1,there1}; + + +check_cp_files_to_dir_w_p_and_d: + @echo; echo Copy a set of files to a directory with -p and -d switches. + @echo ------------------------------; + cd cp_tests; \ + echo A file number one > afile1; \ + echo A file number two, blah. > afile2; \ + touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \ + ln -s afile1 symlink1; \ + mkdir there1; \ + ${GCP} -p -d afile1 afile2 symlink1 there1/; \ + ls -lR > ../cp_pd_files_dir.gnu; + + @echo; + rm -rf cp_tests/{afile{1,2},symlink1,there1}; + + @echo; + cd cp_tests; \ + echo A file number one > afile1; \ + echo A file number two, blah. > afile2; \ + touch --date='Sat Jan 29 21:24:08 PST 2000' afile1; \ + ln -s afile1 symlink1; \ + mkdir there1; \ + ${BCP} -p -d afile1 afile2 symlink1 there1/; \ + ls -lR > ../cp_pd_files_dir.bb; + + @echo; + diff -u cp_pd_files_dir.gnu cp_pd_files_dir.bb; + + @echo; + rm -rf cp_tests/{afile{1,2},symlink1,there1}; + +# This test doesn't work any more; gnu cp now _does_ copy a directory +# to a subdirectory of itself. What's worse, that "feature" has no +# (documented) way to be disabled with command line switches. +# It's not obvious that busybox cp should mimic this behavior. +# For now, this test is removed from the cp_tests list, above. +check_cp_dir_to_dir_wo_a: + # Copy a directory to another directory, without the -a switch. + @echo; echo Copy a directory to another directory, without the -a switch. + @echo ------------------------------; + @echo There should be an error message about cannot cp a dir to a subdir of itself. + cd cp_tests; \ + touch a b c; \ + mkdir adir; \ + ls -lR . > ../cp_a_star_adir.gnu; \ + ${GCP} -a * adir; \ + ls -lR . >> ../cp_a_star_adir.gnu; + + @echo + @echo There should be an error message about cannot cp a dir to a subdir of itself. + cd cp_tests; \ + rm -rf adir; \ + mkdir adir; \ + ls -lR . > ../cp_a_star_adir.bb; \ + ${BCP} -a * adir; \ + ls -lR . >> ../cp_a_star_adir.bb; + + @echo; + diff -u cp_a_star_adir.gnu cp_a_star_adir.bb; + + # Done + @echo; + rm -rf cp_tests; + @echo; echo Done. + + +check_cp_dir_to_dir_w_a: + @echo; echo Copy a directory into another directory with the -a switch. + @echo ------------------------------; + cd cp_tests; \ + mkdir dir{a,b}; \ + echo A file > dira/afile; \ + echo A file in dirb > dirb/afileindirb; \ + ln -s dira/afile dira/alinktoafile; \ + mkdir dira/subdir1; \ + echo Another file > dira/subdir1/anotherfile; \ + ls -lR . > ../cp_a_dira_dirb.gnu; \ + ${GCP} -a dira dirb; \ + ls -lR . >> ../cp_a_dira_dirb.gnu; + + @echo; + rm -rf cp_tests/dir{a,b}; + + @echo; + cd cp_tests; \ + mkdir dir{a,b}; \ + echo A file > dira/afile; \ + echo A file in dirb > dirb/afileindirb; \ + ln -s dira/afile dira/alinktoafile; \ + mkdir dira/subdir1; \ + echo Another file > dira/subdir1/anotherfile; \ + ls -lR . > ../cp_a_dira_dirb.bb; \ + ${BCP} -a dira dirb; \ + ls -lR . >> ../cp_a_dira_dirb.bb; + + @echo; + diff -u cp_a_dira_dirb.gnu cp_a_dira_dirb.bb; + + @echo; + rm -rf cp_tests/dir{a,b}; + + +check_cp_dir_to_dir_w_a_take_two: + @echo; echo Copy a directory into another directory with the -a switch; + @echo ------------------------------; + mkdir -p cp_tests/gnu; \ + mkdir -p cp_tests/bb; \ + cd cp_tests; \ + mkdir here there; \ + echo A file > here/afile; \ + mkdir here/adir; \ + touch here/adir/afileinadir; \ + ln -s $$(pwd) here/alink; + + @echo; + cd cp_tests/gnu; \ + ls -lR . > ../../cp_a_dir_dir.gnu; \ + ${GCP} -a here/ there/; \ + ls -lR . >> ../../cp_a_dir_dir.gnu; + + @echo; + rm -rf cp_tests/there/*; + + sleep 1; + + @echo; + cd cp_tests/bb; \ + ls -lR . > ../../cp_a_dir_dir.bb; \ + ${BCP} -a here/ there/; \ + ls -lR . >> ../../cp_a_dir_dir.bb; + + @echo; + echo "Erik 1" + diff -u cp_a_dir_dir.gnu cp_a_dir_dir.bb; + echo "Erik 2" + + @echo; + echo "Erik 3" + rm -rf cp_tests/*; + + diff --git a/tests/ln_tests.mk b/tests/ln_tests.mk new file mode 100644 index 000000000..3110f8199 --- /dev/null +++ b/tests/ln_tests.mk @@ -0,0 +1,71 @@ +# ln_tests.mk - Set of tests for busybox ln +# ------------- +# Copyright (C) 2000 Karl M. Hegbloom GPL +# + +# GNU `ln' +GLN = /bin/ln +# BusyBox `ln' +BLN = $(shell pwd)/ln + +all:: ln_tests +clean:: ln_clean + +ln_clean: + rm -rf ln_tests ln_*.{gnu,bb} ln + +ln_tests: ln_clean ln + @echo; + @echo "No output from diff means busybox ln is functioning properly."; + + @echo; + ${BLN} || true; + + @echo; + mkdir ln_tests; + + @echo; + cd ln_tests; \ + echo A file > afile; \ + ls -l afile > ../ln_afile_newname.gnu; \ + ${GLN} afile newname; \ + ls -l afile newname >> ../ln_afile_newname.gnu; + + @echo; + rm -f ln_tests/{afile,newname}; + + @echo; + cd ln_tests; \ + echo A file > afile; \ + ls -l afile > ../ln_afile_newname.bb; \ + ${BLN} afile newname; \ + ls -l afile newname >> ../ln_afile_newname.bb; + + @echo; + diff -u ln_afile_newname.gnu ln_afile_newname.bb + + @echo; + rm -f ln_tests/{afile,newname}; + + @echo; + cd ln_tests; \ + echo A file > afile; \ + ls -l afile > ../ln_s_afile_newname.gnu; \ + ${GLN} -s afile newname; \ + ls -l afile newname >> ../ln_s_afile_newname.gnu; + + @echo; + rm -f ln_tests/{afile,newname}; + + @echo; + cd ln_tests; \ + echo A file > afile; \ + ls -l afile > ../ln_s_afile_newname.bb; \ + ${BLN} -s afile newname; \ + ls -l afile newname >> ../ln_s_afile_newname.bb; + + @echo; + diff -u ln_s_afile_newname.gnu ln_s_afile_newname.bb + + @echo; + rm -f ln_tests/{afile,newname}; diff --git a/tests/multibuild.pl b/tests/multibuild.pl new file mode 100755 index 000000000..94930bd95 --- /dev/null +++ b/tests/multibuild.pl @@ -0,0 +1,73 @@ +#!/usr/bin/perl + +# multibuild.pl +# Tests BusyBox-0.48 (at least) to see if each applet builds +# properly on its own. The most likely problems this will +# flush out are those involving preprocessor instructions in +# utility.c. +# +# TODO: some time it might be nice to list absolute and +# differential object sizes for each option... +# + +$logfile = "multibuild.log"; + +# How to handle all the BB_FEATURE_FOO lines +if ($ARGV[0] eq "-all" ) { shift(@ARGV); $choice="all"; } +if ($ARGV[0] eq "-none") { shift(@ARGV); $choice="none"; } +# neither means, leave that part of Config.h alone + +# Support building from pristine source +$make_opt = "-f $ARGV[0]/Makefile BB_SRC_DIR=$ARGV[0]" if ($ARGV[0] ne ""); + +# Move the config file to a safe place +-e "Config.h.orig" || 0==system("mv -f Config.h Config.h.orig") || die; + +# Clear previous log file, if any +unlink($logfile); + +# Parse the config file +open(C,") { + if ($in_trailer) { + if (!$in_olympus) { + s/^\/\/#/#/ if ($choice eq "all" && !/USE_DEVPS_PATCH/); + s/^#/\/\/#/ if ($choice eq "none"); + } + $in_olympus=1 if /End of Features List/; + $trailer .= $_; + } else { + $in_trailer=1 if /End of Applications List/; + if (/^\/*#define BB_([A-Z0-9_]*)/) { + push @apps, $1; + } + } +} +close C; + +# Do the real work ... +$failed_tests=0; +for $a (@apps) { + # print "Testing build of applet $a ...\n"; + open (O, ">Config.h") || die; + print O "#define BB_$a\n", $trailer; + close O; + system("echo -e '\n***\n$a\n***' >>$logfile"); + # With a fast computer and 1-second resolution on file timestamps, this + # process pushes beyond the limits of what unix make can understand. + # That's why need to weed out obsolete files before restarting make. + $result{$a} = system("rm -f *.o applet_source_list; make $make_opt busybox >>$logfile 2>&1"); + $flag = $result{$a} ? "FAILED!!!" : "ok"; + printf("Applet %-20s: %s\n", $a, $flag); + $total_tests++; + $failed_tests++ if $flag eq "FAILED!!!"; + # pause long enough to let user stop us with a ^C + select(undef, undef, undef, 0.03); +} + +# Clean up our mess +system("mv -f Config.h.orig Config.h"); + +print "$total_tests applets tested, $failed_tests failures\n"; +print "See $logfile for details.\n"; + diff --git a/tests/multifeat.pl b/tests/multifeat.pl new file mode 100755 index 000000000..adcb30bbd --- /dev/null +++ b/tests/multifeat.pl @@ -0,0 +1,83 @@ +#!/usr/bin/perl +# +# multifeat.pl +# +# Turns on all applets, then tests turning on one feature at a time through +# iterative compilations. Tests if any features depend on each other in any +# weird ways or such-like problems. +# +# Hacked by Mark Whitley, but based *heavily* on multibuild.pl which was +# written by Larry Doolittle. + +$logfile = "multifeat.log"; + +# How to handle all the BB_APPLET lines +# (most thorough testing occurs when you call it with the -all switch) +if ($ARGV[0] eq "-all" ) { shift(@ARGV); $choice="all"; } +if ($ARGV[0] eq "-none") { shift(@ARGV); $choice="none"; } +# neither means, leave that part of Config.h alone + +# Support building from pristine source +$make_opt = "-f $ARGV[0]/Makefile BB_SRC_DIR=$ARGV[0]" if ($ARGV[0] ne ""); + +# Move the config file to a safe place +-e "Config.h.orig" || 0==system("mv -f Config.h Config.h.orig") || die; + +# Clear previous log file, if any +unlink($logfile); + +# Parse the config file +open(C,") { + if ($in_applist) { + s/^\/\/#/#/ if ($choice eq "all"); + s/^#/\/\/#/ if ($choice eq "none"); + $header .= $_; + if (/End of Applications List/) { + $in_applist=0; + $in_features=1 + } + } + elsif ($in_features) { + if (/^\/*#define BB_FEATURE_([A-Z0-9_]*)/) { + push @features, $1; + } + if (/End of Features List/) { + $in_features=0; + $in_olympus=1 + } + } elsif ($in_olympus) { + $trailer .= $_; + } +} +close C; + +# Do the real work ... +$failed_tests=0; +for $f (@features) { + # print "Testing build with feature $f ...\n"; + open (O, ">Config.h") || die; + print O $header, "#define BB_FEATURE_$f\n", $trailer; + close O; + system("echo -e '\n***\n$f\n***' >>$logfile"); + # With a fast computer and 1-second resolution on file timestamps, this + # process pushes beyond the limits of what unix make can understand. + # That's why need to weed out obsolete files before restarting make. + $result{$f} = system("rm -f *.o applet_source_list; make $make_opt busybox >>$logfile 2>&1"); + $flag = $result{$f} ? "FAILED!!!" : "ok"; + printf("Feature %-20s: %s\n", $f, $flag); + $total_tests++; + $failed_tests++ if $flag eq "FAILED!!!"; + # pause long enough to let user stop us with a ^C + select(undef, undef, undef, 0.03); +} + +# Clean up our mess +system("mv -f Config.h.orig Config.h"); + +print "$total_tests applets tested, $failed_tests failures\n"; +print "See $logfile for details.\n"; + diff --git a/tests/mv_tests.mk b/tests/mv_tests.mk new file mode 100644 index 000000000..f03e08a73 --- /dev/null +++ b/tests/mv_tests.mk @@ -0,0 +1,167 @@ +# mv_tests.mk - Set of tests cases for busybox mv +# ------------- +# Copyright (C) 2000 Karl M. Hegbloom GPL +# + +# GNU `mv' +GMV = /bin/mv +# BusyBox `mv' +BMV = $(shell pwd)/mv + +all:: mv_tests +clean:: mv_clean + +mv_clean: + rm -rf mv_tests mv_*.{gnu,bb} mv + +mv_tests: mv_clean mv + @echo; + @echo "No output from diff means busybox mv is functioning properly."; + @echo; + @echo "No such file or directory is good; it means the old file got removed."; + @echo; + ${BMV} || true; + + @echo; + mkdir mv_tests; + + @echo; + cd mv_tests; \ + echo A file > afile; \ + ls -l afile > ../mv_afile_newname.gnu; \ + ${GMV} afile newname; \ + ls -l newname >> ../mv_afile_newname.gnu; + -ls -l mv_tests/afile; + + @echo; + rm -f mv_tests/{afile,newname}; + + @echo; + cd mv_tests; \ + echo A file > afile; \ + ls -l afile > ../mv_afile_newname.bb; \ + ${BMV} afile newname; \ + ls -l newname >> ../mv_afile_newname.bb; + -ls -l mv_tests/afile; + + @echo; + diff -u mv_afile_newname.gnu mv_afile_newname.bb; + + @echo; + rm -f mv_tests/{afile,newname}; + + @echo; echo ------------------------------; + cd mv_tests; \ + echo A file > afile; \ + ln -s afile symlink; \ + ls -l afile symlink > ../mv_symlink_newname.gnu; \ + ${GMV} symlink newname; \ + ls -l afile newname >> ../mv_symlink_newname.gnu; + -ls -l mv_tests/symlink; + + @echo; + rm -f mv_tests/{afile,newname}; + + @echo; + cd mv_tests; \ + echo A file > afile; \ + ln -s afile symlink; \ + ls -l afile symlink > ../mv_symlink_newname.bb;\ + ${BMV} symlink newname; \ + ls -l afile newname >> ../mv_symlink_newname.bb; + -ls -l mv_tests/symlink; + + @echo; + diff -u mv_symlink_newname.gnu mv_symlink_newname.bb; + + @echo; + rm -rf mv_tests/*; + + @echo; echo ------------------------------; + cd mv_tests; \ + echo A file > afile; \ + ln -s afile symlink; \ + mkdir newdir; \ + ls -lR > ../mv_file_symlink_dir.gnu; \ + ${GMV} symlink afile newdir; \ + ls -lR >> ../mv_file_symlink_dir.gnu; + -ls -l mv_tests/{symlink,afile}; + + @echo; + rm -rf mv_tests/* + + @echo; echo ------------------------------; + cd mv_tests; \ + echo A file > afile; \ + ln -s afile symlink; \ + mkdir newdir; \ + ls -lR > ../mv_file_symlink_dir.bb; \ + ${BMV} symlink afile newdir; \ + ls -lR >> ../mv_file_symlink_dir.bb; + -ls -l mv_tests/{symlink,afile}; + + @echo; + diff -u mv_file_symlink_dir.gnu mv_file_symlink_dir.bb; + + @echo; + rm -rf mv_tests/*; + + @echo; echo ------------------------------; + cd mv_tests; \ + mkdir dir{a,b}; \ + echo A file > dira/afile; \ + echo A file in dirb > dirb/afileindirb; \ + ln -s dira/afile dira/alinktoafile; \ + mkdir dira/subdir1; \ + echo Another file > dira/subdir1/anotherfile; \ + ls -lR . > ../mv_dira_dirb.gnu; \ + ${GMV} dira dirb; \ + ls -lR . >> ../mv_dira_dirb.gnu; + + # false; + @echo; + rm -rf mv_tests/dir{a,b}; + + @echo; + cd mv_tests; \ + mkdir dir{a,b}; \ + echo A file > dira/afile; \ + echo A file in dirb > dirb/afileindirb; \ + ln -s dira/afile dira/alinktoafile; \ + mkdir dira/subdir1; \ + echo Another file > dira/subdir1/anotherfile; \ + ls -lR . > ../mv_dira_dirb.bb; \ + ${BMV} dira dirb; \ + ls -lR . >> ../mv_dira_dirb.bb; + + @echo; + diff -u mv_dira_dirb.gnu mv_dira_dirb.bb; + + # false; + @echo; + rm -rf mv_tests/dir{a,b}; + + @echo; echo ------------------------------; + @echo There should be an error message about cannot mv a dir to a subdir of itself. + cd mv_tests; \ + mkdir adir; \ + touch -r . a b c adir; \ + ls -lR . > ../mv_a_star_adir.gnu; \ + ${GMV} * adir; \ + ls -lR . >> ../mv_a_star_adir.gnu; + + @echo + @echo There should be an error message about cannot mv a dir to a subdir of itself. + cd mv_tests; \ + rm -rf a b c adir; \ + mkdir adir; \ + touch -r . a b c adir; \ + ls -lR . > ../mv_a_star_adir.bb; \ + ${BMV} * adir; \ + ls -lR . >> ../mv_a_star_adir.bb; + + @echo; + diff -u mv_a_star_adir.gnu mv_a_star_adir.bb; + + @echo; + rm -rf mv_test/*; diff --git a/tests/sh.testcases b/tests/sh.testcases new file mode 100644 index 000000000..aa834d4a2 --- /dev/null +++ b/tests/sh.testcases @@ -0,0 +1,89 @@ +# try running this with bash, ksh, ash, and hush. + +# simple quoting rules. +echo a b +echo "a b" +echo a "" b +echo a '' b +echo hello? +echo "hello?" +echo t* hello +echo t\* hello + +# quick and painless exit for lash +if false; then true; exit; fi + +# fairly simple command substitution +echo `echo -e foo\\\necho bar` + +echo THIS IS A TEST >foo +cat $(echo FOO | tr 'A-Z' 'a-z') +cat foo | tr 'A-Z' 'a-z' +cat $(echo FOO | tr 'A-Z' 'a-z') | tr 'A-Z' 'a-z' + +cat foo | if true; then tr 'A-Z' 'a-z'; else echo bar1; fi +cat foo | if false; then tr 'A-Z' 'a-z'; else echo bar2; fi +if true; then tr 'A-Z' 'a-z'; else echo bar3; fi foo 2>&1 +cat foo +cat doesnt_exist >foo 2>&1 +tr 'a-z' 'A-Z' $TMP +ls fish + +# ash, lash, and hush do not create wish; bash and ksh do. +# Thanks to Tapani Tarvainen for this stress test. +unset TMP +rm -f wish +TMP=wish >$TMP +ls wish + +# The following example shows that hush's parser is +# not _really_ Bourne compatible +echo "echo Hello World" >"a=b" +unset a +chmod a+x "a=b" +PATH=$PATH:. +"a=b" +echo $a + +# assuming the shell wasn't too buggy, clean up the mess +rm -f a=b wish fish foo diff --git a/tests/syslog_test.c b/tests/syslog_test.c new file mode 100644 index 000000000..fb4c691b1 --- /dev/null +++ b/tests/syslog_test.c @@ -0,0 +1,19 @@ +#include + +int do_log(char* msg, int delay) +{ + openlog("testlog", LOG_PID, LOG_DAEMON); + while(1) { + syslog(LOG_ERR, "%s: testing one, two, three\n", msg); + sleep(delay); + } + closelog(); + return(0); +}; + +int main(void) +{ + if (fork()==0) + do_log("A", 2); + do_log("B", 3); +} diff --git a/tests/testcases b/tests/testcases new file mode 100644 index 000000000..2aad9b651 --- /dev/null +++ b/tests/testcases @@ -0,0 +1,404 @@ +# testcases +# +# This file should be filled with test cases to test applets that: +# +# - can somehow produce output (we can't test sync or sleep) +# - have a GNU (or other) counterpart +# - are not interactive (don't require a ^C or anything) +# - don't require extensive setup or cleanup (a litte setup is fine) +# - don't have huge and possibly damaging effects (fsck, swapoff) +# +# If possible, a test case should be made that tests each option the applet +# supports. When a new option is added, a new test case should be written for +# it. When somebody reports a bug with a testcase, that testcase should be +# added here as well. +# +# Some other guidelines to follow: +# +# - please try to keep applets alphabetized, it will make life easier +# - use the file tester.sh or testcases when you need to do a non-destructive +# test on a file (i.e., cat, md5sum) +# - try to make the applet you're testing the first thing on the line (this +# not always possible) +# - (???) if you have to create a temporary file, call it TMPFILE +# - pipe symbols that represent real pipes need a space in front of them +# (so the test script can find them and add the "../busybox" after it). +# - pipe symbols that are not used for pipes need to be shell-escaped, +# with a double \. See the expr test cases. + + +# ar + +# basename +basename `pwd` + +# cat +cat tester.sh +echo hello there | cat tester.sh - + +# chmod +# chown +# chgrp +# chroot +# chvt - can't be tested here +# clear - can't be tested here +# cmp +# cp + +# cut +echo "1234" | cut -c1 +echo "1234" | cut -c 1 +echo "1234567890" | cut -c2-7 +echo "1234567890" | cut -c 2-7 +echo "f1 f2" | cut -f2 +echo "f1 f2" | cut -f 2 +echo "f1 f2 f3 f4 f5" | cut -f2-4 +echo "f1 f2 f3 f4 f5" | cut -f 2-4 + +# date +date +date -R +date -u +date +%d/%m/%y + +# dc - needs an input file + +# dd +# BUG: record count line goes to stdout instead of stderr +dd if=/dev/urandom of=O bs=1k count=1 ; ls -l O ; rm O + +# deallocvt + +# df +# XXX: minor formatting differences +df +df . +df -k +df -h +df -m + +# dirname +dirname `pwd` + +# dmesg (XXX: change the silly cmd business in the source) +dmesg +dmesg -n 8 +dmesg -s 512 +# I really don't want to do this next one +#dmesg -c + +# dos2unix - needs an input file +# dpkg +# dpkg_deb + +# du +# BUG: rounding behavior differs from GNU du +du +du -s +du -l +du -k +du -h +du -m + +# dumpkmap - no counterprt? +# dutmp - no counterprt? + +# echo +echo "foo bar baz" +echo -n "no newline" + + +# expr +expr 1 \\| 1 +expr 1 \\| 0 +expr 0 \\| 1 +expr 0 \\| 0 + +expr 1 \\& 1 +expr 1 \\& 0 +expr 0 \\& 1 +expr 0 \\& 0 + +expr 0 \\< 1 +expr 1 \\< 0 + +expr 1 \\> 0 +expr 0 \\> 1 + +expr 0 \\<= 1 +expr 1 \\<= 0 +expr 1 \\<= 1 + +expr 1 \\>= 0 +expr 0 \\>= 1 +expr 1 \\>= 1 + +expr 1 + 2 +expr 2 - 1 +expr 2 \\* 3 +expr 12 / 2 +expr 12 % 5 + +# somebody else can do all the string stuff + + +# fbset - can't be tested here +# fdflush +# find +find . + +# free +# XXX: minor formatting differences +free + +# freeramdisk +# fsck.minix - won't test +# getopt + +# grep +grep -l strdup ../*.c +grep -c strdup ../*.c +grep -lc strdup ../*.c +grep -cv strdup ../*.c +grep -i null ../grep.c +grep -e strdup -e regcomp -e atexit ../grep.c + +# gunzip + +# gzip +# XXX: compressed output differs from gzip-1.2.4, but decompresses fine +echo testing 1 2 3 >tmpfile1; gzip tmpfile1; echo tmpfile*; md5sum tmpfile1.gz; rm tmpfile1.gz +echo testing 1 2 3 | gzip >tmpfile1.gz; md5sum tmpfile1.gz; rm tmpfile1.gz + + +# halt - won't test, dangerous + +# head +head tester.sh +head -n 2 tester.sh + +# hostid +hostid + +# hostname +# XXX: minor formatting differences +hostname +hostname -s +hostname -i +hostname -d +# not going to do this next one +#hostname -F + +# id +# BUG: Busybox id doesn't print supplemental groups +id +id -u +id -g +id -ur +id -un + + +# ifconfig +# requires BB_FEATURE_IFCONFIG_STATUS +ifconfig +#ifconfig -a +#ifconfig eth0 +#ifconfig lo + +# init - won't test +# insmod - won't test + +# kill +#kill -l +# not going to do any more + +# length +# ln - see ln_tests.mk +# loadacm +# loadfont +# loadkmap +# logger +# logname + +# ls +# XXX: minor formatting differences +ls ../e* +ls -l ../e* +ls -s ../e* +ls -h ../e* +ls -1 ../e* + +# lsmod +lsmod + +# makedevs + +# md5sum +md5sum tester.sh + +# mkdir +mkdir D ; ls -ld D ; rmdir D + +# mkfifo +# +# we will test making one. actually testing pushing data through it requires +# more interaction than we can manage here. +# (these lines turn up an existing ls bug) +mkfifo F ; ls -l F ; rm F +mkfifo -m 0600 F ; ls -l F ; rm F + +# mkfs.minix - won't test +# mknod +# mkswap - won't test +# mktemp +# more - can't test: interactive + +# mount +# BUG: proc line starts with /proc instead of proc +mount +# not going to test mount with any args, can't be done safely or sanely + +# mt +# mv - see mv_tests.mk +# nc +# nfsmount +# nslookup +# ping +ping -c 3 yahoo.com +# pivot_root +# poweroff - won't test +# printf +# ps - there's lotsa differences between busybox ps and any other ps + +# pwd +pwd + +# rdate - won't test + +# readlink +ln -sf tester.sh L ; readlink L ; rm -f L + +# reboot - won't test +# renice - won't test +# reset - can't test: no output + +# rm +touch F ; rm F + +# rmdir +# rmmod - won't test: dangerous + +# route +# XXX: doesn't DNS resolve +route + +# rpm2cpio + +# sed - we can do some one-liners here, some testing is a little +# difficult to do in just this space (like a,i,c cmds). + +# test ^$ matching +echo foo | sed -ne '/^$/p' +echo -e "foo\\n\\nbar" | sed -ne '/^$/p' + +sed -e '/test$/d' testcases +sed -e '/^echo/d' testcases +sed -e '/test/s/dangerous/PELIGROSO/' testcases +sed -ne '1,/getopt/p' ../pwd.c +sed -e '/getopt/r ../pwd.c' ../sed.c + + +# setkeycodes + +# sh - note that we cannot test the shell interactively here +sh -c "echo a b c" +sh -c ">" +sh -c "a" +sh sh.testcases + + +# sleep - can't test: produces no output + +# sort +sort tester.sh +sort -n tester.sh +sort -r tester.sh + +# stty +# swapon - won't test: dangerous +# swapoff - won't test: dangerous +# sync - can't test: no output +# syslogd - won't test: too involved + +# tail +tail tester.sh +tail -n 2 tester.sh + +# tar + +# tee +echo "please tee me!" | tee A B C ; cat A B C +echo "please tee me!" | tee A B C ; echo "tee me too!" | tee -a A B C ; cat A B C ; rm A B C + +# telnet - can't test: interactive + +# test +# tftp + +# touch +touch tmpfile1; ls tmpfile1; rm -f tmpfile1 +touch -c tmpfile1; ls tmpfile1; rm -f tmpfile1 + +# tr +# BUG: Busybox tr range handling minix style [a-z] instead of GNU # style a-z +echo "cbaab" | tr abc zyx +echo "TESTING A B C" | tr [A-Z] [a-z] +# not GNU compatible +echo fdhrnzvfu bffvsentr | tr [a-z] [n-z][a-m] +echo abc[] | tr a[b AXB +echo testing | tr -d aeiou + +# true +true ; echo $? + +# false +false ; echo $? + +# tty +# umount +# uname +# uniq +# unix2dos +# update + +# uptime +# BUG: doesn't print number of users +uptime + +# usleep +# uudecode +# uuencode +# watchdog + +# wc +wc tester.sh +wc -c tester.sh +wc -w tester.sh +wc -l tester.sh +wc -L tester.sh + +# wget + +# which +which ls + +# whoami +whoami + +# xargs +# XXX: Busygox xargs divides filenames with '\n' instead of ' ' +ls -1 ../e* | xargs +ls -1 ../e* | xargs md5sum + +# yes - can't test: interactive (needs ^C) + diff --git a/tests/tester.sh b/tests/tester.sh new file mode 100755 index 000000000..a767c6c7f --- /dev/null +++ b/tests/tester.sh @@ -0,0 +1,158 @@ +#!/bin/bash +# +# tester.sh - reads testcases from file and tests busybox applets vs GNU +# counterparts +# +# This should be run from within the tests/ directory. Before you run it, you +# should compile up a busybox that has all applets and all features turned on. + +# set up defaults (can be changed with cmd-line options) +BUSYBOX=../busybox +TESTCASES=testcases +LOGFILE=tester.log +BB_OUT=bb.out +GNU_OUT=gnu.out +SETUP="" +CLEANUP="" +KEEPTMPFILES="no" +DEBUG=2 + + +#while getopts 'p:t:l:b:g:s:c:kd:' opt +while getopts 'p:t:l:s:c:kd:' opt +do + case $opt in + p) BUSYBOX=$OPTARG; ;; + t) TESTCASES=$OPTARG; ;; + l) LOGFILE=$OPTARG; ;; +# b) BB_OUT=$OPTARG; ;; +# g) GNU_OUT=$OPTARG; ;; + s) SETUP=$OPTARG; ;; + c) CLEANUP=$OPTARG; ;; + k) KEEPTMPFILES="yes"; ;; + d) DEBUG=$OPTARG; ;; + *) + echo "usage: $0 [-ptlbgsc]" + echo " -p PATH path to busybox executable (default=$BUSYBOX)" + echo " -t FILE run testcases in FILE (default=$TESTCASES)" + echo " -l FILE log test results in FILE (default=$LOGFILE)" +# echo " -b FILE store temporary busybox output in FILE" +# echo " -g FILE store temporary GNU output in FILE" + echo " -s FILE (setup) run commands in FILE before testcases" + echo " -c FILE (cleanup) run commands in FILE after testcases" + echo " -k keep temporary output files (don't delete them)" + echo " -d NUM set level of debugging output" + echo " 0 = no output" + echo " 1 = output failures / whoops lines only" + echo " 2 = (default) output setup / cleanup msgs and testcase lines" + echo " 3+= other debug noise (internal stuff)" + exit 1 + ;; + esac +done +#shift `expr $OPTIND - 1` + + +# maybe print some debug output +if [ $DEBUG -ge 3 ] +then + echo "BUSYBOX=$BUSYBOX" + echo "TESTCASES=$TESTCASES" + echo "LOGFILE=$LOGFILE" + echo "BB_OUT=$BB_OUT" + echo "GNU_OUT=$GNU_OUT" + echo "SETUP=$SETUP" + echo "CLEANUP=$CLEANUP" + echo "DEBUG=$DEBUG" +fi + + +# do sanity checks +if [ ! -e $BUSYBOX ] +then + echo "Busybox executable: $BUSYBOX not found!" + exit 1 +fi + +if [ ! -e $TESTCASES ] +then + echo "Testcases file: $TESTCASES not found!" + exit 1 +fi + + +# do normal setup +[ -e $LOGFILE ] && rm $LOGFILE +unalias -a # gets rid of aliases that might create different output + + +# do extra setup (if any) +if [ ! -z "$SETUP" ] +then + [ $DEBUG -ge 2 ] && echo "running setup commands in $SETUP" + source $SETUP +fi + + +# go through each line in the testcase file +cat $TESTCASES | while read line +do + #echo $line + # only process non-blank lines and non-comment lines + if [ "$line" ] + then + if [ `echo "$line" | cut -c1` != "#" ] + then + + # test if the applet was compiled into busybox + # (this only tests the applet at the beginning of the line) + #applet=`echo $line | cut -d' ' -f1` + applet=`echo $line | sed 's/\(^[^ ;]*\)[ ;].*/\1/'` + $BUSYBOX 2>&1 | grep -qw $applet + if [ $? -eq 1 ] + then + echo "WHOOPS: $applet not compiled into busybox" | tee -a $LOGFILE + else + + # execute line using gnu / system programs + [ $DEBUG -ge 2 ] && echo "testing: $line" | tee -a $LOGFILE + sh -c "$line" > $GNU_OUT + + # change line to include "busybox" before every statement + line="$BUSYBOX $line" + # is this a bash-2-ism? + # line=${line//;/; $BUSYBOX } + # line=${line//|/| $BUSYBOX } + # assume $BUSYBOX has no commas + line=`echo "$line" | sed -e 's,;,; '$BUSYBOX, \ + -e 's, |, | '$BUSYBOX,` + + # execute line using busybox programs + [ $DEBUG -ge 2 ] && echo "testing: $line" | tee -a $LOGFILE + sh -c "$line" > $BB_OUT + + # see if they match + diff -q $BB_OUT $GNU_OUT > /dev/null + if [ $? -eq 1 ] + then + [ $DEBUG -ge 1 ] && echo "FAILED: $line" | tee -a $LOGFILE + diff -u $BB_OUT $GNU_OUT >> $LOGFILE + fi + fi + fi + fi +done + +[ $DEBUG -gt 0 ] && echo "Finished. Results are in $LOGFILE" + + +# do normal cleanup +[ "$KEEPTMPFILES" = "no" ] && rm -f $BB_OUT $GNU_OUT + + +# do extra cleanup (if any) +if [ ! -z "$CLEANUP" ] +then + [ $DEBUG -ge 2 ] && echo "running cleanup commands in $CLEANUP" + source $CLEANUP +fi diff --git a/tests/tst-syslogd.c b/tests/tst-syslogd.c new file mode 100644 index 000000000..bae10afdf --- /dev/null +++ b/tests/tst-syslogd.c @@ -0,0 +1,44 @@ +/* + * tst-syslogd.c - tests concurrent threads calling syslog + * + * build with: gcc -Wall tst-syslogd.c -lpthread + */ + +#include +#include +#include +#include + +void *log_func(void *arg) +{ + int i; + int thrid = (int)arg; + + openlog(NULL, LOG_PERROR | LOG_PID, LOG_USER); + for (i = 0; i < 10; i++) { + syslog(LOG_DEBUG, "thread %i iter %i\n", thrid, i); + sleep(thrid); /* this mixes things up a bit */ + } + closelog(); + + return NULL; +} + +int main(int argc, char **argv) +{ + pthread_t thr1, thr2, thr3; + int id1 = 1; + int id2 = 2; + int id3 = 3; + + pthread_create(&thr1, NULL, log_func, (void *)id1); + pthread_create(&thr2, NULL, log_func, (void *)id2); + pthread_create(&thr3, NULL, log_func, (void *)id3); + + pthread_join(thr1, NULL); + pthread_join(thr2, NULL); + pthread_join(thr3, NULL); + + return 0; +} + diff --git a/tftp.c b/tftp.c new file mode 100644 index 000000000..08535a95c --- /dev/null +++ b/tftp.c @@ -0,0 +1,589 @@ +/* ------------------------------------------------------------------------- */ +/* tftp.c */ +/* */ +/* A simple tftp client for busybox. */ +/* Tries to follow RFC1350. */ +/* Only "octet" mode supported. */ +/* Optional blocksize negotiation (RFC2347 + RFC2348) */ +/* */ +/* Copyright (C) 2001 Magnus Damm */ +/* */ +/* Parts of the code based on: */ +/* */ +/* atftp: Copyright (C) 2000 Jean-Pierre Lefebvre */ +/* and Remi Lefebvre */ +/* */ +/* utftp: Copyright (C) 1999 Uwe Ohse */ +/* */ +/* 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 +#include +#include + +#include "busybox.h" + +//#define BB_FEATURE_TFTP_GET +//#define BB_FEATURE_TFTP_PUT +//#define BB_FEATURE_TFTP_BLOCKSIZE +//#define BB_FEATURE_TFTP_DEBUG + +#define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */ +#define TFTP_TIMEOUT 5 /* seconds */ + +/* opcodes we support */ + +#define TFTP_RRQ 1 +#define TFTP_WRQ 2 +#define TFTP_DATA 3 +#define TFTP_ACK 4 +#define TFTP_ERROR 5 +#define TFTP_OACK 6 + +static const char *tftp_error_msg[] = { + "Undefined error", + "File not found", + "Access violation", + "Disk full or allocation error", + "Illegal TFTP operation", + "Unknown transfer ID", + "File already exists", + "No such user" +}; + +const int tftp_cmd_get = 1; +const int tftp_cmd_put = 2; + +#ifdef BB_FEATURE_TFTP_BLOCKSIZE + +static int tftp_blocksize_check(int blocksize, int bufsize) +{ + /* Check if the blocksize is valid: + * RFC2348 says between 8 and 65464, + * but our implementation makes it impossible + * to use blocksizes smaller than 22 octets. + */ + + if ((bufsize && (blocksize > bufsize)) || + (blocksize < 8) || (blocksize > 65464)) { + error_msg("bad blocksize"); + return 0; + } + + return blocksize; +} + +static char *tftp_option_get(char *buf, int len, char *option) +{ + int opt_val = 0; + int opt_found = 0; + int k; + + while (len > 0) { + + /* Make sure the options are terminated correctly */ + + for (k = 0; k < len; k++) { + if (buf[k] == '\0') { + break; + } + } + + if (k >= len) { + break; + } + + if (opt_val == 0) { + if (strcasecmp(buf, option) == 0) { + opt_found = 1; + } + } + else { + if (opt_found) { + return buf; + } + } + + k++; + + buf += k; + len -= k; + + opt_val ^= 1; + } + + return NULL; +} + +#endif + +static inline int tftp(const int cmd, const struct hostent *host, + const char *remotefile, int localfd, const int port, int tftp_bufsize) +{ + const int cmd_get = cmd & tftp_cmd_get; + const int cmd_put = cmd & tftp_cmd_put; + const int bb_tftp_num_retries = 5; + + struct sockaddr_in sa; + struct sockaddr_in from; + struct timeval tv; + socklen_t fromlen; + fd_set rfds; + char *cp; + unsigned short tmp; + int socketfd; + int len; + int opcode = 0; + int finished = 0; + int timeout = bb_tftp_num_retries; + int block_nr = 1; + +#ifdef BB_FEATURE_TFTP_BLOCKSIZE + int want_option_ack = 0; +#endif + + /* Can't use RESERVE_BB_BUFFER here since the allocation + * size varies meaning BUFFERS_GO_ON_STACK would fail */ + char *buf=xmalloc(tftp_bufsize + 4); + + tftp_bufsize += 4; + + if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + perror_msg("socket"); + return EXIT_FAILURE; + } + + len = sizeof(sa); + + memset(&sa, 0, len); + bind(socketfd, (struct sockaddr *)&sa, len); + + sa.sin_family = host->h_addrtype; + sa.sin_port = htons(port); + memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr, + sizeof(sa.sin_addr)); + + /* build opcode */ + + if (cmd_get) { + opcode = TFTP_RRQ; + } + + if (cmd_put) { + opcode = TFTP_WRQ; + } + + while (1) { + + cp = buf; + + /* first create the opcode part */ + + *((unsigned short *) cp) = htons(opcode); + + cp += 2; + + /* add filename and mode */ + + if ((cmd_get && (opcode == TFTP_RRQ)) || + (cmd_put && (opcode == TFTP_WRQ))) { + int too_long = 0; + + /* see if the filename fits into buf */ + /* and fill in packet */ + + len = strlen(remotefile) + 1; + + if ((cp + len) >= &buf[tftp_bufsize - 1]) { + too_long = 1; + } + else { + safe_strncpy(cp, remotefile, len); + cp += len; + } + + if (too_long || ((&buf[tftp_bufsize - 1] - cp) < 6)) { + error_msg("too long remote-filename"); + break; + } + + /* add "mode" part of the package */ + + memcpy(cp, "octet", 6); + cp += 6; + +#ifdef BB_FEATURE_TFTP_BLOCKSIZE + + len = tftp_bufsize - 4; /* data block size */ + + if (len != TFTP_BLOCKSIZE_DEFAULT) { + + if ((&buf[tftp_bufsize - 1] - cp) < 15) { + error_msg("too long remote-filename"); + break; + } + + /* add "blksize" + number of blocks */ + + memcpy(cp, "blksize", 8); + cp += 8; + + cp += snprintf(cp, 6, "%d", len) + 1; + + want_option_ack = 1; + } +#endif + } + + /* add ack and data */ + + if ((cmd_get && (opcode == TFTP_ACK)) || + (cmd_put && (opcode == TFTP_DATA))) { + + *((unsigned short *) cp) = htons(block_nr); + + cp += 2; + + block_nr++; + + if (cmd_put && (opcode == TFTP_DATA)) { + len = read(localfd, cp, tftp_bufsize - 4); + + if (len < 0) { + perror_msg("read"); + break; + } + + if (len != (tftp_bufsize - 4)) { + finished++; + } + + cp += len; + } else if (finished) { + break; + } + } + + + /* send packet */ + + + do { + + len = cp - buf; + +#ifdef BB_FEATURE_TFTP_DEBUG + printf("sending %u bytes\n", len); + for (cp = buf; cp < &buf[len]; cp++) + printf("%02x ", *cp); + printf("\n"); +#endif + if (sendto(socketfd, buf, len, 0, + (struct sockaddr *) &sa, sizeof(sa)) < 0) { + perror_msg("send"); + len = -1; + break; + } + + + /* receive packet */ + + + memset(&from, 0, sizeof(from)); + fromlen = sizeof(from); + + tv.tv_sec = TFTP_TIMEOUT; + tv.tv_usec = 0; + + FD_ZERO(&rfds); + FD_SET(socketfd, &rfds); + + switch (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) { + case 1: + len = recvfrom(socketfd, buf, tftp_bufsize, 0, + (struct sockaddr *) &from, &fromlen); + + if (len < 0) { + perror_msg("recvfrom"); + break; + } + + timeout = 0; + + if (sa.sin_port == htons(port)) { + sa.sin_port = from.sin_port; + } + if (sa.sin_port == from.sin_port) { + break; + } + + /* fall-through for bad packets! */ + /* discard the packet - treat as timeout */ + timeout = bb_tftp_num_retries; + + case 0: + error_msg("timeout"); + + if (timeout == 0) { + len = -1; + error_msg("last timeout"); + } else { + timeout--; + } + break; + + default: + perror_msg("select"); + len = -1; + } + + } while (timeout && (len >= 0)); + + if (len < 0) { + break; + } + + /* process received packet */ + + + opcode = ntohs(*((unsigned short *) buf)); + tmp = ntohs(*((unsigned short *) &buf[2])); + +#ifdef BB_FEATURE_TFTP_DEBUG + printf("received %d bytes: %04x %04x\n", len, opcode, tmp); +#endif + + if (opcode == TFTP_ERROR) { + char *msg = NULL; + + if (buf[4] != '\0') { + msg = &buf[4]; + buf[tftp_bufsize - 1] = '\0'; + } else if (tmp < (sizeof(tftp_error_msg) + / sizeof(char *))) { + + msg = (char *) tftp_error_msg[tmp]; + } + + if (msg) { + error_msg("server says: %s", msg); + } + + break; + } + +#ifdef BB_FEATURE_TFTP_BLOCKSIZE + if (want_option_ack) { + + want_option_ack = 0; + + if (opcode == TFTP_OACK) { + + /* server seems to support options */ + + char *res; + + res = tftp_option_get(&buf[2], len-2, + "blksize"); + + if (res) { + int foo = atoi(res); + + if (tftp_blocksize_check(foo, + tftp_bufsize - 4)) { + + if (cmd_put) { + opcode = TFTP_DATA; + } + else { + opcode = TFTP_ACK; + } +#ifdef BB_FEATURE_TFTP_DEBUG + printf("using blksize %u\n"); +#endif + tftp_bufsize = foo + 4; + block_nr = 0; + continue; + } + } + /* FIXME: + * we should send ERROR 8 */ + error_msg("bad server option"); + break; + } + + error_msg("warning: blksize not supported by server" + " - reverting to 512"); + + tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4; + } +#endif + + if (cmd_get && (opcode == TFTP_DATA)) { + + if (tmp == block_nr) { + + len = write(localfd, &buf[4], len - 4); + + if (len < 0) { + perror_msg("write"); + break; + } + + if (len != (tftp_bufsize - 4)) { + finished++; + } + + opcode = TFTP_ACK; + continue; + } + } + + if (cmd_put && (opcode == TFTP_ACK)) { + + if (tmp == (block_nr - 1)) { + if (finished) { + break; + } + + opcode = TFTP_DATA; + continue; + } + } + } + +#ifdef BB_FEATURE_CLEAN_UP + close(socketfd); + + free(buf); +#endif + + return finished ? EXIT_SUCCESS : EXIT_FAILURE; +} + +int tftp_main(int argc, char **argv) +{ + struct hostent *host = NULL; + char *localfile = NULL; + char *remotefile = NULL; + int port = 69; + int cmd = 0; + int fd = -1; + int flags = 0; + int opt; + int result; + int blocksize = TFTP_BLOCKSIZE_DEFAULT; + + /* figure out what to pass to getopt */ + +#ifdef BB_FEATURE_TFTP_BLOCKSIZE +#define BS "b:" +#else +#define BS +#endif + +#ifdef BB_FEATURE_TFTP_GET +#define GET "g" +#else +#define GET +#endif + +#ifdef BB_FEATURE_TFTP_PUT +#define PUT "p" +#else +#define PUT +#endif + + while ((opt = getopt(argc, argv, BS GET PUT "l:r:")) != -1) { + switch (opt) { +#ifdef BB_FEATURE_TFTP_BLOCKSIZE + case 'b': + blocksize = atoi(optarg); + if (!tftp_blocksize_check(blocksize, 0)) { + return EXIT_FAILURE; + } + break; +#endif +#ifdef BB_FEATURE_TFTP_GET + case 'g': + cmd = tftp_cmd_get; + flags = O_WRONLY | O_CREAT; + break; +#endif +#ifdef BB_FEATURE_TFTP_PUT + case 'p': + cmd = tftp_cmd_put; + flags = O_RDONLY; + break; +#endif + case 'l': + localfile = xstrdup(optarg); + break; + case 'r': + remotefile = xstrdup(optarg); + break; + } + } + + if ((cmd == 0) || (optind == argc)) { + show_usage(); + } + if(localfile && strcmp(localfile, "-") == 0) { + fd = fileno((cmd==tftp_cmd_get)? stdout : stdin); + } + if(localfile == NULL) + localfile = remotefile; + if(remotefile == NULL) + remotefile = localfile; + if (fd==-1) { + fd = open(localfile, flags, 0644); + } + if (fd < 0) { + perror_msg_and_die("local file"); + } + + host = xgethostbyname(argv[optind]); + + if (optind + 2 == argc) { + port = atoi(argv[optind + 1]); + } + +#ifdef BB_FEATURE_TFTP_DEBUG + printf("using server \"%s\", remotefile \"%s\", " + "localfile \"%s\".\n", + inet_ntoa(*((struct in_addr *) host->h_addr)), + remotefile, localfile); +#endif + + result = tftp(cmd, host, remotefile, fd, port, blocksize); + +#ifdef BB_FEATURE_CLEAN_UP + if (!(fd == fileno(stdout) || fd == fileno(stdin))) { + close(fd); + } +#endif + return(result); +} diff --git a/time.c b/time.c new file mode 100644 index 000000000..fa352a899 --- /dev/null +++ b/time.c @@ -0,0 +1,502 @@ +/* `time' utility to display resource usage of processes. + Copyright (C) 1990, 91, 92, 93, 96 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. */ + +/* Originally written by David Keppel . + Heavily modified by David MacKenzie . + Heavily modified for busybox by Erik Andersen + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For pid_t. */ +#include +#include /* For getpagesize, maybe. */ + +#define TV_MSEC tv_usec / 1000 +#include +#include "busybox.h" + +/* Information on the resources used by a child process. */ +typedef struct +{ + int waitstatus; + struct rusage ru; + struct timeval start, elapsed; /* Wallclock time of process. */ +} resource_t; + +/* msec = milliseconds = 1/1,000 (1*10e-3) second. + usec = microseconds = 1/1,000,000 (1*10e-6) second. */ + +#ifndef TICKS_PER_SEC +#define TICKS_PER_SEC 100 +#endif + +/* The number of milliseconds in one `tick' used by the `rusage' structure. */ +#define MSEC_PER_TICK (1000 / TICKS_PER_SEC) + +/* Return the number of clock ticks that occur in M milliseconds. */ +#define MSEC_TO_TICKS(m) ((m) / MSEC_PER_TICK) + +#define UL unsigned long + +static const char *const default_format = "real\t%E\nuser\t%u\nsys\t%T"; + +/* The output format for the -p option .*/ +static const char *const posix_format = "real %e\nuser %U\nsys %S"; + + +/* Format string for printing all statistics verbosely. + Keep this output to 24 lines so users on terminals can see it all.*/ +static const char *const long_format = + "\tCommand being timed: \"%C\"\n" + "\tUser time (seconds): %U\n" + "\tSystem time (seconds): %S\n" + "\tPercent of CPU this job got: %P\n" + "\tElapsed (wall clock) time (h:mm:ss or m:ss): %E\n" + "\tAverage shared text size (kbytes): %X\n" + "\tAverage unshared data size (kbytes): %D\n" + "\tAverage stack size (kbytes): %p\n" + "\tAverage total size (kbytes): %K\n" + "\tMaximum resident set size (kbytes): %M\n" + "\tAverage resident set size (kbytes): %t\n" + "\tMajor (requiring I/O) page faults: %F\n" + "\tMinor (reclaiming a frame) page faults: %R\n" + "\tVoluntary context switches: %w\n" + "\tInvoluntary context switches: %c\n" + "\tSwaps: %W\n" + "\tFile system inputs: %I\n" + "\tFile system outputs: %O\n" + "\tSocket messages sent: %s\n" + "\tSocket messages received: %r\n" + "\tSignals delivered: %k\n" + "\tPage size (bytes): %Z\n" + "\tExit status: %x"; + + + /* Wait for and fill in data on child process PID. + Return 0 on error, 1 if ok. */ + +/* pid_t is short on BSDI, so don't try to promote it. */ +static int resuse_end (pid_t pid, resource_t *resp) +{ + int status; + + pid_t caught; + + /* Ignore signals, but don't ignore the children. When wait3 + returns the child process, set the time the command finished. */ + while ((caught = wait3 (&status, 0, &resp->ru)) != pid) + { + if (caught == -1) + return 0; + } + + gettimeofday (&resp->elapsed, (struct timezone *) 0); + resp->elapsed.tv_sec -= resp->start.tv_sec; + if (resp->elapsed.tv_usec < resp->start.tv_usec) + { + /* Manually carry a one from the seconds field. */ + resp->elapsed.tv_usec += 1000000; + --resp->elapsed.tv_sec; + } + resp->elapsed.tv_usec -= resp->start.tv_usec; + + resp->waitstatus = status; + + return 1; +} + +/* Print ARGV to FP, with each entry in ARGV separated by FILLER. */ +static void fprintargv (FILE *fp, char *const *argv, const char *filler) +{ + char *const *av; + + av = argv; + fputs (*av, fp); + while (*++av) + { + fputs (filler, fp); + fputs (*av, fp); + } + if (ferror (fp)) + error_msg_and_die("write error"); +} + +/* Return the number of kilobytes corresponding to a number of pages PAGES. + (Actually, we use it to convert pages*ticks into kilobytes*ticks.) + + Try to do arithmetic so that the risk of overflow errors is minimized. + This is funky since the pagesize could be less than 1K. + Note: Some machines express getrusage statistics in terms of K, + others in terms of pages. */ + +static unsigned long ptok (unsigned long pages) +{ + static unsigned long ps = 0; + unsigned long tmp; + static long size = LONG_MAX; + + /* Initialization. */ + if (ps == 0) + ps = (long) getpagesize (); + + /* Conversion. */ + if (pages > (LONG_MAX / ps)) + { /* Could overflow. */ + tmp = pages / 1024; /* Smaller first, */ + size = tmp * ps; /* then larger. */ + } + else + { /* Could underflow. */ + tmp = pages * ps; /* Larger first, */ + size = tmp / 1024; /* then smaller. */ + } + return size; +} + +/* summarize: Report on the system use of a command. + + Copy the FMT argument to FP except that `%' sequences + have special meaning, and `\n' and `\t' are translated into + newline and tab, respectively, and `\\' is translated into `\'. + + The character following a `%' can be: + (* means the tcsh time builtin also recognizes it) + % == a literal `%' + C == command name and arguments +* D == average unshared data size in K (ru_idrss+ru_isrss) +* E == elapsed real (wall clock) time in [hour:]min:sec +* F == major page faults (required physical I/O) (ru_majflt) +* I == file system inputs (ru_inblock) +* K == average total mem usage (ru_idrss+ru_isrss+ru_ixrss) +* M == maximum resident set size in K (ru_maxrss) +* O == file system outputs (ru_oublock) +* P == percent of CPU this job got (total cpu time / elapsed time) +* R == minor page faults (reclaims; no physical I/O involved) (ru_minflt) +* S == system (kernel) time (seconds) (ru_stime) +* T == system time in [hour:]min:sec +* U == user time (seconds) (ru_utime) +* u == user time in [hour:]min:sec +* W == times swapped out (ru_nswap) +* X == average amount of shared text in K (ru_ixrss) + Z == page size +* c == involuntary context switches (ru_nivcsw) + e == elapsed real time in seconds +* k == signals delivered (ru_nsignals) + p == average unshared stack size in K (ru_isrss) +* r == socket messages received (ru_msgrcv) +* s == socket messages sent (ru_msgsnd) + t == average resident set size in K (ru_idrss) +* w == voluntary context switches (ru_nvcsw) + x == exit status of command + + Various memory usages are found by converting from page-seconds + to kbytes by multiplying by the page size, dividing by 1024, + and dividing by elapsed real time. + + FP is the stream to print to. + FMT is the format string, interpreted as described above. + COMMAND is the command and args that are being summarized. + RESP is resource information on the command. */ + +static void summarize (FILE *fp, const char *fmt, char **command, resource_t *resp) +{ + unsigned long r; /* Elapsed real milliseconds. */ + unsigned long v; /* Elapsed virtual (CPU) milliseconds. */ + + if (WIFSTOPPED (resp->waitstatus)) + fprintf (fp, "Command stopped by signal %d\n", WSTOPSIG (resp->waitstatus)); + else if (WIFSIGNALED (resp->waitstatus)) + fprintf (fp, "Command terminated by signal %d\n", WTERMSIG (resp->waitstatus)); + else if (WIFEXITED (resp->waitstatus) && WEXITSTATUS (resp->waitstatus)) + fprintf (fp, "Command exited with non-zero status %d\n", WEXITSTATUS (resp->waitstatus)); + + /* Convert all times to milliseconds. Occasionally, one of these values + comes out as zero. Dividing by zero causes problems, so we first + check the time value. If it is zero, then we take `evasive action' + instead of calculating a value. */ + + r = resp->elapsed.tv_sec * 1000 + resp->elapsed.tv_usec / 1000; + + v = resp->ru.ru_utime.tv_sec * 1000 + resp->ru.ru_utime.TV_MSEC + + resp->ru.ru_stime.tv_sec * 1000 + resp->ru.ru_stime.TV_MSEC; + + while (*fmt) + { + switch (*fmt) + { + case '%': + switch (*++fmt) + { + case '%': /* Literal '%'. */ + putc ('%', fp); + break; + case 'C': /* The command that got timed. */ + fprintargv (fp, command, " "); + break; + case 'D': /* Average unshared data size. */ + fprintf (fp, "%lu", + MSEC_TO_TICKS (v) == 0 ? 0 : + ptok ((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS (v) + + ptok ((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS (v)); + break; + case 'E': /* Elapsed real (wall clock) time. */ + if (resp->elapsed.tv_sec >= 3600) /* One hour -> h:m:s. */ + fprintf (fp, "%ldh %ldm %02lds", + resp->elapsed.tv_sec / 3600, + (resp->elapsed.tv_sec % 3600) / 60, + resp->elapsed.tv_sec % 60); + else + fprintf (fp, "%ldm %ld.%02lds", /* -> m:s. */ + resp->elapsed.tv_sec / 60, + resp->elapsed.tv_sec % 60, + resp->elapsed.tv_usec / 10000); + break; + case 'F': /* Major page faults. */ + fprintf (fp, "%ld", resp->ru.ru_majflt); + break; + case 'I': /* Inputs. */ + fprintf (fp, "%ld", resp->ru.ru_inblock); + break; + case 'K': /* Average mem usage == data+stack+text. */ + fprintf (fp, "%lu", + MSEC_TO_TICKS (v) == 0 ? 0 : + ptok ((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS (v) + + ptok ((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS (v) + + ptok ((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS (v)); + break; + case 'M': /* Maximum resident set size. */ + fprintf (fp, "%lu", ptok ((UL) resp->ru.ru_maxrss)); + break; + case 'O': /* Outputs. */ + fprintf (fp, "%ld", resp->ru.ru_oublock); + break; + case 'P': /* Percent of CPU this job got. */ + /* % cpu is (total cpu time)/(elapsed time). */ + if (r > 0) + fprintf (fp, "%lu%%", (v * 100 / r)); + else + fprintf (fp, "?%%"); + break; + case 'R': /* Minor page faults (reclaims). */ + fprintf (fp, "%ld", resp->ru.ru_minflt); + break; + case 'S': /* System time. */ + fprintf (fp, "%ld.%02ld", + resp->ru.ru_stime.tv_sec, + resp->ru.ru_stime.TV_MSEC / 10); + break; + case 'T': /* System time. */ + if (resp->ru.ru_stime.tv_sec >= 3600) /* One hour -> h:m:s. */ + fprintf (fp, "%ldh %ldm %02lds", + resp->ru.ru_stime.tv_sec / 3600, + (resp->ru.ru_stime.tv_sec % 3600) / 60, + resp->ru.ru_stime.tv_sec % 60); + else + fprintf (fp, "%ldm %ld.%02lds", /* -> m:s. */ + resp->ru.ru_stime.tv_sec / 60, + resp->ru.ru_stime.tv_sec % 60, + resp->ru.ru_stime.tv_usec / 10000); + break; + case 'U': /* User time. */ + fprintf (fp, "%ld.%02ld", + resp->ru.ru_utime.tv_sec, + resp->ru.ru_utime.TV_MSEC / 10); + break; + case 'u': /* User time. */ + if (resp->ru.ru_utime.tv_sec >= 3600) /* One hour -> h:m:s. */ + fprintf (fp, "%ldh %ldm %02lds", + resp->ru.ru_utime.tv_sec / 3600, + (resp->ru.ru_utime.tv_sec % 3600) / 60, + resp->ru.ru_utime.tv_sec % 60); + else + fprintf (fp, "%ldm %ld.%02lds", /* -> m:s. */ + resp->ru.ru_utime.tv_sec / 60, + resp->ru.ru_utime.tv_sec % 60, + resp->ru.ru_utime.tv_usec / 10000); + break; + case 'W': /* Times swapped out. */ + fprintf (fp, "%ld", resp->ru.ru_nswap); + break; + case 'X': /* Average shared text size. */ + fprintf (fp, "%lu", + MSEC_TO_TICKS (v) == 0 ? 0 : + ptok ((UL) resp->ru.ru_ixrss) / MSEC_TO_TICKS (v)); + break; + case 'Z': /* Page size. */ + fprintf (fp, "%d", getpagesize ()); + break; + case 'c': /* Involuntary context switches. */ + fprintf (fp, "%ld", resp->ru.ru_nivcsw); + break; + case 'e': /* Elapsed real time in seconds. */ + fprintf (fp, "%ld.%02ld", + resp->elapsed.tv_sec, + resp->elapsed.tv_usec / 10000); + break; + case 'k': /* Signals delivered. */ + fprintf (fp, "%ld", resp->ru.ru_nsignals); + break; + case 'p': /* Average stack segment. */ + fprintf (fp, "%lu", + MSEC_TO_TICKS (v) == 0 ? 0 : + ptok ((UL) resp->ru.ru_isrss) / MSEC_TO_TICKS (v)); + break; + case 'r': /* Incoming socket messages received. */ + fprintf (fp, "%ld", resp->ru.ru_msgrcv); + break; + case 's': /* Outgoing socket messages sent. */ + fprintf (fp, "%ld", resp->ru.ru_msgsnd); + break; + case 't': /* Average resident set size. */ + fprintf (fp, "%lu", + MSEC_TO_TICKS (v) == 0 ? 0 : + ptok ((UL) resp->ru.ru_idrss) / MSEC_TO_TICKS (v)); + break; + case 'w': /* Voluntary context switches. */ + fprintf (fp, "%ld", resp->ru.ru_nvcsw); + break; + case 'x': /* Exit status. */ + fprintf (fp, "%d", WEXITSTATUS (resp->waitstatus)); + break; + case '\0': + putc ('?', fp); + return; + default: + putc ('?', fp); + putc (*fmt, fp); + } + ++fmt; + break; + + case '\\': /* Format escape. */ + switch (*++fmt) + { + case 't': + putc ('\t', fp); + break; + case 'n': + putc ('\n', fp); + break; + case '\\': + putc ('\\', fp); + break; + default: + putc ('?', fp); + putc ('\\', fp); + putc (*fmt, fp); + } + ++fmt; + break; + + default: + putc (*fmt++, fp); + } + + if (ferror (fp)) + error_msg_and_die("write error"); + } + putc ('\n', fp); + + if (ferror (fp)) + error_msg_and_die("write error"); +} + +/* Run command CMD and return statistics on it. + Put the statistics in *RESP. */ +static void run_command (char *const *cmd, resource_t *resp) +{ + pid_t pid; /* Pid of child. */ + __sighandler_t interrupt_signal, quit_signal; + + gettimeofday (&resp->start, (struct timezone *) 0); + pid = fork (); /* Run CMD as child process. */ + if (pid < 0) + error_msg_and_die("cannot fork"); + else if (pid == 0) + { /* If child. */ + /* Don't cast execvp arguments; that causes errors on some systems, + versus merely warnings if the cast is left off. */ + execvp (cmd[0], cmd); + error_msg("cannot run %s", cmd[0]); + _exit (errno == ENOENT ? 127 : 126); + } + + /* Have signals kill the child but not self (if possible). */ + interrupt_signal = signal (SIGINT, SIG_IGN); + quit_signal = signal (SIGQUIT, SIG_IGN); + + if (resuse_end (pid, resp) == 0) + error_msg("error waiting for child process"); + + /* Re-enable signals. */ + signal (SIGINT, interrupt_signal); + signal (SIGQUIT, quit_signal); +} + +extern int time_main (int argc, char **argv) +{ + int gotone; + resource_t res; + const char *output_format = default_format; + + argc--; + argv++; + /* Parse any options -- don't use getopt() here so we don't + * consume the args of our client application... */ + while (argc > 0 && **argv == '-') { + gotone = 0; + while (gotone==0 && *++(*argv)) { + switch (**argv) { + case 'v': + output_format = long_format; + break; + case 'p': + output_format = posix_format; + break; + default: + show_usage(); + } + argc--; + argv++; + gotone = 1; + } + } + + if (argv == NULL || *argv == NULL) + show_usage(); + + run_command (argv, &res); + summarize (stdout, output_format, argv, &res); + fflush (stdout); + + if (WIFSTOPPED (res.waitstatus)) + exit (WSTOPSIG (res.waitstatus)); + else if (WIFSIGNALED (res.waitstatus)) + exit (WTERMSIG (res.waitstatus)); + else if (WIFEXITED (res.waitstatus)) + exit (WEXITSTATUS (res.waitstatus)); + return 0; +} diff --git a/top.c b/top.c new file mode 100644 index 000000000..e992d23fa --- /dev/null +++ b/top.c @@ -0,0 +1,739 @@ +/* + * A tiny 'top' utility. + * + * This is written specifically for the linux /proc//stat(m) + * files format. + + * This reads the PIDs of all processes and their status and shows + * the status of processes (first ones that fit to screen) at given + * intervals. + * + * NOTES: + * - At startup this changes to /proc, all the reads are then + * relative to that. + * + * (C) Eero Tamminen + * + * Rewroted by Vladimir Oleynik (C) 2002 + */ + +/* Original code Copyrights */ +/* + * Copyright (c) 1992 Branko Lankester + * Copyright (c) 1992 Roger Binns + * Copyright (C) 1994-1996 Charles L. Blake. + * Copyright (C) 1992-1998 Michael K. Johnson + * May be distributed under the conditions of the + * GNU Library General Public License + */ + +#include +#include +#include +#include +#include +#include +#include +#include +/* get page info */ +#include +#include "busybox.h" + +#define FEATURE_CPU_USAGE_PERCENTAGE /* + 2k */ + +#ifdef FEATURE_CPU_USAGE_PERCENTAGE +#include +#include +#include +#include /* htons */ +#endif + + +typedef struct { + int pid; + char user[9]; + char state[4]; + unsigned long rss; + int ppid; +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + unsigned pcpu; + unsigned long stime, utime; +#endif + char *cmd; + + /* basename of executable file in call to exec(2), + size from kernel headers */ + char short_cmd[16]; +} status_t; + +typedef int (*cmp_t)(status_t *P, status_t *Q); + +static status_t *top; /* Hehe */ +static int ntop; + + +static int pid_sort (status_t *P, status_t *Q) +{ + int p = P->pid; + int q = Q->pid; + + if( p < q ) return -1; + if( p > q ) return 1; + return 0; +} + +static int mem_sort (status_t *P, status_t *Q) +{ + long p = P->rss; + long q = Q->rss; + + if( p > q ) return -1; + if( p < q ) return 1; + return 0; +} + +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + +#define sort_depth 3 +static cmp_t sort_function[sort_depth]; + +static int pcpu_sort (status_t *P, status_t *Q) +{ + int p = P->pcpu; + int q = Q->pcpu; + + if( p > q ) return -1; + if( p < q ) return 1; + return 0; +} + +static int time_sort (status_t *P, status_t *Q) +{ + long p = P->stime; + long q = Q->stime; + + p += P->utime; + q += Q->utime; + if( p > q ) return -1; + if( p < q ) return 1; + return 0; +} + +int mult_lvl_cmp(void* a, void* b) { + int i, cmp_val; + + for(i = 0; i < sort_depth; i++) { + cmp_val = (*sort_function[i])(a, b); + if (cmp_val != 0) + return cmp_val; + } + return 0; +} + +/* This structure stores some critical information from one frame to + the next. mostly used for sorting. Added cumulative and resident fields. */ +struct save_hist { + int ticks; + int pid; + int utime; + int stime; +}; + +/* + * Calculates percent cpu usage for each task. + */ + +static struct save_hist *save_history; + +static unsigned long Hertz; + +/*********************************************************************** + * Some values in /proc are expressed in units of 1/HZ seconds, where HZ + * is the kernel clock tick rate. One of these units is called a jiffy. + * The HZ value used in the kernel may vary according to hacker desire. + * According to Linus Torvalds, this is not true. He considers the values + * in /proc as being in architecture-dependant units that have no relation + * to the kernel clock tick rate. Examination of the kernel source code + * reveals that opinion as wishful thinking. + * + * In any case, we need the HZ constant as used in /proc. (the real HZ value + * may differ, but we don't care) There are several ways we could get HZ: + * + * 1. Include the kernel header file. If it changes, recompile this library. + * 2. Use the sysconf() function. When HZ changes, recompile the C library! + * 3. Ask the kernel. This is obviously correct... + * + * Linus Torvalds won't let us ask the kernel, because he thinks we should + * not know the HZ value. Oh well, we don't have to listen to him. + * Someone smuggled out the HZ value. :-) + * + * This code should work fine, even if Linus fixes the kernel to match his + * stated behavior. The code only fails in case of a partial conversion. + * + */ + +#define FILE_TO_BUF(filename, fd) do{ \ + if (fd == -1 && (fd = open(filename, O_RDONLY)) == -1) { \ + perror_msg_and_die("/proc not be mounted?"); \ + } \ + lseek(fd, 0L, SEEK_SET); \ + if ((local_n = read(fd, buf, sizeof buf - 1)) < 0) { \ + perror_msg_and_die("%s", filename); \ + } \ + buf[local_n] = '\0'; \ +}while(0) + +#define FILE_TO_BUF2(filename, fd) do{ \ + lseek(fd, 0L, SEEK_SET); \ + if ((local_n = read(fd, buf, sizeof buf - 1)) < 0) { \ + perror_msg_and_die("%s", filename); \ + } \ + buf[local_n] = '\0'; \ +}while(0) + +static void init_Hertz_value(void) { + unsigned long user_j, nice_j, sys_j, other_j; /* jiffies (clock ticks) */ + double up_1, up_2, seconds; + unsigned long jiffies, h; + char buf[80]; + int uptime_fd = -1; + int stat_fd = -1; + + long smp_num_cpus = sysconf(_SC_NPROCESSORS_CONF); + + if(smp_num_cpus<1) smp_num_cpus=1; + do { + int local_n; + + FILE_TO_BUF("uptime", uptime_fd); + up_1 = strtod(buf, 0); + FILE_TO_BUF("stat", stat_fd); + sscanf(buf, "cpu %lu %lu %lu %lu", &user_j, &nice_j, &sys_j, &other_j); + FILE_TO_BUF2("uptime", uptime_fd); + up_2 = strtod(buf, 0); + } while((long)( (up_2-up_1)*1000.0/up_1 )); /* want under 0.1% error */ + + close(uptime_fd); + close(stat_fd); + + jiffies = user_j + nice_j + sys_j + other_j; + seconds = (up_1 + up_2) / 2; + h = (unsigned long)( (double)jiffies/seconds/smp_num_cpus ); + /* actual values used by 2.4 kernels: 32 64 100 128 1000 1024 1200 */ + switch(h){ + case 30 ... 34 : Hertz = 32; break; /* ia64 emulator */ + case 48 ... 52 : Hertz = 50; break; + case 58 ... 62 : Hertz = 60; break; + case 63 ... 65 : Hertz = 64; break; /* StrongARM /Shark */ + case 95 ... 105 : Hertz = 100; break; /* normal Linux */ + case 124 ... 132 : Hertz = 128; break; /* MIPS, ARM */ + case 195 ... 204 : Hertz = 200; break; /* normal << 1 */ + case 253 ... 260 : Hertz = 256; break; + case 295 ... 304 : Hertz = 300; break; /* 3 cpus */ + case 393 ... 408 : Hertz = 400; break; /* normal << 2 */ + case 495 ... 504 : Hertz = 500; break; /* 5 cpus */ + case 595 ... 604 : Hertz = 600; break; /* 6 cpus */ + case 695 ... 704 : Hertz = 700; break; /* 7 cpus */ + case 790 ... 808 : Hertz = 800; break; /* normal << 3 */ + case 895 ... 904 : Hertz = 900; break; /* 9 cpus */ + case 990 ... 1010 : Hertz = 1000; break; /* ARM */ + case 1015 ... 1035 : Hertz = 1024; break; /* Alpha, ia64 */ + case 1095 ... 1104 : Hertz = 1100; break; /* 11 cpus */ + case 1180 ... 1220 : Hertz = 1200; break; /* Alpha */ + default: + /* If 32-bit or big-endian (not Alpha or ia64), assume HZ is 100. */ + Hertz = (sizeof(long)==sizeof(int) || htons(999)==999) ? 100UL : 1024UL; + } +} + +static void do_stats(void) +{ + struct timeval t; + static struct timeval oldtime; + struct timezone timez; + float elapsed_time; + + status_t *cur; + int total_time, i, n; + static int prev_count; + int systime, usrtime, pid; + + struct save_hist *New_save_hist; + + /* + * Finds the current time (in microseconds) and calculates the time + * elapsed since the last update. + */ + gettimeofday(&t, &timez); + elapsed_time = (t.tv_sec - oldtime.tv_sec) + + (float) (t.tv_usec - oldtime.tv_usec) / 1000000.0; + oldtime.tv_sec = t.tv_sec; + oldtime.tv_usec = t.tv_usec; + + New_save_hist = alloca(sizeof(struct save_hist)*ntop); + /* + * Make a pass through the data to get stats. + */ + for(n = 0; n < ntop; n++) { + cur = top + n; + + /* + * Calculate time in cur process. Time is sum of user time + * (usrtime) plus system time (systime). + */ + systime = cur->stime; + usrtime = cur->utime; + pid = cur->pid; + total_time = systime + usrtime; + New_save_hist[n].ticks = total_time; + New_save_hist[n].pid = pid; + New_save_hist[n].stime = systime; + New_save_hist[n].utime = usrtime; + + /* find matching entry from previous pass */ + for (i = 0; i < prev_count; i++) { + if (save_history[i].pid == pid) { + total_time -= save_history[i].ticks; + systime -= save_history[i].stime; + usrtime -= save_history[i].utime; + break; + } + } + + /* + * Calculate percent cpu time for cur task. + */ + i = (total_time * 10 * 100/Hertz) / elapsed_time; + if (i > 999) + i = 999; + cur->pcpu = i; + + } + + /* + * Save cur frame's information. + */ + free(save_history); + save_history = memcpy(xmalloc(sizeof(struct save_hist)*n), New_save_hist, + sizeof(struct save_hist)*n); + prev_count = n; + qsort(top, n, sizeof(status_t), (void*)mult_lvl_cmp); +} +#else +static cmp_t sort_function; +#endif /* FEATURE_CPU_USAGE_PERCENTAGE */ + +/* display generic info (meminfo / loadavg) */ +static unsigned long display_generic(void) +{ + FILE *fp; + char buf[80]; + float avg1, avg2, avg3; + unsigned long total, used, mfree, shared, buffers, cached; + unsigned int needs_conversion = 1; + + /* read memory info */ + fp = xfopen("meminfo", "r"); + + /* + * Old kernels (such as 2.4.x) had a nice summary of memory info that + * we could parse, however this is gone entirely in 2.6. Try parsing + * the old way first, and if that fails, parse each field manually. + * + * First, we read in the first line. Old kernels will have bogus + * strings we don't care about, whereas new kernels will start right + * out with MemTotal: + * -- PFM. + */ + if (fscanf(fp, "MemTotal: %lu %s\n", &total, buf) != 2) { + fgets(buf, sizeof(buf), fp); /* skip first line */ + + fscanf(fp, "Mem: %lu %lu %lu %lu %lu %lu", + &total, &used, &mfree, &shared, &buffers, &cached); + } else { + /* + * Revert to manual parsing, which incidentally already has the + * sizes in kilobytes. This should be safe for both 2.4 and + * 2.6. + */ + needs_conversion = 0; + + fscanf(fp, "MemFree: %lu %s\n", &mfree, buf); + + /* + * MemShared: is no longer present in 2.6. Report this as 0, + * to maintain consistent behavior with normal procps. + */ + if (fscanf(fp, "MemShared: %lu %s\n", &shared, buf) != 2) + shared = 0; + + fscanf(fp, "Buffers: %lu %s\n", &buffers, buf); + fscanf(fp, "Cached: %lu %s\n", &cached, buf); + + used = total - mfree; + } + fclose(fp); + + /* read load average */ + fp = xfopen("loadavg", "r"); + if (fscanf(fp, "%f %f %f", &avg1, &avg2, &avg3) != 3) { + error_msg_and_die("failed to read '%s'", "loadavg"); + } + fclose(fp); + + if (needs_conversion) { + /* convert to kilobytes */ + used /= 1024; + mfree /= 1024; + shared /= 1024; + buffers /= 1024; + cached /= 1024; + total /= 1024; + } + + /* output memory info and load average */ + /* clear screen & go to top */ + printf("\e[H\e[J" "Mem: " + "%ldK used, %ldK free, %ldK shrd, %ldK buff, %ldK cached\n", + used, mfree, shared, buffers, cached); + printf("Load average: %.2f, %.2f, %.2f " + "(State: S=sleeping R=running, W=waiting)\n", + avg1, avg2, avg3); + return total; +} + + +/* display process statuses */ +static void display_status(int count, int col) +{ + status_t *s = top; + char rss_str_buf[8]; + unsigned long total_memory = display_generic(); + +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + /* what info of the processes is shown */ + printf("\n\e[7m PID USER STATUS RSS PPID %%CPU %%MEM COMMAND\e[0m\n"); +#else + printf("\n\e[7m PID USER STATUS RSS PPID %%MEM COMMAND\e[0m\n"); +#endif + + while (count--) { + char *namecmd = s->cmd; + int pmem; + + pmem = 1000.0 * s->rss / total_memory; + if (pmem > 999) pmem = 999; + + if(s->rss > 10*1024) + sprintf(rss_str_buf, "%6ldM", s->rss/1024); + else + sprintf(rss_str_buf, "%7ld", s->rss); +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + printf("%5d %-8s %s %s %5d %2d.%d %2u.%u ", +#else + printf("%5d %-8s %s %s %5d %2u.%u ", +#endif + s->pid, s->user, s->state, rss_str_buf, s->ppid, +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + s->pcpu/10, s->pcpu%10, +#endif + pmem/10, pmem%10); + if(namecmd != 0 && namecmd[0] != 0) { + if(strlen(namecmd) > col) + namecmd[col] = 0; + printf("%s\n", namecmd); + } else { + namecmd = s->short_cmd; + if(strlen(namecmd) > (col-2)) + namecmd[col-2] = 0; + printf("[%s]\n", namecmd); + } + s++; + } +} + +/* returns true for file names which are PID dirs + * (i.e. start with number) + */ +static int filter_pids(const struct dirent *dir) +{ + char *name = dir->d_name; + int n; + char status[20]; + char buf[1024]; + FILE *fp; + status_t curstatus; + int pid; + long tasknice; + struct stat sb; + + if (!(*name >= '0' && *name <= '9')) + return 0; + if(stat(name, &sb)) + return 0; + + memset(&curstatus, 0, sizeof(status_t)); + pid = atoi(name); + curstatus.pid = pid; + + my_getpwuid(curstatus.user, sb.st_uid); + + sprintf(status, "%d/stat", pid); + if((fp = fopen(status, "r")) == NULL) + return 0; + name = fgets(buf, sizeof(buf), fp); + fclose(fp); + if(name == NULL) + return 0; + name = strrchr(buf, ')'); /* split into "PID (cmd" and "" */ + if(name == 0 || name[1] != ' ') + return 0; + *name = 0; + sscanf(buf, "%*s (%15c", curstatus.short_cmd); + n = sscanf(name+2, + "%c %d " + "%*s %*s %*s %*s " /* pgrp, session, tty, tpgid */ + "%*s %*s %*s %*s %*s " /* flags, min_flt, cmin_flt, maj_flt, cmaj_flt */ +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + "%lu %lu " +#else + "%*s %*s " +#endif + "%*s %*s %*s " /* cutime, cstime, priority */ + "%ld " + "%*s %*s %*s " /* timeout, it_real_value, start_time */ + "%*s " /* vsize */ + "%ld", + curstatus.state, &curstatus.ppid, +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + &curstatus.utime, &curstatus.stime, +#endif + &tasknice, + &curstatus.rss); +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + if(n != 6) +#else + if(n != 4) +#endif + return 0; + + if (curstatus.rss == 0 && curstatus.state[0] != 'Z') + curstatus.state[1] = 'W'; + else + curstatus.state[1] = ' '; + if (tasknice < 0) + curstatus.state[2] = '<'; + else if (tasknice > 0) + curstatus.state[2] = 'N'; + else + curstatus.state[2] = ' '; + + curstatus.rss <<= (PAGE_SHIFT - 10); /* 2**10 = 1kb */ + + sprintf(status, "%d/cmdline", pid); + if((fp = fopen(status, "r")) == NULL) + return 0; + if(fgets(buf, sizeof(buf), fp) != NULL) { + name = strchr(buf, '\n'); + if(name != NULL) + *name = 0; + if(buf[0]) + curstatus.cmd = strdup(buf); /* if NULL it work true also */ + } + fclose(fp); + + n = ntop; + top = xrealloc(top, (++ntop)*sizeof(status_t)); + memcpy(top + n, &curstatus, sizeof(status_t)); + return 1; +} + + +static struct dirent **namelist; + +static void clearmems(void) { + int i; + + for(i = 0; i < ntop; i++) { + free(top[i].cmd); + free(namelist[i]); + } + free(top); + free(namelist); + top = 0; + namelist = 0; + ntop = 0; +} + +#if defined BB_FEATURE_USE_TERMIOS +#include +#include +#include + + +static struct termios initial_settings; + +static void reset_term(void) +{ + tcsetattr(0, TCSANOW, (void *) &initial_settings); +#ifdef CONFIG_FEATURE_CLEAN_UP + clearmems(); +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + free(save_history); +#endif +#endif /* CONFIG_FEATURE_CLEAN_UP */ +} + +static void sig_catcher (int sig) +{ + reset_term(); +} +#endif /* BB_FEATURE_USE_TERMIOS */ + + +int top_main(int argc, char **argv) +{ + int opt, interval, lines, col; +#if defined BB_FEATURE_USE_TERMIOS + struct termios new_settings; + struct timeval tv; + fd_set readfds; + unsigned char c; + struct sigaction sa; +#if defined BB_FEATURE_AUTOWIDTH + struct winsize win = { 0, 0, 0, 0 }; +#endif +#endif /* BB_FEATURE_USE_TERMIOS */ + + /* Default update rate is 5 seconds */ + interval = 5; + + /* do normal option parsing */ + while ((opt = getopt(argc, argv, "d:")) > 0) { + switch (opt) { + case 'd': + interval = atoi(optarg); + break; + default: + show_usage(); + } + } + + /* Default to 25 lines - 5 lines for status */ + lines = 25 - 5; + /* Default CMD format size */ +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + col = 35 - 6; +#else + col = 35; +#endif + /* change to proc */ + if (chdir("/proc") < 0) { + perror_msg_and_die("chdir('/proc')"); + } +#if defined BB_FEATURE_USE_TERMIOS + tcgetattr(0, (void *) &initial_settings); + memcpy(&new_settings, &initial_settings, sizeof(struct termios)); + new_settings.c_lflag &= ~(ISIG | ICANON); /* unbuffered input */ + /* Turn off echoing */ + new_settings.c_lflag &= ~(ECHO | ECHONL); + + signal (SIGTERM, sig_catcher); + sigaction (SIGTERM, (struct sigaction *) 0, &sa); + sa.sa_flags |= SA_RESTART; + sa.sa_flags &= ~SA_INTERRUPT; + sigaction (SIGTERM, &sa, (struct sigaction *) 0); + sigaction (SIGINT, &sa, (struct sigaction *) 0); + tcsetattr(0, TCSANOW, (void *) &new_settings); + atexit(reset_term); +#if defined BB_FEATURE_AUTOWIDTH + ioctl(0, TIOCGWINSZ, &win); + if (win.ws_row > 4) { + lines = win.ws_row - 5; +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + col = win.ws_col - 80 + 35 - 6; +#else + col = win.ws_col - 80 + 35; +#endif + } +#endif +#endif /* BB_FEATURE_USE_TERMIOS */ +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + sort_function[0] = pcpu_sort; + sort_function[1] = mem_sort; + sort_function[2] = time_sort; +#else + sort_function = mem_sort; +#endif + while (1) { + /* read process IDs & status for all the processes */ + if (scandir(".", &namelist, filter_pids, 0) < 0) { + perror_msg_and_die("scandir('/proc')"); + } +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + if(!Hertz) { + init_Hertz_value(); + do_stats(); + sleep(1); + clearmems(); + continue; + } + do_stats(); +#else + qsort(top, ntop, sizeof(status_t), (void*)sort_function); +#endif + opt = lines; + if (opt > ntop) { + opt = ntop; + } + /* show status for each of the processes */ + display_status(opt, col); +#if defined BB_FEATURE_USE_TERMIOS + tv.tv_sec = interval; + tv.tv_usec = 0; + FD_ZERO (&readfds); + FD_SET (0, &readfds); + select (1, &readfds, NULL, NULL, &tv); + if (FD_ISSET (0, &readfds)) { + if (read (0, &c, 1) <= 0) { /* signal */ + return EXIT_FAILURE; + } + if(c == 'q' || c == initial_settings.c_cc[VINTR]) + return EXIT_SUCCESS; + if(c == 'M') { +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + sort_function[0] = mem_sort; + sort_function[1] = pcpu_sort; + sort_function[2] = time_sort; +#else + sort_function = mem_sort; +#endif + } +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + if(c == 'P') { + sort_function[0] = pcpu_sort; + sort_function[1] = mem_sort; + sort_function[2] = time_sort; + } + if(c == 'T') { + sort_function[0] = time_sort; + sort_function[1] = mem_sort; + sort_function[2] = pcpu_sort; + } +#endif + if(c == 'N') { +#ifdef FEATURE_CPU_USAGE_PERCENTAGE + sort_function[0] = pid_sort; +#else + sort_function = pid_sort; +#endif + } + } +#else + sleep(interval); +#endif /* BB_FEATURE_USE_TERMIOS */ + clearmems(); + } + + return EXIT_SUCCESS; +} diff --git a/touch.c b/touch.c new file mode 100644 index 000000000..036b5c3ee --- /dev/null +++ b/touch.c @@ -0,0 +1,75 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini touch implementation for busybox + * + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +extern int touch_main(int argc, char **argv) +{ + int fd; + int create = TRUE; + + /* Parse options */ + while (--argc > 0 && **(++argv) == '-') { + while (*(++(*argv))) { + switch (**argv) { + case 'c': + create = FALSE; + break; + default: + show_usage(); + } + } + } + + if (argc < 1) { + show_usage(); + } + + while (argc > 0) { + fd = open(*argv, (create == FALSE) ? O_RDWR : O_RDWR | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + if (fd < 0) { + if (create == FALSE && errno == ENOENT) + return EXIT_SUCCESS; + else { + perror_msg_and_die("%s", *argv); + } + } + close(fd); + if (utime(*argv, NULL)) { + perror_msg_and_die("%s", *argv); + } + argc--; + argv++; + } + + return EXIT_SUCCESS; +} diff --git a/tr.c b/tr.c new file mode 100644 index 000000000..5b7b8d091 --- /dev/null +++ b/tr.c @@ -0,0 +1,248 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini tr implementation for busybox + * + * Copyright (c) Michiel Huisjes + * + * This version of tr is adapted from Minix tr and was modified + * by Erik Andersen to be used in busybox. + * + * 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 + * + * Original copyright notice is retained at the end of this file. + */ + +#include +#include +#include +#include +#include +#include "busybox.h" + +/* This must be a #define, since when DODEBUG 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() +{ + 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) + error_msg("%s", 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) + error_msg_and_die("%s", write_error); + out_index = 0; + } + } + + /* NOTREACHED */ +} + +static void map(register unsigned char *string1, unsigned int string1_len, + register unsigned char *string2, unsigned int string2_len) +{ + unsigned char last = '0'; + unsigned int i, j; + + for (j = 0, i = 0; i < string1_len; i++) { + if (string2_len <= j) + pvector[string1[i]] = last; + else + pvector[string1[i]] = last = string2[j++]; + } +} + +/* supported constructs: + * Ranges, e.g., [0-9] ==> 0123456789 + * Escapes, e.g., \a ==> Control-G + */ +static unsigned int expand(const char *arg, register unsigned char *buffer) +{ + unsigned char *buffer_start = buffer; + int i, ac; + + while (*arg) { + if (*arg == '\\') { + arg++; + *buffer++ = process_escape_sequence(&arg); + } else if (*(arg+1) == '-') { + ac = *(arg+2); + if(ac == 0) { + *buffer++ = *arg++; + continue; + } + i = *arg; + while (i <= ac) + *buffer++ = i++; + arg += 3; /* Skip the assumed a-z */ + } else if (*arg == '[') { + arg++; + i = *arg++; + if (*arg++ != '-') { + *buffer++ = '['; + arg -= 2; + continue; + } + ac = *arg++; + while (i <= ac) + *buffer++ = i++; + arg++; /* Skip the assumed ']' */ + } else + *buffer++ = *arg++; + } + + return (buffer - buffer_start); +} + +static int complement(unsigned char *buffer, int buffer_len) +{ + register short i, j, ix; + char conv[ASCII + 2]; + + 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; + } + memcpy(buffer, conv, ix); + return ix; +} + +extern int tr_main(int argc, char **argv) +{ + register unsigned char *ptr; + int output_length=0, input_length; + int idx = 1; + int i; + RESERVE_BB_BUFFER(output, BUFSIZ); + RESERVE_BB_BUFFER(input, BUFSIZ); + RESERVE_BB_UBUFFER(vector, ASCII+1); + RESERVE_BB_BUFFER(invec, ASCII+1); + RESERVE_BB_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: + show_usage(); + } + } + idx++; + } + for (i = 0; i <= ASCII; i++) { + vector[i] = i; + invec[i] = outvec[i] = FALSE; + } + + 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') + 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; + } + convert(); + return (0); +} + +/* + * 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. + * + */ + diff --git a/traceroute.c b/traceroute.c new file mode 100644 index 000000000..c0c216528 --- /dev/null +++ b/traceroute.c @@ -0,0 +1,647 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Van Jacobson. + * + * Special for busybox ported by Vladimir Oleynik 2001 + * 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 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. + */ + +/* + * traceroute host - trace the route ip packets follow going to "host". + * Notes + * ----- + * This program must be run by root or be setuid. (I suggest that + * you *don't* make it setuid -- casual use could result in a lot + * of unnecessary traffic on our poor, congested nets.) + * + * I stole the idea for this program from Steve Deering. Since + * the first release, I've learned that had I attended the right + * IETF working group meetings, I also could have stolen it from Guy + * Almes or Matt Mathis. I don't know (or care) who came up with + * the idea first. I envy the originators' perspicacity and I'm + * glad they didn't keep the idea a secret. + * + * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or + * enhancements to the original distribution. + * + * I've hacked up a round-trip-route version of this that works by + * sending a loose-source-routed udp datagram through the destination + * back to yourself. Unfortunately, SO many gateways botch source + * routing, the thing is almost worthless. Maybe one day... + * + * -- Van Jacobson (van@helios.ee.lbl.gov) + * Tue Dec 20 03:50:13 PST 1988 + */ + +#undef BB_FEATURE_TRACEROUTE_VERBOSE +//#define BB_FEATURE_TRACEROUTE_VERBOSE +#undef BB_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + /* It turns out that libc5 doesn't have proper icmp support + * built into it header files, so we have to supplement it */ +#if __GNU_LIBRARY__ < 5 +static const int ICMP_MINLEN = 8; /* abs minimum */ + +struct icmp_ra_addr +{ + u_int32_t ira_addr; + u_int32_t ira_preference; +}; + + +struct icmp +{ + u_int8_t icmp_type; /* type of message, see below */ + u_int8_t icmp_code; /* type sub code */ + u_int16_t icmp_cksum; /* ones complement checksum of struct */ + union + { + u_char ih_pptr; /* ICMP_PARAMPROB */ + struct in_addr ih_gwaddr; /* gateway address */ + struct ih_idseq /* echo datagram */ + { + u_int16_t icd_id; + u_int16_t icd_seq; + } ih_idseq; + u_int32_t ih_void; + + /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ + struct ih_pmtu + { + u_int16_t ipm_void; + u_int16_t ipm_nextmtu; + } ih_pmtu; + + struct ih_rtradv + { + u_int8_t irt_num_addrs; + u_int8_t irt_wpa; + u_int16_t irt_lifetime; + } ih_rtradv; + } icmp_hun; +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu +#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs +#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa +#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime + union + { + struct + { + u_int32_t its_otime; + u_int32_t its_rtime; + u_int32_t its_ttime; + } id_ts; + struct + { + struct ip idi_ip; + /* options and then 64 bits of data */ + } id_ip; + struct icmp_ra_addr id_radv; + u_int32_t id_mask; + u_int8_t id_data[1]; + } icmp_dun; +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_radv icmp_dun.id_radv +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data +}; + +#define ICMP_MINLEN 8 /* abs minimum */ +#define ICMP_UNREACH 3 /* dest unreachable, codes: */ +#define ICMP_TIMXCEED 11 /* time exceeded, code: */ +#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ +#define ICMP_UNREACH_NET 0 /* bad net */ +#define ICMP_UNREACH_HOST 1 /* bad host */ +#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ +#define ICMP_UNREACH_PORT 3 /* bad port */ +#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ +#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ +#endif + + +#define MAXPACKET 65535 /* max ip packet size */ +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +/* + * format of a (udp) probe packet. + */ +struct opacket { + struct ip ip; + struct udphdr udp; + u_char seq; /* sequence number of this packet */ + u_char ttl; /* ttl packet left with */ + struct timeval tv; /* time packet left */ +}; + +/* + * Definitions for internet protocol version 4. + * Per RFC 791, September 1981. + */ +#define IPVERSION 4 + + +#include "busybox.h" + +static u_char packet[512]; /* last inbound (icmp) packet */ +static struct opacket *outpacket; /* last output (udp) packet */ + +static int s; /* receive (icmp) socket file descriptor */ +static int sndsock; /* send (udp) socket file descriptor */ + +static struct sockaddr whereto; /* Who to try to reach */ +static int datalen; /* How much data */ + +static char *hostname; + +static int max_ttl = 30; +static u_short ident; +static u_short port = 32768+666; /* start udp dest port # for probe packets */ + +#ifdef BB_FEATURE_TRACEROUTE_VERBOSE +static int verbose; +#endif +static int waittime = 5; /* time to wait for response (in seconds) */ +static int nflag; /* print addresses numerically */ + +/* + * Construct an Internet address representation. + * If the nflag has been supplied, give + * numeric value, otherwise try for symbolic name. + */ +static inline void +inetname(struct sockaddr_in *from) +{ + char *cp; + struct hostent *hp; + static char domain[MAXHOSTNAMELEN + 1]; + static int first = 1; + const char *ina; + + if (first && !nflag) { + first = 0; + if (getdomainname(domain, MAXHOSTNAMELEN) != 0) + domain[0] = 0; + } + cp = 0; + if (!nflag && from->sin_addr.s_addr != INADDR_ANY) { + hp = gethostbyaddr((char *)&(from->sin_addr), sizeof (from->sin_addr), AF_INET); + if (hp) { + if ((cp = strchr(hp->h_name, '.')) && !strcmp(cp + 1, domain)) + *cp = 0; + cp = (char *)hp->h_name; + } + } + ina = inet_ntoa(from->sin_addr); + if (nflag) + printf(" %s", ina); + else + printf(" %s (%s)", (cp ? cp : ina), ina); +} + +static inline void +print(u_char *buf, int cc, struct sockaddr_in *from) +{ + struct ip *ip; + int hlen; + + ip = (struct ip *) buf; + hlen = ip->ip_hl << 2; + cc -= hlen; + + inetname(from); +#ifdef BB_FEATURE_TRACEROUTE_VERBOSE + if (verbose) + printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); +#endif +} + +static inline double +deltaT(struct timeval *t1p, struct timeval *t2p) +{ + double dt; + + dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + + (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; + return (dt); +} + +static inline int +wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer) +{ + fd_set fds; + static struct timeval wait; + int cc = 0; + int fromlen = sizeof (*from); + + FD_ZERO(&fds); + FD_SET(sock, &fds); + if (reset_timer) { + /* + * traceroute could hang if someone else has a ping + * running and our ICMP reply gets dropped but we don't + * realize it because we keep waking up to handle those + * other ICMP packets that keep coming in. To fix this, + * "reset_timer" will only be true if the last packet that + * came in was for us or if this is the first time we're + * waiting for a reply since sending out a probe. Note + * that this takes advantage of the select() feature on + * Linux where the remaining timeout is written to the + * struct timeval area. + */ + wait.tv_sec = waittime; + wait.tv_usec = 0; + } + + if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0) + cc=recvfrom(s, (char *)packet, sizeof(packet), 0, + (struct sockaddr *)from, &fromlen); + + return(cc); +} + +#ifdef BB_FEATURE_TRACEROUTE_VERBOSE +/* + * Convert an ICMP "type" field to a printable string. + */ +static inline const char * +pr_type(u_char t) +{ + static const char * const ttab[] = { + "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", + "Source Quench", "Redirect", "ICMP 6", "ICMP 7", + "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", + "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", + "Info Reply" + }; + + if(t > 16) + return("OUT-OF-RANGE"); + + return(ttab[t]); +} +#endif + +static inline int +packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq) +{ + struct icmp *icp; + u_char type, code; + int hlen; + struct ip *ip; + + ip = (struct ip *) buf; + hlen = ip->ip_hl << 2; + if (cc < hlen + ICMP_MINLEN) { +#ifdef BB_FEATURE_TRACEROUTE_VERBOSE + if (verbose) + printf("packet too short (%d bytes) from %s\n", cc, + inet_ntoa(from->sin_addr)); +#endif + return (0); + } + cc -= hlen; + icp = (struct icmp *)(buf + hlen); + type = icp->icmp_type; code = icp->icmp_code; + if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || + type == ICMP_UNREACH) { + struct ip *hip; + struct udphdr *up; + + hip = &icp->icmp_ip; + hlen = hip->ip_hl << 2; + up = (struct udphdr *)((u_char *)hip + hlen); + if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP && + up->source == htons(ident) && + up->dest == htons(port+seq)) + return (type == ICMP_TIMXCEED? -1 : code+1); + } +#ifdef BB_FEATURE_TRACEROUTE_VERBOSE + if (verbose) { + int i; + u_long *lp = (u_long *)&icp->icmp_ip; + + printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n", + cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst), + type, pr_type(type), icp->icmp_code); + for (i = 4; i < cc ; i += sizeof(long)) + printf("%2d: x%8.8lx\n", i, *lp++); + } +#endif + return(0); +} + +static void /* not inline */ +send_probe(int seq, int ttl) +{ + struct opacket *op = outpacket; + struct ip *ip = &op->ip; + struct udphdr *up = &op->udp; + int i; + struct timezone tz; + + ip->ip_off = 0; + ip->ip_hl = sizeof(*ip) >> 2; + ip->ip_p = IPPROTO_UDP; + ip->ip_len = datalen; + ip->ip_ttl = ttl; + ip->ip_v = IPVERSION; + ip->ip_id = htons(ident+seq); + + up->source = htons(ident); + up->dest = htons(port+seq); + up->len = htons((u_short)(datalen - sizeof(struct ip))); + up->check = 0; + + op->seq = seq; + op->ttl = ttl; + (void) gettimeofday(&op->tv, &tz); + + i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto, + sizeof(struct sockaddr)); + if (i < 0 || i != datalen) { + if (i<0) + perror("sendto"); + printf("traceroute: wrote %s %d chars, ret=%d\n", hostname, + datalen, i); + (void) fflush(stdout); + } +} + + +int +#ifndef BB_TRACEROUTE +main(argc, argv) +#else +traceroute_main(argc, argv) +#endif + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + struct hostent *hp; + struct sockaddr_in from, *to; + int ch, i, on, probe, seq, tos, ttl; + + int options = 0; /* socket options */ + char *source = 0; + int nprobes = 3; + + on = 1; + seq = tos = 0; + to = (struct sockaddr_in *)&whereto; + while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF) + switch(ch) { + case 'd': +#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG + options |= SO_DEBUG; +#endif + break; + case 'm': + max_ttl = atoi(optarg); + if (max_ttl <= 1) + error_msg_and_die("max ttl must be >1."); + break; + case 'n': + nflag++; + break; + case 'p': + port = atoi(optarg); + if (port < 1) + error_msg_and_die("port must be >0."); + break; + case 'q': + nprobes = atoi(optarg); + if (nprobes < 1) + error_msg_and_die("nprobes must be >0."); + break; + case 'r': + options |= SO_DONTROUTE; + break; + case 's': + /* + * set the ip source address of the outbound + * probe (e.g., on a multi-homed host). + */ + source = optarg; + break; + case 't': + tos = atoi(optarg); + if (tos < 0 || tos > 255) + error_msg_and_die("tos must be 0 to 255."); + break; + case 'v': +#ifdef BB_FEATURE_TRACEROUTE_VERBOSE + verbose++; +#endif + break; + case 'w': + waittime = atoi(optarg); + if (waittime <= 1) + error_msg_and_die("wait must be >1 sec."); + break; + default: + show_usage(); + } + argc -= optind; + argv += optind; + + if (argc < 1) + show_usage(); + + setlinebuf (stdout); + + memset(&whereto, 0, sizeof(struct sockaddr)); + hp = xgethostbyname(*argv); + to->sin_family = hp->h_addrtype; + memcpy(&to->sin_addr, hp->h_addr, hp->h_length); + hostname = (char *)hp->h_name; + if (*++argv) + datalen = atoi(*argv); + if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) + error_msg_and_die("packet size must be 0 <= s < %d.", + MAXPACKET - sizeof(struct opacket)); + datalen += sizeof(struct opacket); + outpacket = (struct opacket *)xmalloc((unsigned)datalen); + memset(outpacket, 0, datalen); + outpacket->ip.ip_dst = to->sin_addr; + outpacket->ip.ip_tos = tos; + outpacket->ip.ip_v = IPVERSION; + outpacket->ip.ip_id = 0; + + ident = (getpid() & 0xffff) | 0x8000; + + if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) + perror_msg_and_die(can_not_create_raw_socket); + + s = create_icmp_socket(); + +#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG + if (options & SO_DEBUG) + (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, + (char *)&on, sizeof(on)); +#endif + if (options & SO_DONTROUTE) + (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, + (char *)&on, sizeof(on)); +#ifdef SO_SNDBUF + if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, + sizeof(datalen)) < 0) + perror_msg_and_die("SO_SNDBUF"); +#endif /* SO_SNDBUF */ +#ifdef IP_HDRINCL + if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, + sizeof(on)) < 0) + perror_msg_and_die("IP_HDRINCL"); +#endif /* IP_HDRINCL */ +#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG + if (options & SO_DEBUG) + (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, + (char *)&on, sizeof(on)); +#endif + if (options & SO_DONTROUTE) + (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, + (char *)&on, sizeof(on)); + + if (source) { + memset(&from, 0, sizeof(struct sockaddr)); + from.sin_family = AF_INET; + from.sin_addr.s_addr = inet_addr(source); + if (from.sin_addr.s_addr == -1) + error_msg_and_die("unknown host %s", source); + outpacket->ip.ip_src = from.sin_addr; +#ifndef IP_HDRINCL + if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) + perror_msg_and_die("bind"); +#endif /* IP_HDRINCL */ + } + + fprintf(stderr, "traceroute to %s (%s)", hostname, + inet_ntoa(to->sin_addr)); + if (source) + fprintf(stderr, " from %s", source); + fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen); + + for (ttl = 1; ttl <= max_ttl; ++ttl) { + u_long lastaddr = 0; + int got_there = 0; + int unreachable = 0; + + printf("%2d ", ttl); + for (probe = 0; probe < nprobes; ++probe) { + int cc, reset_timer; + struct timeval t1, t2; + struct timezone tz; + struct ip *ip; + + (void) gettimeofday(&t1, &tz); + send_probe(++seq, ttl); + reset_timer = 1; + while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) { + (void) gettimeofday(&t2, &tz); + if ((i = packet_ok(packet, cc, &from, seq))) { + reset_timer = 1; + if (from.sin_addr.s_addr != lastaddr) { + print(packet, cc, &from); + lastaddr = from.sin_addr.s_addr; + } + printf(" %g ms", deltaT(&t1, &t2)); + switch(i - 1) { + case ICMP_UNREACH_PORT: + ip = (struct ip *)packet; + if (ip->ip_ttl <= 1) + printf(" !"); + ++got_there; + break; + case ICMP_UNREACH_NET: + ++unreachable; + printf(" !N"); + break; + case ICMP_UNREACH_HOST: + ++unreachable; + printf(" !H"); + break; + case ICMP_UNREACH_PROTOCOL: + ++got_there; + printf(" !P"); + break; + case ICMP_UNREACH_NEEDFRAG: + ++unreachable; + printf(" !F"); + break; + case ICMP_UNREACH_SRCFAIL: + ++unreachable; + printf(" !S"); + break; + } + break; + } else + reset_timer = 0; + } + if (cc == 0) + printf(" *"); + (void) fflush(stdout); + } + putchar('\n'); + if (got_there || unreachable >= nprobes-1) + exit(0); + } + + return 0; +} diff --git a/true_false.c b/true_false.c new file mode 100644 index 000000000..b00e29820 --- /dev/null +++ b/true_false.c @@ -0,0 +1,39 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini true/false implementation for busybox + * + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +/* getopt not needed */ + +#include +#include "busybox.h" + + +extern int true_main(int argc, char **argv) +{ + return EXIT_SUCCESS; +} + +extern int false_main(int argc, char **argv) +{ + return EXIT_FAILURE; +} diff --git a/tty.c b/tty.c new file mode 100644 index 000000000..4510c2996 --- /dev/null +++ b/tty.c @@ -0,0 +1,44 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini tty implementation for busybox + * + * 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 + * + */ + +#include +#include +#include +#include +#include "busybox.h" + +extern int tty_main(int argc, char **argv) +{ + char *tty; + + if (argc > 1) { + if (argv[1][0] != '-' || argv[1][1] != 's') + show_usage(); + } else { + tty = ttyname(0); + if (tty) + puts(tty); + else + puts("not a tty"); + } + return(isatty(0) ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/umount.c b/umount.c new file mode 100644 index 000000000..2a06a3b45 --- /dev/null +++ b/umount.c @@ -0,0 +1,298 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini umount implementation for busybox + * + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +/* Teach libc5 about realpath -- it includes it but the + * prototype is missing... */ +#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1) +extern char *realpath(const char *path, char *resolved_path); +#endif + +static const int MNT_FORCE = 1; +static const int MS_MGC_VAL = 0xc0ed0000; /* Magic number indicatng "new" flags */ +static const int MS_REMOUNT = 32; /* Alter flags of a mounted FS. */ +static const int MS_RDONLY = 1; /* Mount read-only. */ + +extern int mount (__const char *__special_file, __const char *__dir, + __const char *__fstype, unsigned long int __rwflag, + __const void *__data); +extern int umount (__const char *__special_file); +extern int umount2 (__const char *__special_file, int __flags); + +struct _mtab_entry_t { + char *device; + char *mountpt; + struct _mtab_entry_t *next; +}; + +static struct _mtab_entry_t *mtab_cache = NULL; + + + +#if defined BB_FEATURE_MOUNT_FORCE +static int doForce = FALSE; +#endif +#if defined BB_FEATURE_MOUNT_LOOP +static int freeLoop = TRUE; +#endif +#if defined BB_FEATURE_MTAB_SUPPORT +static int useMtab = TRUE; +#endif +static int umountAll = FALSE; +static int doRemount = FALSE; +extern const char mtab_file[]; /* Defined in utility.c */ + + + +/* These functions are here because the getmntent functions do not appear + * to be re-entrant, which leads to all sorts of problems when we try to + * use them recursively - randolph + * + * TODO: Perhaps switch to using Glibc's getmntent_r + * -Erik + */ +static void mtab_read(void) +{ + struct _mtab_entry_t *entry = NULL; + struct mntent *e; + FILE *fp; + + if (mtab_cache != NULL) + return; + + if ((fp = setmntent(mtab_file, "r")) == NULL) { + error_msg("Cannot open %s", mtab_file); + return; + } + while ((e = getmntent(fp))) { + entry = xmalloc(sizeof(struct _mtab_entry_t)); + entry->device = strdup(e->mnt_fsname); + entry->mountpt = strdup(e->mnt_dir); + entry->next = mtab_cache; + mtab_cache = entry; + } + endmntent(fp); +} + +static char *mtab_getinfo(const char *match, const char which) +{ + struct _mtab_entry_t *cur = mtab_cache; + + while (cur) { + if (strcmp(cur->mountpt, match) == 0 || + strcmp(cur->device, match) == 0) { + if (which == MTAB_GETMOUNTPT) { + return cur->mountpt; + } else { +#if !defined BB_FEATURE_MTAB_SUPPORT + if (strcmp(cur->device, "/dev/root") == 0) { + /* Adjusts device to be the real root device, + * or leaves device alone if it can't find it */ + cur->device = find_real_root_device_name(cur->device); + } +#endif + return cur->device; + } + } + cur = cur->next; + } + return NULL; +} + +static char *mtab_next(void **iter) +{ + char *mp; + + if (iter == NULL || *iter == NULL) + return NULL; + mp = ((struct _mtab_entry_t *) (*iter))->mountpt; + *iter = (void *) ((struct _mtab_entry_t *) (*iter))->next; + return mp; +} + +static char *mtab_first(void **iter) +{ + struct _mtab_entry_t *mtab_iter; + + if (!iter) + return NULL; + mtab_iter = mtab_cache; + *iter = (void *) mtab_iter; + return mtab_next(iter); +} + +/* Don't bother to clean up, since exit() does that + * automagically, so we can save a few bytes */ +#ifdef BB_FEATURE_CLEAN_UP +static void mtab_free(void) +{ + struct _mtab_entry_t *this, *next; + + this = mtab_cache; + while (this) { + next = this->next; + if (this->device) + free(this->device); + if (this->mountpt) + free(this->mountpt); + free(this); + this = next; + } +} +#endif + +static int do_umount(const char *name) +{ + int status; + char *blockDevice = mtab_getinfo(name, MTAB_GETDEVICE); + + if (blockDevice && strcmp(blockDevice, name) == 0) + name = mtab_getinfo(blockDevice, MTAB_GETMOUNTPT); + + status = umount(name); + +#if defined BB_FEATURE_MOUNT_LOOP + if (freeLoop == TRUE && blockDevice != NULL && !strncmp("/dev/loop", blockDevice, 9)) + /* this was a loop device, delete it */ + del_loop(blockDevice); +#endif +#if defined BB_FEATURE_MOUNT_FORCE + if (status != 0 && doForce == TRUE) { + status = umount2(blockDevice, MNT_FORCE); + if (status != 0) { + error_msg_and_die("forced umount of %s failed!", blockDevice); + } + } +#endif + if (status != 0 && doRemount == TRUE && errno == EBUSY) { + status = mount(blockDevice, name, NULL, + MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL); + if (status == 0) { + error_msg("%s busy - remounted read-only", blockDevice); + } else { + error_msg("Cannot remount %s read-only", blockDevice); + } + } + if (status == 0) { +#if defined BB_FEATURE_MTAB_SUPPORT + if (useMtab == TRUE) + erase_mtab(name); +#endif + return (TRUE); + } + return (FALSE); +} + +static int umount_all(void) +{ + int status = TRUE; + char *mountpt; + void *iter; + + for (mountpt = mtab_first(&iter); mountpt; mountpt = mtab_next(&iter)) { + /* Never umount /proc on a umount -a */ + if (strstr(mountpt, "proc")!= NULL) + continue; + if (!do_umount(mountpt)) { + /* Don't bother retrying the umount on busy devices */ + if (errno == EBUSY) { + perror_msg("%s", mountpt); + status = FALSE; + continue; + } + if (!do_umount(mountpt)) { + printf("Couldn't umount %s on %s: %s\n", + mountpt, mtab_getinfo(mountpt, MTAB_GETDEVICE), + strerror(errno)); + status = FALSE; + } + } + } + return (status); +} + +extern int umount_main(int argc, char **argv) +{ + char path[PATH_MAX]; + + if (argc < 2) { + show_usage(); + } +#ifdef BB_FEATURE_CLEAN_UP + atexit(mtab_free); +#endif + + /* Parse any options */ + while (--argc > 0 && **(++argv) == '-') { + while (*++(*argv)) + switch (**argv) { + case 'a': + umountAll = TRUE; + break; +#if defined BB_FEATURE_MOUNT_LOOP + case 'l': + freeLoop = FALSE; + break; +#endif +#ifdef BB_FEATURE_MTAB_SUPPORT + case 'n': + useMtab = FALSE; + break; +#endif +#ifdef BB_FEATURE_MOUNT_FORCE + case 'f': + doForce = TRUE; + break; +#endif + case 'r': + doRemount = TRUE; + break; + case 'v': + break; /* ignore -v */ + default: + show_usage(); + } + } + + mtab_read(); + if (umountAll == TRUE) { + if (umount_all() == TRUE) + return EXIT_SUCCESS; + else + return EXIT_FAILURE; + } + if (realpath(*argv, path) == NULL) + perror_msg_and_die("%s", path); + if (do_umount(path) == TRUE) + return EXIT_SUCCESS; + perror_msg_and_die("%s", *argv); +} + diff --git a/uname.c b/uname.c new file mode 100644 index 000000000..f7e2291a8 --- /dev/null +++ b/uname.c @@ -0,0 +1,156 @@ +/* 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. */ + +/* 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 */ + +/* Busyboxed by Erik Andersen */ + +#include +#include +#include +#include +#include + +#if defined (HAVE_SYSINFO) && defined (HAVE_SYS_SYSTEMINFO_H) +# include +#endif +#include "busybox.h" + +static void print_element(unsigned int mask, char *element); + +/* Values that are bitwise or'd into `toprint'. */ +/* Operating system name. */ +static const int PRINT_SYSNAME = 1; + +/* Node name on a communications network. */ +static const int PRINT_NODENAME = 2; + +/* Operating system release. */ +static const int PRINT_RELEASE = 4; + +/* Operating system version. */ +static const int PRINT_VERSION = 8; + +/* Machine hardware name. */ +static const int PRINT_MACHINE = 16; + + /* Host processor type. */ +static const int PRINT_PROCESSOR = 32; + +/* Mask indicating which elements of the name to print. */ +static unsigned char toprint; + + +int uname_main(int argc, char **argv) +{ + struct utsname name; + char processor[256]; + +#if defined(__sparc__) && defined(__linux__) + char *fake_sparc = getenv("FAKE_SPARC"); +#endif + + toprint = 0; + + /* Parse any options */ + //fprintf(stderr, "argc=%d, argv=%s\n", argc, *argv); + while (--argc > 0 && **(++argv) == '-') { + while (*(++(*argv))) { + switch (**argv) { + case 's': + toprint |= PRINT_SYSNAME; + break; + case 'n': + toprint |= PRINT_NODENAME; + break; + case 'r': + toprint |= PRINT_RELEASE; + break; + case 'v': + toprint |= PRINT_VERSION; + break; + case 'm': + toprint |= PRINT_MACHINE; + break; + case 'p': + toprint |= PRINT_PROCESSOR; + break; + case 'a': + toprint = (PRINT_SYSNAME | PRINT_NODENAME | PRINT_RELEASE | + PRINT_PROCESSOR | PRINT_VERSION | + PRINT_MACHINE); + break; + default: + show_usage(); + } + } + } + + if (toprint == 0) + toprint = PRINT_SYSNAME; + + if (uname(&name) == -1) + perror_msg("cannot get system name"); + +#if defined (HAVE_SYSINFO) && defined (SI_ARCHITECTURE) + if (sysinfo(SI_ARCHITECTURE, processor, sizeof(processor)) == -1) + perror_msg("cannot get processor type"); +} + +#else + strcpy(processor, "unknown"); +#endif + +#if defined(__sparc__) && defined(__linux__) + if (fake_sparc != NULL + && (fake_sparc[0] == 'y' + || fake_sparc[0] == 'Y')) strcpy(name.machine, "sparc"); +#endif + + print_element(PRINT_SYSNAME, name.sysname); + print_element(PRINT_NODENAME, name.nodename); + print_element(PRINT_RELEASE, name.release); + print_element(PRINT_VERSION, name.version); + print_element(PRINT_MACHINE, name.machine); + print_element(PRINT_PROCESSOR, processor); + + return EXIT_SUCCESS; +} + +/* If the name element set in MASK is selected for printing in `toprint', + print ELEMENT; then print a space unless it is the last element to + be printed, in which case print a newline. */ + +static void print_element(unsigned int mask, char *element) +{ + if (toprint & mask) { + toprint &= ~mask; + printf("%s%c", element, toprint ? ' ' : '\n'); + } +} diff --git a/uniq.c b/uniq.c new file mode 100644 index 000000000..e46fc4488 --- /dev/null +++ b/uniq.c @@ -0,0 +1,89 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini uniq implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and John Beppu + * Copyright (C) 1999,2000,2001 by John Beppu + * Written by John Beppu + * Rewritten 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 + * + */ + +#include +#include +#include +#include +#include +#include "busybox.h" + +static int print_count; +static int print_uniq = 1; +static int print_duplicates = 1; + +static void print_line(char *line, int count, FILE *fp) +{ + if ((print_duplicates && count > 1) || (print_uniq && count == 1)) { + if (print_count) + fprintf(fp, "%7d\t%s", count, line); + else + fputs(line, fp); + } +} + +int uniq_main(int argc, char **argv) +{ + FILE *in = stdin, *out = stdout; + char *lastline = NULL, *input; + int opt, count = 0; + + /* parse argv[] */ + while ((opt = getopt(argc, argv, "cdu")) > 0) { + switch (opt) { + case 'c': + print_count = 1; + break; + case 'd': + print_duplicates = 1; + print_uniq = 0; + break; + case 'u': + print_duplicates = 0; + print_uniq = 1; + break; + } + } + + if (argv[optind] != NULL) { + in = xfopen(argv[optind], "r"); + if (argv[optind+1] != NULL) + out = xfopen(argv[optind+1], "w"); + } + + while ((input = get_line_from_file(in)) != NULL) { + if (lastline == NULL || strcmp(input, lastline) != 0) { + print_line(lastline, count, out); + free(lastline); + lastline = input; + count = 0; + } + count++; + } + print_line(lastline, count, out); + free(lastline); + + return EXIT_SUCCESS; +} diff --git a/update.c b/update.c new file mode 100644 index 000000000..27a04ddee --- /dev/null +++ b/update.c @@ -0,0 +1,112 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini update implementation for busybox; much pasted from update-2.11 + * + * + * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (c) 1996, 1997, 1999 Torsten Poulin. + * Copyright (c) 2000 by Karl M. Hegbloom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * Note: This program is only necessary if you are running a 2.0.x (or + * earlier) kernel. 2.2.x and higher flush filesystem buffers automatically. + */ + +#include +#include +#include /* for getopt() */ +#include + +#if __GNU_LIBRARY__ > 5 + #include +#else + extern int bdflush (int func, long int data); +#endif + +#include "busybox.h" + +static unsigned int sync_duration = 30; +static unsigned int flush_duration = 5; +static int use_sync = 0; + +extern int update_main(int argc, char **argv) +{ + int pid; + int opt; + + while ((opt = getopt(argc, argv, "Ss:f:")) > 0) { + switch (opt) { + case 'S': + use_sync = 1; + break; + case 's': + sync_duration = atoi(optarg); + break; + case 'f': + flush_duration = atoi(optarg); + break; + default: + show_usage(); + } + } + + if (daemon(0, 1) < 0) + perror_msg_and_die("daemon"); + +#ifdef OPEN_MAX + for (pid = 0; pid < OPEN_MAX; pid++) close(pid); +#else + /* glibc 2.1.92 requires using sysconf(_SC_OPEN_MAX) */ + for (pid = 0; pid < sysconf(_SC_OPEN_MAX); pid++) close(pid); +#endif + + /* This is no longer necessary since 1.3.5x, but it will harmlessly + * exit if that is the case. + */ + + /* set the program name that will show up in a 'ps' listing */ + argv[0] = "bdflush (update)"; + argv[1] = NULL; + argv[2] = NULL; + for (;;) { + if (use_sync) { + sleep(sync_duration); + sync(); + } else { + sleep(flush_duration); + if (bdflush(1, 0) < 0) { + openlog("update", LOG_CONS, LOG_DAEMON); + syslog(LOG_INFO, + "This kernel does not need update(8). Exiting."); + closelog(); + return EXIT_SUCCESS; + } + } + } + + return EXIT_SUCCESS; +} + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/uptime.c b/uptime.c new file mode 100644 index 000000000..5460ac8a5 --- /dev/null +++ b/uptime.c @@ -0,0 +1,77 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini uptime implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 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 + * + */ + +/* This version of uptime doesn't display the number of users on the system, + * since busybox init doesn't mess with utmp. For folks using utmp that are + * just dying to have # of users reported, feel free to write it as some type + * of BB_FEATURE_UTMP_SUPPORT #define + */ + +/* getopt not needed */ + + +#include +#include +#include +#include +#include "busybox.h" + +static const int FSHIFT = 16; /* nr of bits of precision */ +#define FIXED_1 (1<> FSHIFT) +#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) + + +extern int uptime_main(int argc, char **argv) +{ + int updays, uphours, upminutes; + struct sysinfo info; + struct tm *current_time; + time_t current_secs; + + time(¤t_secs); + current_time = localtime(¤t_secs); + + sysinfo(&info); + + printf(" %2d:%02d%s up ", + current_time->tm_hour%12 ? current_time->tm_hour%12 : 12, + current_time->tm_min, current_time->tm_hour > 11 ? "pm" : "am"); + updays = (int) info.uptime / (60*60*24); + if (updays) + printf("%d day%s, ", updays, (updays != 1) ? "s" : ""); + upminutes = (int) info.uptime / 60; + uphours = (upminutes / 60) % 24; + upminutes %= 60; + if(uphours) + printf("%2d:%02d, ", uphours, upminutes); + else + printf("%d min, ", upminutes); + + printf("load average: %ld.%02ld, %ld.%02ld, %ld.%02ld\n", + LOAD_INT(info.loads[0]), LOAD_FRAC(info.loads[0]), + LOAD_INT(info.loads[1]), LOAD_FRAC(info.loads[1]), + LOAD_INT(info.loads[2]), LOAD_FRAC(info.loads[2])); + + return EXIT_SUCCESS; +} diff --git a/usage.c b/usage.c new file mode 100644 index 000000000..dfea1f96b --- /dev/null +++ b/usage.c @@ -0,0 +1,10 @@ +#include "busybox.h" + +const char usage_messages[] = + +#define MAKE_USAGE +#include "usage.h" + +#include "applets.h" + +; diff --git a/usage.h b/usage.h new file mode 100644 index 000000000..2cf591905 --- /dev/null +++ b/usage.h @@ -0,0 +1,1951 @@ +#define adjtimex_trivial_usage \ + "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]" +#define adjtimex_full_usage \ + "Reads and optionally sets system timebase parameters.\n" \ + "See adjtimex(2).\n\n" \ + "Options:\n" \ + "\t-q\t\tquiet mode - do not print\n" \ + "\t-o offset\ttime offset, microseconds\n" \ + "\t-f frequency\tfrequency adjust, integer kernel units (65536 is 1ppm)\n" \ + "\t\t\t(positive values make the system clock run fast)\n" \ + "\t-t tick\t\tmicroseconds per tick, usually 10000\n" \ + "\t-p timeconstant\n" + +#define ar_trivial_usage \ + "-[ov][ptx] ARCHIVE FILES" +#define ar_full_usage \ + "Extract or list FILES from an ar archive.\n\n" \ + "Options:\n" \ + "\t-o\t\tpreserve original dates\n" \ + "\t-p\t\textract to stdout\n" \ + "\t-t\t\tlist\n" \ + "\t-x\t\textract\n" \ + "\t-v\t\tverbosely list files processed\n" + +#define basename_trivial_usage \ + "FILE [SUFFIX]" +#define basename_full_usage \ + "Strips directory path and suffixes from FILE.\n" \ + "If specified, also removes any trailing SUFFIX." +#define basename_example_usage \ + "$ basename /usr/local/bin/foo\n" \ + "foo\n" \ + "$ basename /usr/local/bin/\n" \ + "bin\n" \ + "$ basename /foo/bar.txt .txt\n" \ + "bar" + +#define cat_trivial_usage \ + "[FILE]..." +#define cat_full_usage \ + "Concatenates FILE(s) and prints them to stdout." +#define cat_example_usage \ + "$ cat /proc/uptime\n" \ + "110716.72 17.67" + +#define chgrp_trivial_usage \ + "[OPTION]... GROUP FILE..." +#define chgrp_full_usage \ + "Change the group membership of each FILE to GROUP.\n" \ + "\nOptions:\n" \ + "\t-R\tChanges files and directories recursively." +#define chgrp_example_usage \ + "$ ls -l /tmp/foo\n" \ + "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" \ + "$ chgrp root /tmp/foo\n" \ + "$ ls -l /tmp/foo\n" \ + "-r--r--r-- 1 andersen root 0 Apr 12 18:25 /tmp/foo\n" + +#define chmod_trivial_usage \ + "[-R] MODE[,MODE]... FILE..." +#define chmod_full_usage \ + "Each MODE is one or more of the letters ugoa, one of the\n" \ + "symbols +-= and one or more of the letters rwxst.\n\n" \ + "Options:\n" \ + "\t-R\tChanges files and directories recursively." +#define chmod_example_usage \ + "$ ls -l /tmp/foo\n" \ + "-rw-rw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" \ + "$ chmod u+x /tmp/foo\n" \ + "$ ls -l /tmp/foo\n" \ + "-rwxrw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo*\n" \ + "$ chmod 444 /tmp/foo\n" \ + "$ ls -l /tmp/foo\n" \ + "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" + +#define chown_trivial_usage \ + "[ -Rh ]... OWNER[<.|:>[GROUP]] FILE..." +#define chown_full_usage \ + "Change the owner and/or group of each FILE to OWNER and/or GROUP.\n" \ + "\nOptions:\n" \ + "\t-R\tChanges files and directories recursively.\n" \ + "\t-h\tDo not dereference symbolic links." +#define chown_example_usage \ + "$ ls -l /tmp/foo\n" \ + "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" \ + "$ chown root /tmp/foo\n" \ + "$ ls -l /tmp/foo\n" \ + "-r--r--r-- 1 root andersen 0 Apr 12 18:25 /tmp/foo\n" \ + "$ chown root.root /tmp/foo\n" \ + "ls -l /tmp/foo\n" \ + "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" + +#define chroot_trivial_usage \ + "NEWROOT [COMMAND...]" +#define chroot_full_usage \ + "Run COMMAND with root directory set to NEWROOT." +#define chroot_example_usage \ + "$ ls -l /bin/ls\n" \ + "lrwxrwxrwx 1 root root 12 Apr 13 00:46 /bin/ls -> /BusyBox\n" \ + "$ mount /dev/hdc1 /mnt -t minix\n" \ + "$ chroot /mnt\n" \ + "$ ls -l /bin/ls\n" \ + "-rwxr-xr-x 1 root root 40816 Feb 5 07:45 /bin/ls*\n" + +#define chvt_trivial_usage \ + "N" +#define chvt_full_usage \ + "Changes the foreground virtual terminal to /dev/ttyN" + +#define clear_trivial_usage \ + "" +#define clear_full_usage \ + "Clear screen." + +#define cmp_trivial_usage \ + "FILE1 [FILE2]" +#define cmp_full_usage \ + "\t-s\tquiet mode - do not print\n" \ + "Compare files." + +#define cp_trivial_usage \ + "[OPTION]... SOURCE DEST" +#define cp_full_usage \ + "Copies SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.\n" \ + "\n" \ + "\t-a\tSame as -dpR\n" \ + "\t-d\tPreserves links\n" \ + "\t-p\tPreserves file attributes if possible\n" \ + "\t-f\tforce (implied; ignored) - always set\n" \ + "\t-R\tCopies directories recursively" + +#define cpio_trivial_usage \ + "-[dimtuv][F cpiofile]" +#define cpio_full_usage \ + "Extract or list files from a cpio archive\n" \ + "Main operation mode:\n" \ + "\td\t\tmake leading directories\n" \ + "\ti\t\textract\n" \ + "\tm\t\tpreserve mtime\n" \ + "\tt\t\tlist\n" \ + "\tu\t\tunconditional overwrite\t" \ + "\tF\t\tinput from file\t" + +#define cut_trivial_usage \ + "[OPTION]... [FILE]..." +#define cut_full_usage \ + "Prints selected fields from each input FILE to standard output.\n\n" \ + "Options:\n" \ + "\t-b LIST\t\tOutput only bytes from LIST\n" \ + "\t-c LIST\t\tOutput only characters from LIST\n" \ + "\t-d CHAR\t\tUse CHAR instead of tab as the field delimiter\n" \ + "\t-s\t\tOutput only the lines containing delimiter\n" \ + "\t-f N\t\tPrint only these fields\n" \ + "\t-n\t\tIgnored" +#define cut_example_usage \ + "$ echo "Hello world" | cut -f 1 -d ' '\n" \ + "Hello\n" \ + "$ echo "Hello world" | cut -f 2 -d ' '\n" \ + "world\n" + +#define date_trivial_usage \ + "[OPTION]... [+FORMAT]" +#define date_full_usage \ + "Displays the current time in the given FORMAT, or sets the system date.\n" \ + "\nOptions:\n" \ + "\t-R\t\tOutputs RFC-822 compliant date string\n" \ + "\t-d STRING\tdisplay time described by STRING, not `now'\n" \ + "\t-s\t\tSets time described by STRING\n" \ + "\t-u\t\tPrints or sets Coordinated Universal Time" +#define date_example_usage \ + "$ date\n" \ + "Wed Apr 12 18:52:41 MDT 2000\n" + +#define dc_trivial_usage \ + "expression ..." +#define dc_full_usage \ + "This is a Tiny RPN calculator that understands the\n" \ + "following operations: +, -, /, *, and, or, not, eor.\n" \ + "i.e., 'dc 2 2 add' -> 4, and 'dc 8 8 \\* 2 2 + /' -> 16" +#define dc_example_usage \ + "$ dc 2 2 +\n" \ + "4\n" \ + "$ dc 8 8 \* 2 2 + /\n" \ + "16\n" \ + "$ dc 0 1 and\n" \ + "0\n" \ + "$ dc 0 1 or\n" \ + "1\n" \ + "$ echo 72 9 div 8 mul | dc\n" \ + "64\n" + +#define dd_trivial_usage \ + "[if=FILE] [of=FILE] [bs=N] [count=N] [skip=N]\n" \ + "\t [seek=N] [conv=notrunc|noerror|sync]" +#define dd_full_usage \ + "Copy a file, converting and formatting according to options\n\n" \ + "\tif=FILE\t\tread from FILE instead of stdin\n" \ + "\tof=FILE\t\twrite to FILE instead of stdout\n" \ + "\tbs=N\t\tread and write N bytes at a time\n" \ + "\tcount=N\t\tcopy only N input blocks\n" \ + "\tskip=N\t\tskip N input blocks\n" \ + "\tseek=N\t\tskip N output blocks\n" \ + "\tconv=notrunc\tdon't truncate output file\n" \ + "\tconv=noerror\tcontinue after read errors\n" \ + "\tconv=sync\tpad blocks with zeros\n" \ + "\n" \ + "Numbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024),\n" \ + "MD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)." +#define dd_example_usage \ + "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" \ + "4+0 records in\n" \ + "4+0 records out\n" + +#define deallocvt_trivial_usage \ + "N" +#define deallocvt_full_usage \ + "Deallocate unused virtual terminal /dev/ttyN" + + +#ifdef BB_FEATURE_HUMAN_READABLE + #define USAGE_HUMAN_READABLE(a) a + #define USAGE_NOT_HUMAN_READABLE(a) +#else + #define USAGE_HUMAN_READABLE(a) + #define USAGE_NOT_HUMAN_READABLE(a) a +#endif +#define df_trivial_usage \ + "[-" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILESYSTEM ...]" +#define df_full_usage \ + "Print the filesystem space used and space available.\n\n" \ + "Options:\n" \ + USAGE_HUMAN_READABLE( \ + "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \ + "\t-m\tprint sizes in megabytes\n" \ + "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \ + "\n\t-k\tprint sizes in kilobytes(compatibility)") +#define df_example_usage \ + "$ df\n" \ + "Filesystem 1k-blocks Used Available Use% Mounted on\n" \ + "/dev/sda3 8690864 8553540 137324 98% /\n" \ + "/dev/sda1 64216 36364 27852 57% /boot\n" \ + "$ df /dev/sda3\n" \ + "Filesystem 1k-blocks Used Available Use% Mounted on\n" \ + "/dev/sda3 8690864 8553540 137324 98% /\n" + +#define dirname_trivial_usage \ + "[FILENAME ...]" +#define dirname_full_usage \ + "Strips non-directory suffix from FILENAME" +#define dirname_example_usage \ + "$ dirname /tmp/foo\n" \ + "/tmp\n" \ + "$ dirname /tmp/foo/\n" \ + "/tmp\n" + +#define dmesg_trivial_usage \ + "[-c] [-n LEVEL] [-s SIZE]" +#define dmesg_full_usage \ + "Prints or controls the kernel ring buffer\n\n" \ + "Options:\n" \ + "\t-c\t\tClears the ring buffer's contents after printing\n" \ + "\t-n LEVEL\tSets console logging level\n" \ + "\t-s SIZE\t\tUse a buffer of size SIZE" + +#define dos2unix_trivial_usage \ + "[option] [FILE]" +#define dos2unix_full_usage \ + "Converts FILE from dos format to unix format. When no option\n" \ + "is given, the input is converted to the opposite output format.\n" \ + "When no file is given, uses stdin for input and stdout for output.\n\n" \ + "Options:\n" \ + "\t-u\toutput will be in UNIX format\n" \ + "\t-d\toutput will be in DOS format" + +#define dpkg_trivial_usage \ + "-i package_file\n" \ + "[-CPru] package_name" +#define dpkg_full_usage \ + "\t-i\tInstall the package\n" \ + "\t-C\tConfigure an unpackaged package\n" \ + "\t-P\tPurge all files of a package\n" \ + "\t-r\tRemove all but the configuration files for a package\n" \ + "\t-u\tUnpack a package, but dont configure it\n" + +#define dpkg_deb_trivial_usage \ + "[-cefItxX] FILE [argument]" +#define dpkg_deb_full_usage \ + "Perform actions on debian packages (.debs)\n\n" \ + "Options:\n" \ + "\t-c\tList contents of filesystem tree\n" \ + "\t-e\tExtract control files to [argument] directory\n" \ + "\t-f\tDisplay control field name starting with [argument]\n" \ + "\t-I\tDisplay the control filenamed [argument]\n" \ + "\t-t\tExtract filesystem tree to stdout in tar format\n" \ + "\t-x\tExtract packages filesystem tree to directory\n" \ + "\t-X\tVerbose extract" +#define dpkg_deb_example_usage \ + "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n" + +#define du_trivial_usage \ + "[-lsx" USAGE_HUMAN_READABLE("hm") USAGE_NOT_HUMAN_READABLE("") "k] [FILE]..." +#define du_full_usage \ + "Summarizes disk space used for each FILE and/or directory.\n" \ + "Disk space is printed in units of 1024 bytes.\n\n" \ + "Options:\n" \ + "\t-l\tcount sizes many times if hard linked\n" \ + "\t-s\tdisplay only a total for each argument" \ + USAGE_HUMAN_READABLE( \ + "\n\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \ + "\t-m\tprint sizes in megabytes\n" \ + "\t-x\tskip directories on different filesystems\n" \ + "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \ + "\n\t-k\tprint sizes in kilobytes(compatibility)") +#define du_example_usage \ + "$ du\n" \ + "16 ./CVS\n" \ + "12 ./kernel-patches/CVS\n" \ + "80 ./kernel-patches\n" \ + "12 ./tests/CVS\n" \ + "36 ./tests\n" \ + "12 ./scripts/CVS\n" \ + "16 ./scripts\n" \ + "12 ./docs/CVS\n" \ + "104 ./docs\n" \ + "2417 .\n" + +#define dumpkmap_trivial_usage \ + "> keymap" +#define dumpkmap_full_usage \ + "Prints out a binary keyboard translation table to standard output." +#define dumpkmap_example_usage \ + "$ dumpkmap > keymap\n" + +#define dutmp_trivial_usage \ + "[FILE]" +#define dutmp_full_usage \ + "Dump utmp file format (pipe delimited) from FILE\n" \ + "or stdin to stdout. (i.e., 'dutmp /var/run/utmp')" +#define dutmp_example_usage \ + "$ dutmp /var/run/utmp\n" \ + "8|7||si|||0|0|0|955637625|760097|0\n" \ + "2|0|~|~~|reboot||0|0|0|955637625|782235|0\n" \ + "1|20020|~|~~|runlevel||0|0|0|955637625|800089|0\n" \ + "8|125||l4|||0|0|0|955637629|998367|0\n" \ + "6|245|tty1|1|LOGIN||0|0|0|955637630|998974|0\n" \ + "6|246|tty2|2|LOGIN||0|0|0|955637630|999498|0\n" \ + "7|336|pts/0|vt00andersen|andersen|:0.0|0|0|0|955637763|0|0\n" + +#define echo_trivial_usage \ + "[-neE] [ARG ...]" +#define echo_full_usage \ + "Prints the specified ARGs to stdout\n\n" \ + "Options:\n" \ + "\t-n\tsuppress trailing newline\n" \ + "\t-e\tinterpret backslash-escaped characters (i.e., \\t=tab)\n" \ + "\t-E\tdisable interpretation of backslash-escaped characters" +#define echo_example_usage \ + "$ echo "Erik is cool"\n" \ + "Erik is cool\n" \ + "$ echo -e "Erik\\nis\\ncool"\n" \ + "Erik\n" \ + "is\n" \ + "cool\n" \ + "$ echo "Erik\\nis\\ncool"\n" \ + "Erik\\nis\\ncool\n" + +#define env_trivial_usage \ + "[-iu] [-] [name=value]... [command]" +#define env_full_usage \ + "Prints the current environment or runs a program after setting\n" \ + "up the specified environment.\n\n" \ + "Options:\n" \ + "\t-, -i\tstart with an empty environment\n" \ + "\t-u\tremove variable from the environment\n" + +#define expr_trivial_usage \ + "EXPRESSION" +#define expr_full_usage \ + "Prints the value of EXPRESSION to standard output.\n\n" \ + "EXPRESSION may be:\n" \ + "\tARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n" \ + "\tARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n" \ + "\tARG1 < ARG2 ARG1 is less than ARG2\n" \ + "\tARG1 <= ARG2 ARG1 is less than or equal to ARG2\n" \ + "\tARG1 = ARG2 ARG1 is equal to ARG2\n" \ + "\tARG1 != ARG2 ARG1 is unequal to ARG2\n" \ + "\tARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n" \ + "\tARG1 > ARG2 ARG1 is greater than ARG2\n" \ + "\tARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n" \ + "\tARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n" \ + "\tARG1 * ARG2 arithmetic product of ARG1 and ARG2\n" \ + "\tARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n" \ + "\tARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n" \ + "\tSTRING : REGEXP anchored pattern match of REGEXP in STRING\n" \ + "\tmatch STRING REGEXP same as STRING : REGEXP\n" \ + "\tsubstr STRING POS LENGTH substring of STRING, POS counted from 1\n" \ + "\tindex STRING CHARS index in STRING where any CHARS is found,\n" \ + "\t or 0\n" \ + "\tlength STRING length of STRING\n" \ + "\tquote TOKEN interpret TOKEN as a string, even if\n" \ + "\t it is a keyword like `match' or an\n" \ + "\t operator like `/'\n" \ + "\t( EXPRESSION ) value of EXPRESSION\n\n" \ + "Beware that many operators need to be escaped or quoted for shells.\n" \ + "Comparisons are arithmetic if both ARGs are numbers, else\n" \ + "lexicographical. Pattern matches return the string matched between \n" \ + "\\( and \\) or null; if \\( and \\) are not used, they return the number \n" \ + "of characters matched or 0." + +#define false_trivial_usage \ + "" +#define false_full_usage \ + "Return an exit code of FALSE (1)." +#define false_example_usage \ + "$ false\n" \ + "$ echo $?\n" \ + "1\n" + +#define fbset_trivial_usage \ + "[options] [mode]" +#define fbset_full_usage \ + "Show and modify frame buffer settings" +#define fbset_example_usage \ + "$ fbset\n" \ + "mode "1024x768-76"\n" \ + "\t# D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz\n" \ + "\tgeometry 1024 768 1024 768 16\n" \ + "\ttimings 12714 128 32 16 4 128 4\n" \ + "\taccel false\n" \ + "\trgba 5/11,6/5,5/0,0/0\n" \ + "endmode\n" + +#define fdflush_trivial_usage \ + "DEVICE" +#define fdflush_full_usage \ + "Forces floppy disk drive to detect disk change" + +#ifdef BB_FEATURE_FIND_TYPE + #define USAGE_FIND_TYPE(a) a +#else + #define USAGE_FIND_TYPE(a) +#endif +#ifdef BB_FEATURE_FIND_PERM + #define USAGE_FIND_PERM(a) a +#else + #define USAGE_FIND_PERM(a) +#endif +#ifdef BB_FEATURE_FIND_MTIME + #define USAGE_FIND_MTIME(a) a +#else + #define USAGE_FIND_MTIME(a) +#endif +#ifdef BB_FEATURE_FIND_NEWER + #define USAGE_FIND_NEWER(a) a +#else + #define USAGE_FIND_NEWER(a) +#endif + +#define find_trivial_usage \ + "[PATH...] [EXPRESSION]" +#define find_full_usage \ + "Search for files in a directory hierarchy. The default PATH is\n" \ + "the current directory; default EXPRESSION is '-print'\n" \ + "\nEXPRESSION may consist of:\n" \ + "\t-follow\t\tDereference symbolic links.\n" \ + "\t-name PATTERN\tFile name (leading directories removed) matches PATTERN.\n" \ + "\t-print\t\tPrint (default and assumed).\n" \ + USAGE_FIND_TYPE( \ + "\n\t-type X\t\tFiletype matches X (where X is one of: f,d,l,b,c,...)" \ +) USAGE_FIND_PERM( \ + "\n\t-perm PERMS\tPermissions match any of (+NNN); all of (-NNN);\n\t\t\tor exactly (NNN)" \ +) USAGE_FIND_MTIME( \ + "\n\t-mtime TIME\tModified time is greater than (+N); less than (-N);\n\t\t\tor exactly (N) days"\ +) USAGE_FIND_NEWER( \ + "\n\t-newer FILE\tModified time is more recent than FILE's") +#define find_example_usage \ + "$ find / -name /etc/passwd\n" \ + "/etc/passwd\n" + +#define free_trivial_usage \ + "" +#define free_full_usage \ + "Displays the amount of free and used system memory" +#define free_example_usage \ + "$ free\n" \ + " total used free shared buffers\n" \ + " Mem: 257628 248724 8904 59644 93124\n" \ + " Swap: 128516 8404 120112\n" \ + "Total: 386144 257128 129016\n" \ + +#define freeramdisk_trivial_usage \ + "DEVICE" +#define freeramdisk_full_usage \ + "Frees all memory used by the specified ramdisk." +#define freeramdisk_example_usage \ + "$ freeramdisk /dev/ram2\n" + +#define fsck_minix_trivial_usage \ + "[-larvsmf] /dev/name" +#define fsck_minix_full_usage \ + "Performs a consistency check for MINIX filesystems.\n\n" \ + "Options:\n" \ + "\t-l\tLists all filenames\n" \ + "\t-r\tPerform interactive repairs\n" \ + "\t-a\tPerform automatic repairs\n" \ + "\t-v\tverbose\n" \ + "\t-s\tOutputs super-block information\n" \ + "\t-m\tActivates MINIX-like \"mode not cleared\" warnings\n" \ + "\t-f\tForce file system check." + +#define getopt_trivial_usage \ + "[OPTIONS]..." +#define getopt_full_usage \ + "Parse command options\n" \ + "\t-a, --alternative Allow long options starting with single -\n" \ + "\t-l, --longoptions=longopts Long options to be recognized\n" \ + "\t-n, --name=progname The name under which errors are reported\n" \ + "\t-o, --options=optstring Short options to be recognized\n" \ + "\t-q, --quiet Disable error reporting by getopt(3)\n" \ + "\t-Q, --quiet-output No normal output\n" \ + "\t-s, --shell=shell Set shell quoting conventions\n" \ + "\t-T, --test Test for getopt(1) version\n" \ + "\t-u, --unqote Do not quote the output" +#define getopt_example_usage \ + "$ cat getopt.test\n" \ + "#!/bin/sh\n" \ + "GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \\\n" \ + " -n 'example.busybox' -- "$@"`\n" \ + "if [ $? != 0 ] ; then exit 1 ; fi\n" \ + "eval set -- "$GETOPT"\n" \ + "while true ; do\n" \ + " case $1 in\n" \ + " -a|--a-long) echo \"Option a\" ; shift ;;\n" \ + " -b|--b-long) echo \"Option b, argument \`$2'\" ; shift 2 ;;\n" \ + " -c|--c-long)\n" \ + " case "$2" in\n" \ + " \"\") echo \"Option c, no argument\"; shift 2 ;;\n" \ + " *) echo \"Option c, argument \`$2'\" ; shift 2 ;;\n" \ + " esac ;;\n" \ + " --) shift ; break ;;\n" \ + " *) echo \"Internal error!\" ; exit 1 ;;\n" \ + " esac\n" \ + "done\n" + +#define grep_trivial_usage \ + "[-ihHnqvs] PATTERN [FILEs...]" +#define grep_full_usage \ + "Search for PATTERN in each FILE or standard input.\n\n" \ + "Options:\n" \ + "\t-H\tprefix output lines with filename where match was found\n" \ + "\t-h\tsuppress the prefixing filename on output\n" \ + "\t-i\tignore case distinctions\n" \ + "\t-l\tlist names of files that match\n" \ + "\t-n\tprint line number with output lines\n" \ + "\t-q\tbe quiet. Returns 0 if result was found, 1 otherwise\n" \ + "\t-v\tselect non-matching lines\n" \ + "\t-s\tsuppress file open/read error messages" +#define grep_example_usage \ + "$ grep root /etc/passwd\n" \ + "root:x:0:0:root:/root:/bin/bash\n" \ + "$ grep ^[rR]oo. /etc/passwd\n" \ + "root:x:0:0:root:/root:/bin/bash\n" + +#define gunzip_trivial_usage \ + "[OPTION]... FILE" +#define gunzip_full_usage \ + "Uncompress FILE (or standard input if FILE is '-').\n\n" \ + "Options:\n" \ + "\t-c\tWrite output to standard output\n" \ + "\t-t\tTest compressed file integrity" +#define gunzip_example_usage \ + "$ ls -la /tmp/BusyBox*\n" \ + "-rw-rw-r-- 1 andersen andersen 557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n" \ + "$ gunzip /tmp/BusyBox-0.43.tar.gz\n" \ + "$ ls -la /tmp/BusyBox*\n" \ + "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n" + +#define gzip_trivial_usage \ + "[OPTION]... FILE" +#define gzip_full_usage \ + "Compress FILE with maximum compression.\n" \ + "When FILE is '-', reads standard input. Implies -c.\n\n" \ + "Options:\n" \ + "\t-c\tWrite output to standard output instead of FILE.gz\n" \ + "\t-d\tdecompress" +#define gzip_example_usage \ + "$ ls -la /tmp/busybox*\n" \ + "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/busybox.tar\n" \ + "$ gzip /tmp/busybox.tar\n" \ + "$ ls -la /tmp/busybox*\n" \ + "-rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/busybox.tar.gz\n" + +#define halt_trivial_usage \ + "" +#define halt_full_usage \ + "Halt the system." + +#define head_trivial_usage \ + "[OPTION] [FILE]..." +#define head_full_usage \ + "Print first 10 lines of each FILE to standard output.\n" \ + "With more than one FILE, precede each with a header giving the\n" \ + "file name. With no FILE, or when FILE is -, read standard input.\n\n" \ + "Options:\n" \ + "\t-n NUM\t\tPrint first NUM lines instead of first 10" +#define head_example_usage \ + "$ head -n 2 /etc/passwd\n" \ + "root:x:0:0:root:/root:/bin/bash\n" \ + "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n" + +#define hostid_trivial_usage \ + "" +#define hostid_full_usage \ + "Print out a unique 32-bit identifier for the machine." + +#define hostname_trivial_usage \ + "[OPTION] {hostname | -F FILE}" +#define hostname_full_usage \ + "Get or set the hostname or DNS domain name. If a hostname is given\n" \ + "(or FILE with the -F parameter), the host name will be set.\n\n" \ + "Options:\n" \ + "\t-s\t\tShort\n" \ + "\t-i\t\tAddresses for the hostname\n" \ + "\t-d\t\tDNS domain name\n" \ + "\t-F, --file FILE\tUse the contents of FILE to specify the hostname" +#define hostname_example_usage \ + "$ hostname\n" \ + "sage \n" + +#define id_trivial_usage \ + "[OPTIONS]... [USERNAME]" +#define id_full_usage \ + "Print information for USERNAME or the current user\n\n" \ + "Options:\n" \ + "\t-g\tprints only the group ID\n" \ + "\t-u\tprints only the user ID\n" \ + "\t-n\tprint a name instead of a number (with for -ug)\n" \ + "\t-r\tprints the real user ID instead of the effective ID (with -ug)" +#define id_example_usage \ + "$ id\n" \ + "uid=1000(andersen) gid=1000(andersen)\n" + +#ifdef BB_FEATURE_IFCONFIG_SLIP + #define USAGE_SIOCSKEEPALIVE(a) a +#else + #define USAGE_SIOCSKEEPALIVE(a) +#endif +#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ + #define USAGE_IFCONFIG_MII(a) a +#else + #define USAGE_IFCONFIG_MII(a) +#endif +#ifdef BB_FEATURE_IFCONFIG_HW + #define USAGE_IFCONFIG_HW(a) a +#else + #define USAGE_IFCONFIG_HW(a) +#endif +#ifdef BB_FEATURE_IFCONFIG_STATUS + #define USAGE_IFCONFIG_OPT_A(a) a +#else + #define USAGE_IFCONFIG_OPT_A(a) +#endif + +#define ifconfig_trivial_usage \ + USAGE_IFCONFIG_OPT_A("[-a]") " [
]" +#define ifconfig_full_usage \ + "configure a network interface\n\n" \ + "Options:\n" \ + "\t[[-]broadcast [
]] [[-]pointopoint [
]]\n" \ + "\t[netmask
] [dstaddr
]\n" \ + USAGE_SIOCSKEEPALIVE("\t[outfill ] [keepalive ]\n") \ + "\t" USAGE_IFCONFIG_HW("[hw ether
] ") \ + "[metric ] [mtu ]\n" \ + "\t[[-]trailers] [[-]arp] [[-]allmulti]\n" \ + "\t[multicast] [[-]promisc] [txqueuelen ] [[-]dynamic]\n" \ + USAGE_IFCONFIG_MII("\t[mem_start ] [io_addr ] [irq ]\n") \ + "\t[up|down] ..." + +#define init_trivial_usage \ + "" +#define init_full_usage \ + "Init is the parent of all processes." +#define init_notes_usage \ +"This version of init is designed to be run only by the kernel.\n" \ +"\n" \ +"BusyBox init doesn't support multiple runlevels. The runlevels field of\n" \ +"the /etc/inittab file is completely ignored by BusyBox init. If you want \n" \ +"runlevels, use sysvinit.\n" \ +"\n" \ +"BusyBox init works just fine without an inittab. If no inittab is found, \n" \ +"it has the following default behavior:\n" \ +"\n" \ +" ::sysinit:/etc/init.d/rcS\n" \ +" ::askfirst:/bin/sh\n" \ +" ::ctrlaltdel:/sbin/reboot\n" \ +" ::shutdown:/sbin/swapoff -a\n" \ +" ::shutdown:/bin/umount -a -r\n" \ +" ::restart:/sbin/init\n" \ +"\n" \ +"if it detects that /dev/console is _not_ a serial console, it will also run:\n" \ +"\n" \ +" tty2::askfirst:/bin/sh\n" \ +" tty3::askfirst:/bin/sh\n" \ +" tty4::askfirst:/bin/sh\n" \ +"\n" \ +"If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" \ +"\n" \ +" :::\n" \ +"\n" \ +" : \n" \ +"\n" \ +" WARNING: This field has a non-traditional meaning for BusyBox init!\n" \ +" The id field is used by BusyBox init to specify the controlling tty for\n" \ +" the specified process to run on. The contents of this field are\n" \ +" appended to "/dev/" and used as-is. There is no need for this field to\n" \ +" be unique, although if it isn't you may have strange results. If this\n" \ +" field is left blank, the controlling tty is set to the console. Also\n" \ +" note that if BusyBox detects that a serial console is in use, then only\n" \ +" entries whose controlling tty is either the serial console or /dev/null\n" \ +" will be run. BusyBox init does nothing with utmp. We don't need no\n" \ +" stinkin' utmp.\n" \ +"\n" \ +" : \n" \ +"\n" \ +" The runlevels field is completely ignored.\n" \ +"\n" \ +" : \n" \ +"\n" \ +" Valid actions include: sysinit, respawn, askfirst, wait, \n" \ +" once, restart, ctrlaltdel, and shutdown.\n" \ +"\n" \ +" The available actions can be classified into two groups: actions\n" \ +" that are run only once, and actions that are re-run when the specified\n" \ +" process exits.\n" \ +"\n" \ +" Run only-once actions:\n" \ +"\n" \ +" 'sysinit' is the first item run on boot. init waits until all\n" \ +" sysinit actions are completed before continuing. Following the\n" \ +" completion of all sysinit actions, all 'wait' actions are run.\n" \ +" 'wait' actions, like 'sysinit' actions, cause init to wait until\n" \ +" the specified task completes. 'once' actions are asynchronous,\n" \ +" therefore, init does not wait for them to complete. 'restart' is\n" \ +" the action taken to restart the init process. By default this should\n" \ +" simply run /sbin/init, but can be a script which runs pivot_root or it\n" \ +" can do all sorts of other interesting things. The 'ctrlaltdel' init\n" \ +" actions are run when the system detects that someone on the system\n" \ +" console has pressed the CTRL-ALT-DEL key combination. Typically one\n" \ +" wants to run 'reboot' at this point to cause the system to reboot.\n" \ +" Finally the 'shutdown' action specifies the actions to taken when\n" \ +" init is told to reboot. Unmounting filesystems and disabling swap\n" \ +" is a very good here\n" \ +"\n" \ +" Run repeatedly actions:\n" \ +"\n" \ +" 'respawn' actions are run after the 'once' actions. When a process\n" \ +" started with a 'respawn' action exits, init automatically restarts\n" \ +" it. Unlike sysvinit, BusyBox init does not stop processes from\n" \ +" respawning out of control. The 'askfirst' actions acts just like\n" \ +" respawn, except that before running the specified process it\n" \ +" displays the line "Please press Enter to activate this console."\n" \ +" and then waits for the user to press enter before starting the\n" \ +" specified process. \n" \ +"\n" \ +" Unrecognized actions (like initdefault) will cause init to emit an\n" \ +" error message, and then go along with its business. All actions are\n" \ +" run in the order they appear in /etc/inittab.\n" \ +"\n" \ +" : \n" \ +"\n" \ +" Specifies the process to be executed and it's command line.\n" \ +"\n" \ +"Example /etc/inittab file:\n" \ +"\n" \ +" # This is run first except when booting in single-user mode.\n" \ +" #\n" \ +" ::sysinit:/etc/init.d/rcS\n" \ +" \n" \ +" # /bin/sh invocations on selected ttys\n" \ +" #\n" \ +" # Start an "askfirst" shell on the console (whatever that may be)\n" \ +" ::askfirst:-/bin/sh\n" \ +" # Start an "askfirst" shell on /dev/tty2-4\n" \ +" tty2::askfirst:-/bin/sh\n" \ +" tty3::askfirst:-/bin/sh\n" \ +" tty4::askfirst:-/bin/sh\n" \ +" \n" \ +" # /sbin/getty invocations for selected ttys\n" \ +" #\n" \ +" tty4::respawn:/sbin/getty 38400 tty4\n" \ +" tty5::respawn:/sbin/getty 38400 tty5\n" \ +" \n" \ +" \n" \ +" # Example of how to put a getty on a serial line (for a terminal)\n" \ +" #\n" \ +" #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" \ +" #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" \ +" #\n" \ +" # Example how to put a getty on a modem line.\n" \ +" #::respawn:/sbin/getty 57600 ttyS2\n" \ +" \n" \ +" # Stuff to do when restarting the init process\n" \ +" ::restart:/sbin/init\n" \ +" \n" \ +" # Stuff to do before rebooting\n" \ +" ::ctrlaltdel:/sbin/reboot\n" \ +" ::shutdown:/bin/umount -a -r\n" \ +" ::shutdown:/sbin/swapoff -a\n" + +#define insmod_trivial_usage \ + "[OPTION]... MODULE [symbol=value]..." +#define insmod_full_usage \ + "Loads the specified kernel modules into the kernel.\n\n" \ + "Options:\n" \ + "\t-f\tForce module to load into the wrong kernel version.\n" \ + "\t-k\tMake module autoclean-able.\n" \ + "\t-v\tverbose output\n" \ + "\t-L\tLock to prevent simultaneous loads of a module\n" \ + "\t-x\tdo not export externs" + +#define kill_trivial_usage \ + "[-signal] process-id [process-id ...]" +#define kill_full_usage \ + "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\ + "Options:\n" \ + "\t-l\tList all signal names and numbers." +#define kill_example_usage \ + "$ ps | grep apache\n" \ + "252 root root S [apache]\n" \ + "263 www-data www-data S [apache]\n" \ + "264 www-data www-data S [apache]\n" \ + "265 www-data www-data S [apache]\n" \ + "266 www-data www-data S [apache]\n" \ + "267 www-data www-data S [apache]\n" \ + "$ kill 252\n" + +#define killall_trivial_usage \ + "[-signal] process-name [process-name ...]" +#define killall_full_usage \ + "Send a signal (default is SIGTERM) to the specified process(es).\n\n"\ + "Options:\n" \ + "\t-l\tList all signal names and numbers." +#define killall_example_usage \ + "$ killall apache\n" + +#define klogd_trivial_usage \ + "-n" +#define klogd_full_usage \ + "Kernel logger.\n"\ + "Options:\n"\ + "\t-n\tRun as a foreground process." + +#define length_trivial_usage \ + "STRING" +#define length_full_usage \ + "Prints out the length of the specified STRING." +#define length_example_usage \ + "$ length Hello\n" \ + "5\n" + +#define ln_trivial_usage \ + "[OPTION] TARGET... LINK_NAME|DIRECTORY" +#define ln_full_usage \ + "Create a link named LINK_NAME or DIRECTORY to the specified TARGET\n"\ + "\nYou may use '--' to indicate that all following arguments are non-options.\n\n" \ + "Options:\n" \ + "\t-s\tmake symbolic links instead of hard links\n" \ + "\t-f\tremove existing destination files\n" \ + "\t-n\tno dereference symlinks - treat like normal file" +#define ln_example_usage \ + "$ ln -s BusyBox /tmp/ls\n" \ + "$ ls -l /tmp/ls\n" \ + "lrwxrwxrwx 1 root root 7 Apr 12 18:39 ls -> BusyBox*\n" + +#define loadacm_trivial_usage \ + "< mapfile" +#define loadacm_full_usage \ + "Loads an acm from standard input." +#define loadacm_example_usage \ + "$ loadacm < /etc/i18n/acmname\n" + +#define loadfont_trivial_usage \ + "< font" +#define loadfont_full_usage \ + "Loads a console font from standard input." +#define loadfont_example_usage \ + "$ loadfont < /etc/i18n/fontname\n" + +#define loadkmap_trivial_usage \ + "< keymap" +#define loadkmap_full_usage \ + "Loads a binary keyboard translation table from standard input." +#define loadkmap_example_usage \ + "$ loadkmap < /etc/i18n/lang-keymap\n" + +#define logger_trivial_usage \ + "[OPTION]... [MESSAGE]" +#define logger_full_usage \ + "Write MESSAGE to the system log. If MESSAGE is omitted, log stdin.\n\n" \ + "Options:\n" \ + "\t-s\tLog to stderr as well as the system log.\n" \ + "\t-t\tLog using the specified tag (defaults to user name).\n" \ + "\t-p\tEnter the message with the specified priority.\n" \ + "\t\tThis may be numerical or a ``facility.level'' pair." +#define logger_example_usage \ + "$ logger "hello"\n" + +#define logname_trivial_usage \ + "" +#define logname_full_usage \ + "Print the name of the current user." +#define logname_example_usage \ + "$ logname\n" \ + "root\n" + +#define logread_trivial_usage \ + "" + +#define logread_full_usage \ + "Shows the messages from syslogd (using circular buffer)." + +#define losetup_trivial_usage \ + "[OPTION]... LOOPDEVICE [FILE]" +#define losetup_full_usage \ + "Associate LOOPDEVICE with FILE.\n\n" \ + "Options:\n" \ + "\t-d\t\tDisassociate LOOPDEVICE.\n" \ + "\t-o OFFSET\tStart OFFSET bytes into FILE.\n" + +#ifdef BB_FEATURE_LS_TIMESTAMPS + #define USAGE_LS_TIMESTAMPS(a) a +#else + #define USAGE_LS_TIMESTAMPS(a) +#endif +#ifdef BB_FEATURE_LS_FILETYPES + #define USAGE_LS_FILETYPES(a) a +#else + #define USAGE_LS_FILETYPES(a) +#endif +#ifdef BB_FEATURE_LS_FOLLOWLINKS + #define USAGE_LS_FOLLOWLINKS(a) a +#else + #define USAGE_LS_FOLLOWLINKS(a) +#endif +#ifdef BB_FEATURE_LS_RECURSIVE + #define USAGE_LS_RECURSIVE(a) a +#else + #define USAGE_LS_RECURSIVE(a) +#endif +#ifdef BB_FEATURE_LS_SORTFILES + #define USAGE_LS_SORTFILES(a) a +#else + #define USAGE_LS_SORTFILES(a) +#endif +#ifdef BB_FEATURE_AUTOWIDTH + #define USAGE_AUTOWIDTH(a) a +#else + #define USAGE_AUTOWIDTH(a) +#endif +#define ls_trivial_usage \ + "[-1Aa" USAGE_LS_TIMESTAMPS("c") "Cd" USAGE_LS_TIMESTAMPS("e") USAGE_LS_FILETYPES("F") "iln" USAGE_LS_FILETYPES("p") USAGE_LS_FOLLOWLINKS("L") USAGE_LS_RECURSIVE("R") USAGE_LS_SORTFILES("rS") "s" USAGE_AUTOWIDTH("T") USAGE_LS_TIMESTAMPS("tu") USAGE_LS_SORTFILES("v") USAGE_AUTOWIDTH("w") "x" USAGE_LS_SORTFILES("X") USAGE_HUMAN_READABLE("h") USAGE_NOT_HUMAN_READABLE("") "k] [filenames...]" +#define ls_full_usage \ + "List directory contents\n\n" \ + "Options:\n" \ + "\t-1\tlist files in a single column\n" \ + "\t-A\tdo not list implied . and ..\n" \ + "\t-a\tdo not hide entries starting with .\n" \ + "\t-C\tlist entries by columns\n" \ + USAGE_LS_TIMESTAMPS("\t-c\twith -l: show ctime\n") \ + "\t-d\tlist directory entries instead of contents\n" \ + USAGE_LS_TIMESTAMPS("\t-e\tlist both full date and full time\n") \ + USAGE_LS_FILETYPES("\t-F\tappend indicator (one of */=@|) to entries\n") \ + "\t-i\tlist the i-node for each file\n" \ + "\t-l\tuse a long listing format\n" \ + "\t-n\tlist numeric UIDs and GIDs instead of names\n" \ + USAGE_LS_FILETYPES("\t-p\tappend indicator (one of /=@|) to entries\n") \ + USAGE_LS_FOLLOWLINKS("\t-L\tlist entries pointed to by symbolic links\n") \ + USAGE_LS_RECURSIVE("\t-R\tlist subdirectories recursively\n") \ + USAGE_LS_SORTFILES("\t-r\tsort the listing in reverse order\n") \ + USAGE_LS_SORTFILES("\t-S\tsort the listing by file size\n") \ + "\t-s\tlist the size of each file, in blocks\n" \ + USAGE_AUTOWIDTH("\t-T NUM\tassume Tabstop every NUM columns\n") \ + USAGE_LS_TIMESTAMPS("\t-t\twith -l: show modification time\n") \ + USAGE_LS_TIMESTAMPS("\t-u\twith -l: show access time\n") \ + USAGE_LS_SORTFILES("\t-v\tsort the listing by version\n") \ + USAGE_AUTOWIDTH("\t-w NUM\tassume the terminal is NUM columns wide\n") \ + "\t-x\tlist entries by lines instead of by columns\n" \ + USAGE_LS_SORTFILES("\t-X\tsort the listing by extension\n") \ + USAGE_HUMAN_READABLE( \ + "\t-h\tprint sizes in human readable format (e.g., 1K 243M 2G )\n" \ + "\t-k\tprint sizes in kilobytes(default)") USAGE_NOT_HUMAN_READABLE( \ + "\t-k\tprint sizes in kilobytes(compatibility)") + +#define lsmod_trivial_usage \ + "" +#define lsmod_full_usage \ + "List the currently loaded kernel modules." + +#define makedevs_trivial_usage \ + "NAME TYPE MAJOR MINOR FIRST LAST [s]" +#define makedevs_full_usage \ + "Creates a range of block or character special files\n\n" \ + "TYPEs include:\n" \ + "\tb:\tMake a block (buffered) device.\n" \ + "\tc or u:\tMake a character (un-buffered) device.\n" \ + "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes.\n\n" \ + "FIRST specifies the number appended to NAME to create the first device.\n" \ + "LAST specifies the number of the last item that should be created.\n" \ + "If 's' is the last argument, the base device is created as well.\n\n" \ + "For example:\n" \ + "\tmakedevs /dev/ttyS c 4 66 2 63 -> ttyS2-ttyS63\n" \ + "\tmakedevs /dev/hda b 3 0 0 8 s -> hda,hda1-hda8" +#define makedevs_example_usage \ + "$ makedevs /dev/ttyS c 4 66 2 63\n" \ + "[creates ttyS2-ttyS63]\n" \ + "$ makedevs /dev/hda b 3 0 0 8 s\n" \ + "[creates hda,hda1-hda8]\n" + +#define md5sum_trivial_usage \ + "[OPTION] [FILE]...\n" \ + "or: md5sum [OPTION] -c [FILE]" +#define md5sum_full_usage \ + "Print or check MD5 checksums.\n\n" \ + "Options:\n" \ + "With no FILE, or when FILE is -, read standard input.\n\n" \ + "\t-b\tread files in binary mode\n" \ + "\t-c\tcheck MD5 sums against given list\n" \ + "\t-t\tread files in text mode (default)\n" \ + "\t-g\tread a string\n" \ + "\nThe following two options are useful only when verifying checksums:\n" \ + "\t-s\tdon't output anything, status code shows success\n" \ + "\t-w\twarn about improperly formated MD5 checksum lines" +#define md5sum_example_usage \ + "$ md5sum < busybox\n" \ + "6fd11e98b98a58f64ff3398d7b324003\n" \ + "$ md5sum busybox\n" \ + "6fd11e98b98a58f64ff3398d7b324003 busybox\n" \ + "$ md5sum -c -\n" \ + "6fd11e98b98a58f64ff3398d7b324003 busybox\n" \ + "busybox: OK\n" \ + "^D\n" + +#define mkdir_trivial_usage \ + "[OPTION] DIRECTORY..." +#define mkdir_full_usage \ + "Create the DIRECTORY(ies) if they do not already exist\n\n" \ + "Options:\n" \ + "\t-m\tset permission mode (as in chmod), not rwxrwxrwx - umask\n" \ + "\t-p\tno error if existing, make parent directories as needed" +#define mkdir_example_usage \ + "$ mkdir /tmp/foo\n" \ + "$ mkdir /tmp/foo\n" \ + "/tmp/foo: File exists\n" \ + "$ mkdir /tmp/foo/bar/baz\n" \ + "/tmp/foo/bar/baz: No such file or directory\n" \ + "$ mkdir -p /tmp/foo/bar/baz\n" + +#define mkfifo_trivial_usage \ + "[OPTIONS] name" +#define mkfifo_full_usage \ + "Creates a named pipe (identical to 'mknod name p')\n\n" \ + "Options:\n" \ + "\t-m\tcreate the pipe using the specified mode (default a=rw)" + +#define mkfs_minix_trivial_usage \ + "[-c | -l filename] [-nXX] [-iXX] /dev/name [blocks]" +#define mkfs_minix_full_usage \ + "Make a MINIX filesystem.\n\n" \ + "Options:\n" \ + "\t-c\t\tCheck the device for bad blocks\n" \ + "\t-n [14|30]\tSpecify the maximum length of filenames\n" \ + "\t-i INODES\tSpecify the number of inodes for the filesystem\n" \ + "\t-l FILENAME\tRead the bad blocks list from FILENAME\n" \ + "\t-v\t\tMake a Minix version 2 filesystem" + +#define mknod_trivial_usage \ + "[OPTIONS] NAME TYPE MAJOR MINOR" +#define mknod_full_usage \ + "Create a special file (block, character, or pipe).\n\n" \ + "Options:\n" \ + "\t-m\tcreate the special file using the specified mode (default a=rw)\n\n" \ + "TYPEs include:\n" \ + "\tb:\tMake a block (buffered) device.\n" \ + "\tc or u:\tMake a character (un-buffered) device.\n" \ + "\tp:\tMake a named pipe. MAJOR and MINOR are ignored for named pipes." +#define mknod_example_usage \ + "$ mknod /dev/fd0 b 2 0 \n" \ + "$ mknod -m 644 /tmp/pipe p\n" + +#define mkswap_trivial_usage \ + "[-c] [-v0|-v1] device [block-count]" +#define mkswap_full_usage \ + "Prepare a disk partition to be used as a swap partition.\n\n" \ + "Options:\n" \ + "\t-c\t\tCheck for read-ability.\n" \ + "\t-v0\t\tMake version 0 swap [max 128 Megs].\n" \ + "\t-v1\t\tMake version 1 swap [big!] (default for kernels >\n\t\t\t2.1.117).\n" \ + "\tblock-count\tNumber of block to use (default is entire partition)." + +#define mktemp_trivial_usage \ + "[-q] TEMPLATE" +#define mktemp_full_usage \ + "Creates a temporary file with its name based on TEMPLATE.\n" \ + "TEMPLATE is any name with six `Xs' (i.e., /tmp/temp.XXXXXX)." +#define mktemp_example_usage \ + "$ mktemp /tmp/temp.XXXXXX\n" \ + "/tmp/temp.mWiLjM\n" \ + "$ ls -la /tmp/temp.mWiLjM\n" \ + "-rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM\n" + +#define modprobe_trivial_usage \ + "modprobe [ -adnqv ] [ -C config ] module [ symbol=value ... ]\n" \ + "modprobe [ -adnqv ] [ -C config ] [ -t type ] pattern\n" \ + "modprobe -l [ -C config ] [ -t type ] pattern\n" \ + "modprobe -c [ -C config ]\n" \ + "modprobe -r [ -dnv ] [ -C config ] [ module ...]\n" \ + "modprobe -V\n" +#define modprobe_full_usage \ + "Used to load kernel modules and automatically load their dependancies." \ + "USAGE:\n" \ + "\tmodprobe [ -adnqv ] [ -C config ] module [ symbol=value ... ]\n" \ + "\tmodprobe [ -adnqv ] [ -C config ] [ -t type ] pattern\n" \ + "\tmodprobe -l [ -C config ] [ -t type ] pattern\n" \ + "\tmodprobe -c [ -C config ]\n" \ + "\tmodprobe -r [ -dnv ] [ -C config ] [ module ...]\n" \ + "\tmodprobe -V\n" \ + "\n" \ + "OPTIONS\n" \ + "\t-a (*** not supported ***)\n" \ + "\t Load all matching modules instead of stopping after\n" \ + "\t the first successful loading.\n" \ + "\n" \ + "\t-c (*** not supported ***)\n" \ + "\t Show the currently used configuration.\n" \ + "\n" \ + "\t-d\n" \ + "\t Show information about the internal representation\n" \ + "\t of the stack of modules.\n" \ + "\n" \ + "\t-k\n" \ + "\t Set 'autoclean' on loaded modules. Used by the\n" \ + "\t kernel when it calls on modprobe to satify a miss­\n" \ + "\t ing feature (supplied as a module). The -q option\n" \ + "\t is implied by -k. These options will automatically\n" \ + "\t be sent to insmod.\n" \ + "\n" \ + "\t-l (*** not supported ***)\n" \ + "\t List matching modules.\n" \ + "\n" \ + "\t-n\n" \ + "\t Don't actually perform the action, just show what\n" \ + "\t would be done.\n" \ + "\n" \ + "\t-q\n" \ + "\t Do not complain about insmod failing to install a\n" \ + "\t module. Continue as normal, but silently, with\n" \ + "\t other possibilities for modprobe to test. This\n" \ + "\t option will automatically be sent to insmod.\n" \ + "\n" \ + "\t-r\n" \ + "\t Remove module (stacks) or do autoclean, depending\n" \ + "\t on whether there are any modules mentioned on the\n" \ + "\t command line.\n" \ + "\n" \ + "\t-s\n" \ + "\t Report via syslog instead of stderr. This options\n" \ + "\t will automatically be sent to insmod.\n" \ + "\n" \ + "\t-t type (*** not supported ***)\n" \ + "\t Only consider modules of this type (tag).\n" \ + "\n" \ + "\t-v\n" \ + "\t Print all commands as they are executed.\n" \ + "\n" \ + "\t-V\n" \ + "\t Show the release version of modprobe.\n" \ + "\n" \ + "\t-C configfile (*** not supported ***)\n" \ + "\t Use the file configfile instead of (the optional)\n" \ + "\t /etc/modules.conf to specify the configuration.\n" \ + "\t The environment variable MODULECONF can also be\n" \ + "\t used to select (and override) a different configu­\n" \ + "\t ration file from the default /etc/modules.conf (or\n" \ + "\t /etc/conf.modules (depreciated)).\n" +#define modprobe_example_usage \ + "$ modprobe pcnet_cs\n" \ + "$ modprobe -r pcnet_cs\n" + +#define more_trivial_usage \ + "[FILE ...]" +#define more_full_usage \ + "More is a filter for viewing FILE one screenful at a time." +#define more_example_usage \ + "$ dmesg | more\n" + +#ifdef BB_FEATURE_MOUNT_LOOP + #define USAGE_MOUNT_LOOP(a) a +#else + #define USAGE_MOUNT_LOOP(a) +#endif +#ifdef BB_FEATURE_MTAB_SUPPORT + #define USAGE_MTAB(a) a +#else + #define USAGE_MTAB(a) +#endif +#define mount_trivial_usage \ + "[flags] DEVICE NODE [-o options,more-options]" +#define mount_full_usage \ + "Mount a filesystem\n\n" \ + "Flags:\n" \ + "\t-a:\t\tMount all filesystems in fstab.\n" \ + USAGE_MTAB( \ + "\t-f:\t\t\"Fake\" Add entry to mount table but don't mount it.\n" \ + "\t-n:\t\tDon't write a mount table entry.\n" \ + ) \ + "\t-o option:\tOne of many filesystem options, listed below.\n" \ + "\t-r:\t\tMount the filesystem read-only.\n" \ + "\t-t fs-type:\tSpecify the filesystem type.\n" \ + "\t-w:\t\tMount for reading and writing (default).\n" \ + "\n" \ + "Options for use with the \"-o\" flag:\n" \ + "\tasync/sync:\tWrites are asynchronous / synchronous.\n" \ + "\tatime/noatime:\tEnable / disable updates to inode access times.\n" \ + "\tdev/nodev:\tAllow use of special device files / disallow them.\n" \ + "\texec/noexec:\tAllow use of executable files / disallow them.\n" \ + USAGE_MOUNT_LOOP( \ + "\tloop:\t\tMounts a file via loop device.\n" \ + ) \ + "\tsuid/nosuid:\tAllow set-user-id-root programs / disallow them.\n" \ + "\tremount:\tRe-mount a mounted filesystem, changing its flags.\n" \ + "\tro/rw:\t\tMount for read-only / read-write.\n" \ + "\tbind:\t\tUse the linux 2.4.x \"bind\" feature.\n" \ + "\nThere are EVEN MORE flags that are specific to each filesystem.\n" \ + "You'll have to see the written documentation for those filesystems." +#define mount_example_usage \ + "$ mount\n" \ + "/dev/hda3 on / type minix (rw)\n" \ + "proc on /proc type proc (rw)\n" \ + "devpts on /dev/pts type devpts (rw)\n" \ + "$ mount /dev/fd0 /mnt -t msdos -o ro\n" \ + "$ mount /tmp/diskimage /opt -t ext2 -o loop\n" + +#define mt_trivial_usage \ + "[-f device] opcode value" +#define mt_full_usage \ + "Control magnetic tape drive operation\n" \ + "\nAvailable Opcodes:\n\n" \ + "bsf bsfm bsr bss datacompression drvbuffer eof eom erase\n" \ + "fsf fsfm fsr fss load lock mkpart nop offline ras1 ras2\n" \ + "ras3 reset retension rew rewoffline seek setblk setdensity\n" \ + "setpart tell unload unlock weof wset" + +#define mv_trivial_usage \ + "SOURCE DEST\n" \ + "or: mv SOURCE... DIRECTORY" +#define mv_full_usage \ + "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY." +#define mv_example_usage \ + "$ mv /tmp/foo /bin/bar\n" + +#define nc_trivial_usage \ + "[OPTIONS] [IP] [port]" +#define nc_full_usage \ + "Netcat opens a pipe to IP:port\n\n" \ + "Options:\n" \ + "\t-l\t\tlisten mode, for inbound connects\n" \ + "\t-p PORT\t\tlocal port number\n" \ + "\t-e PROG\t\tprogram to exec after connect (dangerous!)" +#define nc_example_usage \ + "$ nc foobar.somedomain.com 25\n" \ + "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" \ + "help\n" \ + "214-Commands supported:\n" \ + "214- HELO EHLO MAIL RCPT DATA AUTH\n" \ + "214 NOOP QUIT RSET HELP\n" \ + "quit\n" \ + "221 foobar closing connection\n" + +#define nslookup_trivial_usage \ + "[HOST] [SERVER]" +#define nslookup_full_usage \ + "Queries the nameserver for the IP address of the given HOST\n" \ + "optionally using a specified DNS server" +#define nslookup_example_usage \ + "$ nslookup localhost\n" \ + "Server: default\n" \ + "Address: default\n" \ + "\n" \ + "Name: debian\n" \ + "Address: 127.0.0.1\n" + +#define pidof_trivial_usage \ + "process-name [process-name ...]" +#define pidof_full_usage \ + "Lists the PIDs of all processes with names that match the names on the command line" +#define pidof_example_usage \ + "$ pidof init\n" \ + "1\n" + +#ifndef BB_FEATURE_FANCY_PING +#define ping_trivial_usage "host" +#define ping_full_usage "Send ICMP ECHO_REQUEST packets to network hosts" +#else +#define ping_trivial_usage \ + "[OPTION]... host" +#define ping_full_usage \ + "Send ICMP ECHO_REQUEST packets to network hosts.\n\n" \ + "Options:\n" \ + "\t-c COUNT\tSend only COUNT pings.\n" \ + "\t-s SIZE\t\tSend SIZE data bytes in packets (default=56).\n" \ + "\t-q\t\tQuiet mode, only displays output at start\n" \ + "\t\t\tand when finished." +#endif +#define ping_example_usage \ + "$ ping localhost\n" \ + "PING slag (127.0.0.1): 56 data bytes\n" \ + "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" \ + "\n" \ + "--- debian ping statistics ---\n" \ + "1 packets transmitted, 1 packets received, 0% packet loss\n" \ + "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" + +#define pivot_root_trivial_usage \ + "NEW_ROOT PUT_OLD" +#define pivot_root_full_usage \ + "Move the current root file system to PUT_OLD and make NEW_ROOT\n" \ + "the new root file system." + +#define poweroff_trivial_usage \ + "" +#define poweroff_full_usage \ + "Halt the system and request that the kernel shut off the power." + +#define printf_trivial_usage \ + "FORMAT [ARGUMENT...]" +#define printf_full_usage \ + "Formats and prints ARGUMENT(s) according to FORMAT,\n" \ + "Where FORMAT controls the output exactly as in C printf." +#define printf_example_usage \ + "$ printf "Val=%d\\n" 5\n" \ + "Val=5\n" + +#define ps_trivial_usage \ + "" +#define ps_full_usage \ + "Report process status\n" \ + "\nThis version of ps accepts no options." +#define ps_example_usage \ + "$ ps\n" \ + " PID Uid Gid State Command\n" \ + " 1 root root S init\n" \ + " 2 root root S [kflushd]\n" \ + " 3 root root S [kupdate]\n" \ + " 4 root root S [kpiod]\n" \ + " 5 root root S [kswapd]\n" \ + " 742 andersen andersen S [bash]\n" \ + " 743 andersen andersen S -bash\n" \ + " 745 root root S [getty]\n" \ + " 2990 andersen andersen R ps\n" + +#define pwd_trivial_usage \ + "" +#define pwd_full_usage \ + "Print the full filename of the current working directory." +#define pwd_example_usage \ + "$ pwd\n" \ + "/root\n" + +#define rdate_trivial_usage \ + "[OPTION] HOST" +#define rdate_full_usage \ + "Get and possibly set the system date and time from a remote HOST.\n\n" \ + "Options:\n" \ + "\t-s\tSet the system date and time (default).\n" \ + "\t-p\tPrint the date and time." + +#define readlink_trivial_usage \ + "" +#define readlink_full_usage \ + "Read a symbolic link." + +#define reboot_trivial_usage \ + "" +#define reboot_full_usage \ + "Reboot the system." + +#define renice_trivial_usage \ + "priority pid [pid ...]" +#define renice_full_usage \ + "Changes priority of running processes. Allowed priorities range\n" \ + "from 20 (the process runs only when nothing else is running) to 0\n" \ + "(default priority) to -20 (almost nothing else ever gets to run)." + +#define reset_trivial_usage \ + "" +#define reset_full_usage \ + "Resets the screen." + +#define rm_trivial_usage \ + "[OPTION]... FILE..." +#define rm_full_usage \ + "Remove (unlink) the FILE(s). You may use '--' to\n" \ + "indicate that all following arguments are non-options.\n\n" \ + "Options:\n" \ + "\t-i\t\talways prompt before removing each destination" \ + "\t-f\t\tremove existing destinations, never prompt\n" \ + "\t-r or -R\tremove the contents of directories recursively" +#define rm_example_usage \ + "$ rm -rf /tmp/foo\n" + +#define rmdir_trivial_usage \ + "[OPTION]... DIRECTORY..." +#define rmdir_full_usage \ + "Remove the DIRECTORY(ies), if they are empty." +#define rmdir_example_usage \ + "# rmdir /tmp/foo\n" + +#define rmmod_trivial_usage \ + "[OPTION]... [MODULE]..." +#define rmmod_full_usage \ + "Unloads the specified kernel modules from the kernel.\n\n" \ + "Options:\n" \ + "\t-a\tTry to remove all unused kernel modules." +#define rmmod_example_usage \ + "$ rmmod tulip\n" + +#define route_trivial_usage \ + "[{add|del|flush}]" +#define route_full_usage \ + "Edit the kernel's routing tables" + +#define rpm2cpio_trivial_usage \ + "package.rpm" +#define rpm2cpio_full_usage \ + "Outputs a cpio archive of the rpm file." + +#define sed_trivial_usage \ + "[-nef] pattern [files...]" +#define sed_full_usage \ + "Options:\n" \ + "\t-n\t\tsuppress automatic printing of pattern space\n" \ + "\t-e script\tadd the script to the commands to be executed\n" \ + "\t-f scriptfile\tadd the contents of script-file to the commands to be executed\n" \ + "\n" \ + "If no -e or -f is given, the first non-option argument is taken as the\n" \ + "sed script to interpret. All remaining arguments are names of input\n" \ + "files; if no input files are specified, then the standard input is read." +#define sed_example_usage \ + "$ echo "foo" | sed -e 's/f[a-zA-Z]o/bar/g'\n" \ + "bar\n" + +#define setkeycodes_trivial_usage \ + "SCANCODE KEYCODE ..." +#define setkeycodes_full_usage \ + "Set entries into the kernel's scancode-to-keycode map,\n" \ + "allowing unusual keyboards to generate usable keycodes.\n\n" \ + "SCANCODE may be either xx or e0xx (hexadecimal),\n" \ + "and KEYCODE is given in decimal" +#define setkeycodes_example_usage \ + "$ setkeycodes e030 127\n" + +#define lash_trivial_usage \ + "[FILE]...\n" \ + "or: sh -c command [args]..." +#define lash_full_usage \ + "lash: The BusyBox LAme SHell (command interpreter)" +#define lash_notes_usage \ +"This command does not yet have proper documentation.\n" \ +"\n" \ +"Use lash just as you would use any other shell. It properly handles pipes,\n" \ +"redirects, job control, can be used as the shell for scripts, and has a\n" \ +"sufficient set of builtins to do what is needed. It does not (yet) support\n" \ +"Bourne Shell syntax. If you need things like "if-then-else", "while", and such\n" \ +"use ash or bash. If you just need a very simple and extremely small shell,\n" \ +"this will do the job." + +#define sleep_trivial_usage \ + "N" +#define sleep_full_usage \ + "Pause for N seconds." +#define sleep_example_usage \ + "$ sleep 2\n" \ + "[2 second delay results]\n" + + +#ifdef BB_FEATURE_SORT_UNIQUE + #define USAGE_SORT_UNIQUE(a) a +#else + #define USAGE_SORT_UNIQUE(a) +#endif +#ifdef BB_FEATURE_SORT_REVERSE + #define USAGE_SORT_REVERSE(a) a +#else + #define USAGE_SORT_REVERSE(a) +#endif +#define sort_trivial_usage \ + "[-n" USAGE_SORT_REVERSE("r") USAGE_SORT_UNIQUE("u") "] [FILE]..." +#define sort_full_usage \ + "Sorts lines of text in the specified files\n\n"\ + "Options:\n" \ + USAGE_SORT_UNIQUE("\t-u\tsuppress duplicate lines\n") \ + USAGE_SORT_REVERSE("\t-r\tsort in reverse order\n") \ + "\t-n\tsort numerics" +#define sort_example_usage \ + "$ echo -e \"e\\nf\\nb\\nd\\nc\\na\" | sort\n" \ + "a\n" \ + "b\n" \ + "c\n" \ + "d\n" \ + "e\n" \ + "f\n" + +#define strings_trivial_usage \ + "[-afo] [-n length] [file ... ]" +#define strings_full_usage \ + "Display printable strings in a binary file." \ + "\n\nOptions:" \ + "\n\t-f\tPrecede each string with the name of the file where it was found." \ + "\n\t-n N\tSpecifies that at least N characters forms a sequence (default 4)" \ + "\n\t-o\tEach string is preceded by its decimal offset in the file." + +#define stty_trivial_usage \ + "[-a|g] [-F DEVICE] [SETTING]..." +#define stty_full_usage \ + "Without arguments, prints baud rate, line discipline," \ + "\nand deviations from stty sane." \ + "\n\nOptions:" \ + "\n\t-F DEVICE\topen device instead of stdin" \ + "\n\t-a\t\tprint all current settings in human-readable form" \ + "\n\t-g\t\tprint in stty-readable form" \ + "\n\t[SETTING]\tsee manpage" + +#define swapoff_trivial_usage \ + "[OPTION] [DEVICE]" +#define swapoff_full_usage \ + "Stop swapping virtual memory pages on DEVICE.\n\n" \ + "Options:\n" \ + "\t-a\tStop swapping on all swap devices" + +#define swapon_trivial_usage \ + "[OPTION] [DEVICE]" +#define swapon_full_usage \ + "Start swapping virtual memory pages on DEVICE.\n\n" \ + "Options:\n" \ + "\t-a\tStart swapping on all swap devices" + +#define sync_trivial_usage \ + "" +#define sync_full_usage \ + "Write all buffered filesystem blocks to disk." + + +#ifdef BB_FEATURE_REMOTE_LOG + #define USAGE_REMOTE_LOG(a) a +#else + #define USAGE_REMOTE_LOG(a) +#endif +#define syslogd_trivial_usage \ + "[OPTION]..." +#define syslogd_full_usage \ + "Linux system and kernel logging utility.\n" \ + "Note that this version of syslogd ignores /etc/syslog.conf.\n\n" \ + "Options:\n" \ + "\t-m NUM\t\tInterval between MARK lines (default=20min, 0=off)\n" \ + "\t-n\t\tRun as a foreground process\n" \ + "\t-O FILE\t\tUse an alternate log file (default=/var/log/messages)" \ + USAGE_REMOTE_LOG( \ + "\n\t-R HOST[:PORT]\tLog to IP or hostname on PORT (default PORT=514/UDP)\n" \ + "\t-L\t\tLog locally and via network logging (default is network only)") +#define syslogd_example_usage \ + "$ syslogd -R masterlog:514\n" \ + "$ syslogd -R 192.168.1.1:601\n" + + +#ifndef BB_FEATURE_FANCY_TAIL + #define USAGE_UNSIMPLE_TAIL(a) +#else + #define USAGE_UNSIMPLE_TAIL(a) a +#endif +#define tail_trivial_usage \ + "[OPTION]... [FILE]..." +#define tail_full_usage \ + "Print last 10 lines of each FILE to standard output.\n" \ + "With more than one FILE, precede each with a header giving the\n" \ + "file name. With no FILE, or when FILE is -, read standard input.\n\n" \ + "Options:\n" \ + USAGE_UNSIMPLE_TAIL("\t-c N[kbm]\toutput the last N bytes\n") \ + "\t-n N[kbm]\tprint last N lines instead of last 10\n" \ + "\t-f\t\toutput data as the file grows" \ + USAGE_UNSIMPLE_TAIL( "\n\t-q\t\tnever output headers giving file names\n" \ + "\t-s SEC\t\twait SEC seconds between reads with -f\n" \ + "\t-v\t\talways output headers giving file names\n\n" \ + "If the first character of N (bytes or lines) is a '+', output begins with \n" \ + "the Nth item from the start of each file, otherwise, print the last N items\n" \ + "in the file. N bytes may be suffixed by k (x1024), b (x512), or m (1024^2)." ) +#define tail_example_usage \ + "$ tail -n 1 /etc/resolv.conf\n" \ + "nameserver 10.0.0.1\n" + +#ifdef BB_FEATURE_TAR_CREATE + #define USAGE_TAR_CREATE(a) a +#else + #define USAGE_TAR_CREATE(a) +#endif +#ifdef BB_FEATURE_TAR_EXCLUDE + #define USAGE_TAR_EXCLUDE(a) a +#else + #define USAGE_TAR_EXCLUDE(a) +#endif +#define tar_trivial_usage \ + "-[" USAGE_TAR_CREATE("c") "xtvO] " \ + USAGE_TAR_EXCLUDE("[--exclude FILE] [-X FILE]") \ + "[-f TARFILE] [-C DIR] [FILE(s)] ..." +#define tar_full_usage \ + "Create, extract, or list files from a tar file.\n\n" \ + "Options:\n" \ + USAGE_TAR_CREATE("\tc\t\tcreate\n") \ + "\tx\t\textract\n" \ + "\tt\t\tlist\n" \ + "\nFile selection:\n" \ + "\tf\t\tname of TARFILE or \"-\" for stdin\n" \ + "\tO\t\textract to stdout\n" \ + USAGE_TAR_EXCLUDE( \ + "\texclude\t\tfile to exclude\n" \ + "\tX\t\tfile with names to exclude\n" \ + ) \ + "\tC\t\tchange to directory DIR before operation\n" \ + "\tv\t\tverbosely list files processed" +#define tar_example_usage \ + "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" \ + "$ tar -cf /tmp/tarball.tar /usr/local\n" + +#define tee_trivial_usage \ + "[OPTION]... [FILE]..." +#define tee_full_usage \ + "Copy standard input to each FILE, and also to standard output.\n\n" \ + "Options:\n" \ + "\t-a\tappend to the given FILEs, do not overwrite" +#define tee_example_usage \ + "$ echo "Hello" | tee /tmp/foo\n" \ + "$ cat /tmp/foo\n" \ + "Hello\n" + +#define telnet_trivial_usage \ + "HOST [PORT]" +#define telnet_full_usage \ + "Telnet is used to establish interactive communication with another\n"\ + "computer over a network using the TELNET protocol." + +#define test_trivial_usage \ + "EXPRESSION\n or [ EXPRESSION ]" +#define test_full_usage \ + "Checks file types and compares values returning an exit\n" \ + "code determined by the value of EXPRESSION." +#define test_example_usage \ + "$ test 1 -eq 2\n" \ + "$ echo $?\n" \ + "1\n" \ + "$ test 1 -eq 1\n" \ + "$ echo $? \n" \ + "0\n" \ + "$ [ -d /etc ]\n" \ + "$ echo $?\n" \ + "0\n" \ + "$ [ -d /junk ]\n" \ + "$ echo $?\n" \ + "1\n" + +#ifdef BB_FEATURE_TFTP_GET + #define USAGE_TFTP_GET(a) a +#else + #define USAGE_TFTP_GET(a) +#endif +#ifdef BB_FEATURE_TFTP_PUT + #define USAGE_TFTP_PUT(a) a +#else + #define USAGE_TFTP_PUT(a) +#endif + +#define time_trivial_usage \ + "[OPTION]... COMMAND [ARGS...]" +#define time_full_usage \ + "Runs the program COMMAND with arguments ARGS. When COMMAND finishes,\n" + "COMMAND's resource usage information is displayed\n\n" + "Options:\n" \ + "\t-v\tDisplays verbose resource usage information." + +#define tftp_trivial_usage \ + "[OPTION]... HOST [PORT]" +#define tftp_full_usage \ + "Transfers a file from/to a tftp server using \"octet\" mode.\n\n" \ + "Options:\n" \ + "\t-b SIZE\tTransfer blocks of SIZE octets.\n" \ + USAGE_TFTP_GET( \ + "\t-g\tGet file.\n" \ + ) \ + "\t-l FILE\tTransfer local FILE.\n" \ + USAGE_TFTP_PUT( \ + "\t-p\tPut file.\n" \ + ) \ + "\t-r FILE\tTransfer remote FILE.\n" + +#define top_trivial_usage \ + "[-d ]" +#define top_full_usage \ + "top provides an view of processor activity in real time.\n" \ + "This utility reads the status for all processes in /proc each \n" \ + "and shows the status for however many processes will fit on the screen.\n" \ + "This utility will not show processes that are started after program startup,\n" \ + "but it will show the EXIT status for and PIDs that exit while it is running." + +#define touch_trivial_usage \ + "[-c] FILE [FILE ...]" +#define touch_full_usage \ + "Update the last-modified date on the given FILE[s].\n\n" \ + "Options:\n" \ + "\t-c\tDo not create any files" +#define touch_example_usage \ + "$ ls -l /tmp/foo\n" \ + "/bin/ls: /tmp/foo: No such file or directory\n" \ + "$ touch /tmp/foo\n" \ + "$ ls -l /tmp/foo\n" \ + "-rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo\n" + +#define tr_trivial_usage \ + "[-cds] STRING1 [STRING2]" +#define tr_full_usage \ + "Translate, squeeze, and/or delete characters from\n" \ + "standard input, writing to standard output.\n\n" \ + "Options:\n" \ + "\t-c\ttake complement of STRING1\n" \ + "\t-d\tdelete input characters coded STRING1\n" \ + "\t-s\tsqueeze multiple output characters of STRING2 into one character" +#define tr_example_usage \ + "$ echo "gdkkn vnqkc" | tr [a-y] [b-z]\n" \ + "hello world\n" + +#define traceroute_trivial_usage \ + "[-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\ + [-s src_addr] [-t tos] [-w wait] host [data size]" +#define traceroute_full_usage \ + "trace the route ip packets follow going to \"host\"\n" \ + "Options:\n" \ + "\t-d\tset SO_DEBUG options to socket\n" \ + "\t-n\tPrint hop addresses numerically rather than symbolically\n" \ + "\t-r\tBypass the normal routing tables and send directly to a host\n" \ + "\t-v\tVerbose output\n" \ + "\t-m max_ttl\tSet the max time-to-live (max number of hops)\n" \ + "\t-p port#\tSet the base UDP port number used in probes\n" \ + "\t\t(default is 33434)\n" \ + "\t-q nqueries\tSet the number of probes per ``ttl'' to nqueries\n" \ + "\t\t(default is 3)\n" \ + "\t-s src_addr\tUse the following IP address as the source address\n" \ + "\t-t tos\tSet the type-of-service in probe packets to the following value\n" \ + "\t\t(default 0)\n" \ + "\t-w wait\tSet the time (in seconds) to wait for a response to a probe\n" \ + "\t\t(default 3 sec.)." + + +#define true_trivial_usage \ + "" +#define true_full_usage \ + "Return an exit code of TRUE (0)." +#define true_example_usage \ + "$ true\n" \ + "$ echo $?\n" \ + "0\n" + +#define tty_trivial_usage \ + "" +#define tty_full_usage \ + "Print the file name of the terminal connected to standard input.\n\n"\ + "Options:\n" \ + "\t-s\tprint nothing, only return an exit status" +#define tty_example_usage \ + "$ tty\n" \ + "/dev/tty2\n" + +#ifdef BB_FEATURE_MOUNT_FORCE + #define USAGE_MOUNT_FORCE(a) a +#else + #define USAGE_MOUNT_FORCE(a) +#endif +#define umount_trivial_usage \ + "[flags] FILESYSTEM|DIRECTORY" +#define umount_full_usage \ + "Unmount file systems\n" \ + "\nFlags:\n" "\t-a\tUnmount all file systems" \ + USAGE_MTAB(" in /etc/mtab\n\t-n\tDon't erase /etc/mtab entries") \ + "\n\t-r\tTry to remount devices as read-only if mount is busy" \ + USAGE_MOUNT_FORCE("\n\t-f\tForce umount (i.e., unreachable NFS server)") \ + USAGE_MOUNT_LOOP("\n\t-l\tDo not free loop device (if a loop device has been used)") +#define umount_example_usage \ + "$ umount /dev/hdc1 \n" + +#define uname_trivial_usage \ + "[OPTION]..." +#define uname_full_usage \ + "Print certain system information. With no OPTION, same as -s.\n\n" \ + "Options:\n" \ + "\t-a\tprint all information\n" \ + "\t-m\tthe machine (hardware) type\n" \ + "\t-n\tprint the machine's network node hostname\n" \ + "\t-r\tprint the operating system release\n" \ + "\t-s\tprint the operating system name\n" \ + "\t-p\tprint the host processor type\n" \ + "\t-v\tprint the operating system version" +#define uname_example_usage \ + "$ uname -a\n" \ + "Linux debian 2.2.15pre13 #5 Tue Mar 14 16:03:50 MST 2000 i686 unknown\n" + +#define uniq_trivial_usage \ + "[OPTION]... [INPUT [OUTPUT]]" +#define uniq_full_usage \ + "Discard all but one of successive identical lines from INPUT\n" \ + "(or standard input), writing to OUTPUT (or standard output).\n\n" \ + "Options:\n" \ + "\t-c\tprefix lines by the number of occurrences\n" \ + "\t-d\tonly print duplicate lines\n" \ + "\t-u\tonly print unique lines" +#define uniq_example_usage \ + "$ echo -e \"a\\na\\nb\\nc\\nc\\na\" | sort | uniq\n" \ + "a\n" \ + "b\n" \ + "c\n" + +#define unix2dos_trivial_usage \ + "[option] [FILE]" +#define unix2dos_full_usage \ + "Converts FILE from unix format to dos format. When no option\n" \ + "is given, the input is converted to the opposite output format.\n" \ + "When no file is given, uses stdin for input and stdout for output.\n" \ + "Options:\n" \ + "\t-u\toutput will be in UNIX format\n" \ + "\t-d\toutput will be in DOS format" + +#define update_trivial_usage \ + "[options]" +#define update_full_usage \ + "Periodically flushes filesystem buffers.\n\n" \ + "Options:\n" \ + "\t-S\tforce use of sync(2) instead of flushing\n" \ + "\t-s SECS\tcall sync this often (default 30)\n" \ + "\t-f SECS\tflush some buffers this often (default 5)" + +#define uptime_trivial_usage \ + "" +#define uptime_full_usage \ + "Display the time since the last boot." +#define uptime_example_usage \ + "$ uptime\n" \ + " 1:55pm up 2:30, load average: 0.09, 0.04, 0.00\n" + +#define usleep_trivial_usage \ + "N" +#define usleep_full_usage \ + "Pause for N microseconds." +#define usleep_example_usage \ + "$ usleep 1000000\n" \ + "[pauses for 1 second]\n" + +#define uudecode_trivial_usage \ + "[FILE]..." +#define uudecode_full_usage \ + "Uudecode a file that is uuencoded.\n\n" \ + "Options:\n" \ + "\t-o FILE\tdirect output to FILE" +#define uudecode_example_usage \ + "$ uudecode -o busybox busybox.uu\n" \ + "$ ls -l busybox\n" \ + "-rwxr-xr-x 1 ams ams 245264 Jun 7 21:35 busybox\n" + +#define uuencode_trivial_usage \ + "[OPTION] [INFILE] REMOTEFILE" +#define uuencode_full_usage \ + "Uuencode a file.\n\n" \ + "Options:\n" \ + "\t-m\tuse base64 encoding per RFC1521" +#define uuencode_example_usage \ + "$ uuencode busybox busybox\n" \ + "begin 755 busybox\n" \ + "\n" \ + "$ uudecode busybox busybox > busybox.uu\n" \ + "$\n" + +#define vi_trivial_usage \ + "[OPTION] [FILE]..." +#define vi_full_usage \ + "edit FILE.\n\n" \ + "Options:\n" \ + "\t-R\tRead-only- do not write to the file." + +#define watchdog_trivial_usage \ + "DEV" +#define watchdog_full_usage \ + "Periodically write to watchdog device DEV" + +#define wc_trivial_usage \ + "[OPTION]... [FILE]..." +#define wc_full_usage \ + "Print line, word, and byte counts for each FILE, and a total line if\n" \ + "more than one FILE is specified. With no FILE, read standard input.\n\n" \ + "Options:\n" \ + "\t-c\tprint the byte counts\n" \ + "\t-l\tprint the newline counts\n" \ + "\t-L\tprint the length of the longest line\n" \ + "\t-w\tprint the word counts" +#define wc_example_usage \ + "$ wc /etc/passwd\n" \ + " 31 46 1365 /etc/passwd\n" + +#define wget_trivial_usage \ + "[-c|--continue] [-q|--quiet] [-O|--output-document file]\n\t[--header 'header: value'] [-P DIR] url" +#define wget_full_usage \ + "wget retrieves files via HTTP or FTP\n\n" \ + "Options:\n" \ + "\t-c\tcontinue retrieval of aborted transfers\n" \ + "\t-q\tquiet mode - do not print\n" \ + "\t-P\tSet directory prefix to DIR\n" \ + "\t-O\tsave to filename ('-' for stdout)" + +#define which_trivial_usage \ + "[COMMAND ...]" +#define which_full_usage \ + "Locates a COMMAND." +#define which_example_usage \ + "$ which login\n" \ + "/bin/login\n" + +#define whoami_trivial_usage \ + "" +#define whoami_full_usage \ + "Prints the user name associated with the current effective user id." + +#define xargs_trivial_usage \ + "[COMMAND] [ARGS...]" +#define xargs_full_usage \ + "Executes COMMAND on every item given by standard input." +#define xargs_example_usage \ + "$ ls | xargs gzip\n" \ + "$ find . -name '*.c' -print | xargs rm\n" + +#define yes_trivial_usage \ + "[OPTION]... [STRING]..." +#define yes_full_usage \ + "Repeatedly outputs a line with all specified STRING(s), or 'y'." + +#define zcat_trivial_usage \ + "FILE" +#define zcat_full_usage \ + "Uncompress to stdout." diff --git a/usleep.c b/usleep.c new file mode 100644 index 000000000..6023bf430 --- /dev/null +++ b/usleep.c @@ -0,0 +1,38 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini usleep implementation for busybox + * + * + * 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 + * + */ + +/* getopt not needed */ + +#include +#include +#include "busybox.h" + +extern int usleep_main(int argc, char **argv) +{ + if ((argc < 2) || (**(argv + 1) == '-')) { + show_usage(); + } + + usleep(atoi(*(++argv))); /* return void */ + return EXIT_SUCCESS; +} diff --git a/uudecode.c b/uudecode.c new file mode 100644 index 000000000..21dc4b23a --- /dev/null +++ b/uudecode.c @@ -0,0 +1,353 @@ +/* uudecode.c -- uudecode utility. + * Copyright (C) 1994, 1995 Free Software Foundation, Inc. + * + * 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. + * + * 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. + * + * 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. + */ + + + +#include +#include +#include +#include +#include +#include "busybox.h" +#include "pwd_grp/pwd.h" +#include "pwd_grp/grp.h" + +/*struct passwd *getpwnam();*/ + +/* Single character decode. */ +#define DEC(Char) (((Char) - ' ') & 077) + +static int read_stduu (const char *inname) +{ + char buf[2 * BUFSIZ]; + + while (1) { + int n; + char *p; + + if (fgets (buf, sizeof(buf), stdin) == NULL) { + 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")) { + error_msg("%s: No `end' line", inname); + return FALSE; + } + + return TRUE; +} + +static int read_base64 (const char *inname) +{ + 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) { + error_msg("%s: Short file", inname); + return FALSE; + } + p = buf; + + if (memcmp (buf, "====", 4) == 0) + break; + if (last_data != 0) { + 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++ == '=') { + error_msg("%s: illegal line", inname); + return FALSE; + } + c2 = b64_tab[*p++]; + + while (b64_tab[*p] == '\177') + if (*p++ == '\n') { + 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') { + 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; +} + +static int decode (const char *inname, + const char *forced_outname) +{ + struct passwd *pw; + register char *p; + int mode; + char buf[2 * BUFSIZ]; + char *outname = NULL; + int do_base64 = 0; + int res; + int dofre; + + /* Search for header line. */ + + while (1) { + if (fgets (buf, sizeof (buf), stdin) == NULL) { + 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') { + error_msg("%s: Illegal ~user", inname); + return FALSE; + } + *p++ = '\0'; + pw = getpwnam (buf + 1); + if (pw == NULL) { + 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)) + )) { + 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: + 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 { + perror_msg("%s", argv[optind]); + exit_status = EXIT_FAILURE; + } + optind++; + } + while (optind < argc); + } + return(exit_status); +} + +/* 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. + */ + + diff --git a/uuencode.c b/uuencode.c new file mode 100644 index 000000000..fc037403a --- /dev/null +++ b/uuencode.c @@ -0,0 +1,180 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2000 by Glenn McGrath + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include "busybox.h" + +/* Conversion table. for base 64 */ +static char tbl_base64[64] = { + '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', '+', '/' +}; + +static char tbl_std[64] = { + '`', '!', '"', '#', '$', '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', + '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', '[', '\\', ']', '^', '_' +}; + +/* + * 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) = '='; + } + else if (i == length + 2) { + *(p - 1) = *(p - 2) = '='; + } + /* ...and zero-terminate it. */ + *p = '\0'; +} + +int uuencode_main(int argc, char **argv) +{ + const int src_buf_size = 60; // This *MUST* be a multiple of 3 + const int dst_buf_size = 4 * ((src_buf_size + 2) / 3); + RESERVE_BB_BUFFER(src_buf, src_buf_size + 1); + RESERVE_BB_BUFFER(dst_buf, dst_buf_size + 1); + struct stat stat_buf; + FILE *src_stream = stdin; + char *tbl = tbl_std; + size_t size; + mode_t mode; + int opt; + int column = 0; + int write_size = 0; + int remaining; + int buffer_offset = 0; + + while ((opt = getopt(argc, argv, "m")) != -1) { + switch (opt) { + case 'm': + tbl = tbl_base64; + break; + default: + show_usage(); + } + } + + switch (argc - optind) { + case 2: + src_stream = xfopen(argv[optind], "r"); + stat(argv[optind], &stat_buf); + mode = stat_buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + if (src_stream == stdout) { + printf("NULL\n"); + } + break; + case 1: + mode = 0666 & ~umask(0666); + break; + default: + show_usage(); + } + + 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) { + /* Encode the buffer we just read in */ + uuencode(src_buf, dst_buf, size, tbl); + + /* Write the buffer to stdout, wrapping at 60 chars. + * This looks overly complex, but it gets tricky as + * the line has to continue to wrap correctly if we + * have to refill the buffer + * + * Improvments most welcome + */ + + /* Initialise values for the new buffer */ + remaining = 4 * ((size + 2) / 3); + buffer_offset = 0; + + /* Write the buffer to stdout, wrapping at 60 chars + * starting from the column the last buffer ran out + */ + do { + if (remaining > (60 - column)) { + write_size = 60 - column; + } + else if (remaining < 60) { + write_size = remaining; + } else { + write_size = 60; + } + + /* Setup a new row if required */ + if (column == 0) { + putchar('\n'); + if (tbl == tbl_std) { + putchar('M'); + } + } + /* Write to the 60th column */ + if (fwrite(&dst_buf[buffer_offset], 1, write_size, stdout) != write_size) { + perror("Couldnt finish writing"); + } + /* Update variables based on last write */ + buffer_offset += write_size; + remaining -= write_size; + column += write_size; + if (column % 60 == 0) { + column = 0; + } + } while (remaining > 0); + } + printf(tbl == tbl_std ? "\n`\nend\n" : "\n====\n"); + + return(EXIT_SUCCESS); +} diff --git a/vi.c b/vi.c new file mode 100644 index 000000000..fba5f445a --- /dev/null +++ b/vi.c @@ -0,0 +1,3966 @@ +/* vi: set sw=8 ts=8: */ +/* + * tiny vi.c: A small 'vi' clone + * Copyright (C) 2000, 2001 Sterling Huxley + * + * 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. + */ + +static const char vi_Version[] = + "$Id: vi.c,v 1.20 2003/12/23 21:26:05 andersen Exp $"; + +/* + * To compile for standalone use: + * gcc -Wall -Os -s -DSTANDALONE -o vi vi.c + * or + * gcc -Wall -Os -s -DSTANDALONE -DBB_FEATURE_VI_CRASHME -o vi vi.c # include testing features + * strip vi + */ + +/* + * Things To Do: + * EXINIT + * $HOME/.exrc and ./.exrc + * add magic to search /foo.*bar + * add :help command + * :map macros + * how about mode lines: vi: set sw=8 ts=8: + * if mark[] values were line numbers rather than pointers + * it would be easier to change the mark when add/delete lines + * More intelligence in refresh() + * ":r !cmd" and "!cmd" to filter text through an external command + * A true "undo" facility + * An "ex" line oriented mode- maybe using "cmdedit" + */ + +//---- Feature -------------- Bytes to immplement +#ifdef STANDALONE +#define vi_main main +#define BB_FEATURE_VI_COLON // 4288 +#define BB_FEATURE_VI_YANKMARK // 1408 +#define BB_FEATURE_VI_SEARCH // 1088 +#define BB_FEATURE_VI_USE_SIGNALS // 1056 +#define BB_FEATURE_VI_DOT_CMD // 576 +#define BB_FEATURE_VI_READONLY // 128 +#define BB_FEATURE_VI_SETOPTS // 576 +#define BB_FEATURE_VI_SET // 224 +#define BB_FEATURE_VI_WIN_RESIZE // 256 WIN_RESIZE +// To test editor using CRASHME: +// vi -C filename +// To stop testing, wait until all to text[] is deleted, or +// Ctrl-Z and kill -9 %1 +// while in the editor Ctrl-T will toggle the crashme function on and off. +//#define BB_FEATURE_VI_CRASHME // randomly pick commands to execute +#endif /* STANDALONE */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef STANDALONE +#include "busybox.h" +#endif /* STANDALONE */ + +#ifndef TRUE +#define TRUE ((int)1) +#define FALSE ((int)0) +#endif /* TRUE */ +#define MAX_SCR_COLS BUFSIZ + +// Misc. non-Ascii keys that report an escape sequence +#define VI_K_UP 128 // cursor key Up +#define VI_K_DOWN 129 // cursor key Down +#define VI_K_RIGHT 130 // Cursor Key Right +#define VI_K_LEFT 131 // cursor key Left +#define VI_K_HOME 132 // Cursor Key Home +#define VI_K_END 133 // Cursor Key End +#define VI_K_INSERT 134 // Cursor Key Insert +#define VI_K_PAGEUP 135 // Cursor Key Page Up +#define VI_K_PAGEDOWN 136 // Cursor Key Page Down +#define VI_K_FUN1 137 // Function Key F1 +#define VI_K_FUN2 138 // Function Key F2 +#define VI_K_FUN3 139 // Function Key F3 +#define VI_K_FUN4 140 // Function Key F4 +#define VI_K_FUN5 141 // Function Key F5 +#define VI_K_FUN6 142 // Function Key F6 +#define VI_K_FUN7 143 // Function Key F7 +#define VI_K_FUN8 144 // Function Key F8 +#define VI_K_FUN9 145 // Function Key F9 +#define VI_K_FUN10 146 // Function Key F10 +#define VI_K_FUN11 147 // Function Key F11 +#define VI_K_FUN12 148 // Function Key F12 + +static const int YANKONLY = FALSE; +static const int YANKDEL = TRUE; +static const int FORWARD = 1; // code depends on "1" for array index +static const int BACK = -1; // code depends on "-1" for array index +static const int LIMITED = 0; // how much of text[] in char_search +static const int FULL = 1; // how much of text[] in char_search + +static const int S_BEFORE_WS = 1; // used in skip_thing() for moving "dot" +static const int S_TO_WS = 2; // used in skip_thing() for moving "dot" +static const int S_OVER_WS = 3; // used in skip_thing() for moving "dot" +static const int S_END_PUNCT = 4; // used in skip_thing() for moving "dot" +static const int S_END_ALNUM = 5; // used in skip_thing() for moving "dot" + +typedef unsigned char Byte; + + +static int editing; // >0 while we are editing a file +static int cmd_mode; // 0=command 1=insert +static int file_modified; // buffer contents changed +static int err_method; // indicate error with beep or flash +static int fn_start; // index of first cmd line file name +static int save_argc; // how many file names on cmd line +static int cmdcnt; // repetition count +static fd_set rfds; // use select() for small sleeps +static struct timeval tv; // use select() for small sleeps +static char erase_char; // the users erase character +static int rows, columns; // the terminal screen is this size +static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset +static char *SOs, *SOn; // terminal standout start/normal ESC sequence +static char *bell; // terminal bell sequence +static char *Ceol, *Ceos; // Clear-end-of-line and Clear-end-of-screen ESC sequence +static char *CMrc; // Cursor motion arbitrary destination ESC sequence +static char *CMup, *CMdown; // Cursor motion up and down ESC sequence +static Byte *status_buffer; // mesages to the user +static Byte last_input_char; // last char read from user +static Byte last_forward_char; // last char searched for with 'f' +static Byte *cfn; // previous, current, and next file name +static Byte *text, *end, *textend; // pointers to the user data in memory +static Byte *screen; // pointer to the virtual screen buffer +static int screensize; // and its size +static Byte *screenbegin; // index into text[], of top line on the screen +static Byte *dot; // where all the action takes place +static int tabstop; +static struct termios term_orig, term_vi; // remember what the cooked mode was + +#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR +static int last_row; // where the cursor was last moved to +#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ +#ifdef BB_FEATURE_VI_USE_SIGNALS +static jmp_buf restart; // catch_sig() +#endif /* BB_FEATURE_VI_USE_SIGNALS */ +#ifdef BB_FEATURE_VI_WIN_RESIZE +static struct winsize winsize; // remember the window size +#endif /* BB_FEATURE_VI_WIN_RESIZE */ +#ifdef BB_FEATURE_VI_DOT_CMD +static int adding2q; // are we currently adding user input to q +static Byte *last_modifying_cmd; // last modifying cmd for "." +static Byte *ioq, *ioq_start; // pointer to string for get_one_char to "read" +#endif /* BB_FEATURE_VI_DOT_CMD */ +#if defined(BB_FEATURE_VI_DOT_CMD) || defined(BB_FEATURE_VI_YANKMARK) +static Byte *modifying_cmds; // cmds that modify text[] +#endif /* BB_FEATURE_VI_DOT_CMD || BB_FEATURE_VI_YANKMARK */ +#ifdef BB_FEATURE_VI_READONLY +static int vi_readonly, readonly; +#endif /* BB_FEATURE_VI_READONLY */ +#ifdef BB_FEATURE_VI_SETOPTS +static int autoindent; +static int showmatch; +static int ignorecase; +#endif /* BB_FEATURE_VI_SETOPTS */ +#ifdef BB_FEATURE_VI_YANKMARK +static Byte *reg[28]; // named register a-z, "D", and "U" 0-25,26,27 +static int YDreg, Ureg; // default delete register and orig line for "U" +static Byte *mark[28]; // user marks points somewhere in text[]- a-z and previous context '' +static Byte *context_start, *context_end; +#endif /* BB_FEATURE_VI_YANKMARK */ +#ifdef BB_FEATURE_VI_SEARCH +static Byte *last_search_pattern; // last pattern from a '/' or '?' search +#endif /* BB_FEATURE_VI_SEARCH */ + + +static void edit_file(Byte *); // edit one file +static void do_cmd(Byte); // execute a command +static void sync_cursor(Byte *, int *, int *); // synchronize the screen cursor to dot +static Byte *begin_line(Byte *); // return pointer to cur line B-o-l +static Byte *end_line(Byte *); // return pointer to cur line E-o-l +static Byte *dollar_line(Byte *); // return pointer to just before NL +static Byte *prev_line(Byte *); // return pointer to prev line B-o-l +static Byte *next_line(Byte *); // return pointer to next line B-o-l +static Byte *end_screen(void); // get pointer to last char on screen +static int count_lines(Byte *, Byte *); // count line from start to stop +static Byte *find_line(int); // find begining of line #li +static Byte *move_to_col(Byte *, int); // move "p" to column l +static int isblnk(Byte); // is the char a blank or tab +static void dot_left(void); // move dot left- dont leave line +static void dot_right(void); // move dot right- dont leave line +static void dot_begin(void); // move dot to B-o-l +static void dot_end(void); // move dot to E-o-l +static void dot_next(void); // move dot to next line B-o-l +static void dot_prev(void); // move dot to prev line B-o-l +static void dot_scroll(int, int); // move the screen up or down +static void dot_skip_over_ws(void); // move dot pat WS +static void dot_delete(void); // delete the char at 'dot' +static Byte *bound_dot(Byte *); // make sure text[0] <= P < "end" +static Byte *new_screen(int, int); // malloc virtual screen memory +static Byte *new_text(int); // malloc memory for text[] buffer +static Byte *char_insert(Byte *, Byte); // insert the char c at 'p' +static Byte *stupid_insert(Byte *, Byte); // stupidly insert the char c at 'p' +static Byte find_range(Byte **, Byte **, Byte); // return pointers for an object +static int st_test(Byte *, int, int, Byte *); // helper for skip_thing() +static Byte *skip_thing(Byte *, int, int, int); // skip some object +static Byte *find_pair(Byte *, Byte); // find matching pair () [] {} +static Byte *text_hole_delete(Byte *, Byte *); // at "p", delete a 'size' byte hole +static Byte *text_hole_make(Byte *, int); // at "p", make a 'size' byte hole +static Byte *yank_delete(Byte *, Byte *, int, int); // yank text[] into register then delete +static void show_help(void); // display some help info +static void print_literal(Byte *, Byte *); // copy s to buf, convert unprintable +static void rawmode(void); // set "raw" mode on tty +static void cookmode(void); // return to "cooked" mode on tty +static int mysleep(int); // sleep for 'h' 1/100 seconds +static Byte readit(void); // read (maybe cursor) key from stdin +static Byte get_one_char(void); // read 1 char from stdin +static int file_size(Byte *); // what is the byte size of "fn" +static int file_insert(Byte *, Byte *, int); +static int file_write(Byte *, Byte *, Byte *); +static void place_cursor(int, int, int); +static void screen_erase(); +static void clear_to_eol(void); +static void clear_to_eos(void); +static void standout_start(void); // send "start reverse video" sequence +static void standout_end(void); // send "end reverse video" sequence +static void flash(int); // flash the terminal screen +static void beep(void); // beep the terminal +static void indicate_error(char); // use flash or beep to indicate error +static void show_status_line(void); // put a message on the bottom line +static void psb(char *, ...); // Print Status Buf +static void psbs(char *, ...); // Print Status Buf in standout mode +static void ni(Byte *); // display messages +static void edit_status(void); // show file status on status line +static void redraw(int); // force a full screen refresh +static void format_line(Byte*, Byte*, int); +static void refresh(int); // update the terminal from screen[] + +#ifdef BB_FEATURE_VI_SEARCH +static Byte *char_search(Byte *, Byte *, int, int); // search for pattern starting at p +static int mycmp(Byte *, Byte *, int); // string cmp based in "ignorecase" +#endif /* BB_FEATURE_VI_SEARCH */ +#ifdef BB_FEATURE_VI_COLON +static void Hit_Return(void); +static Byte *get_one_address(Byte *, int *); // get colon addr, if present +static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present +static void colon(Byte *); // execute the "colon" mode cmds +#endif /* BB_FEATURE_VI_COLON */ +static Byte *get_input_line(Byte *); // get input line- use "status line" +#ifdef BB_FEATURE_VI_USE_SIGNALS +static void winch_sig(int); // catch window size changes +static void suspend_sig(int); // catch ctrl-Z +static void alarm_sig(int); // catch alarm time-outs +static void catch_sig(int); // catch ctrl-C +static void core_sig(int); // catch a core dump signal +#endif /* BB_FEATURE_VI_USE_SIGNALS */ +#ifdef BB_FEATURE_VI_DOT_CMD +static void start_new_cmd_q(Byte); // new queue for command +static void end_cmd_q(); // stop saving input chars +#else /* BB_FEATURE_VI_DOT_CMD */ +#define end_cmd_q() +#endif /* BB_FEATURE_VI_DOT_CMD */ +#ifdef BB_FEATURE_VI_WIN_RESIZE +static void window_size_get(int); // find out what size the window is +#endif /* BB_FEATURE_VI_WIN_RESIZE */ +#ifdef BB_FEATURE_VI_SETOPTS +static void showmatching(Byte *); // show the matching pair () [] {} +#endif /* BB_FEATURE_VI_SETOPTS */ +#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME) +static Byte *string_insert(Byte *, Byte *); // insert the string at 'p' +#endif /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */ +#ifdef BB_FEATURE_VI_YANKMARK +static Byte *text_yank(Byte *, Byte *, int); // save copy of "p" into a register +static Byte what_reg(void); // what is letter of current YDreg +static void check_context(Byte); // remember context for '' command +static Byte *swap_context(Byte *); // goto new context for '' command +#endif /* BB_FEATURE_VI_YANKMARK */ +#ifdef BB_FEATURE_VI_CRASHME +static void crash_dummy(); +static void crash_test(); +static int crashme = 0; +#endif /* BB_FEATURE_VI_CRASHME */ + + +extern int vi_main(int argc, char **argv) +{ + int c; + +#ifdef BB_FEATURE_VI_YANKMARK + int i; +#endif /* BB_FEATURE_VI_YANKMARK */ + + CMrc= "\033[%d;%dH"; // Terminal Crusor motion ESC sequence + CMup= "\033[A"; // move cursor up one line, same col + CMdown="\n"; // move cursor down one line, same col + Ceol= "\033[0K"; // Clear from cursor to end of line + Ceos= "\033[0J"; // Clear from cursor to end of screen + SOs = "\033[7m"; // Terminal standout mode on + SOn = "\033[0m"; // Terminal standout mode off + bell= "\007"; // Terminal bell sequence +#ifdef BB_FEATURE_VI_CRASHME + (void) srand((long) getpid()); +#endif /* BB_FEATURE_VI_CRASHME */ + status_buffer = (Byte *) xmalloc(200); // hold messages to user +#ifdef BB_FEATURE_VI_READONLY + vi_readonly = readonly = FALSE; + if (strncmp(argv[0], "view", 4) == 0) { + readonly = TRUE; + vi_readonly = TRUE; + } +#endif /* BB_FEATURE_VI_READONLY */ +#ifdef BB_FEATURE_VI_SETOPTS + autoindent = 1; + ignorecase = 1; + showmatch = 1; +#endif /* BB_FEATURE_VI_SETOPTS */ +#ifdef BB_FEATURE_VI_YANKMARK + for (i = 0; i < 28; i++) { + reg[i] = 0; + } // init the yank regs +#endif /* BB_FEATURE_VI_YANKMARK */ +#if defined(BB_FEATURE_VI_DOT_CMD) || defined(BB_FEATURE_VI_YANKMARK) + modifying_cmds = (Byte *) "aAcCdDiIJoOpPrRsxX<>~"; // cmds modifying text[] +#endif /* BB_FEATURE_VI_DOT_CMD */ + + // 1- process $HOME/.exrc file + // 2- process EXINIT variable from environment + // 3- process command line args + while ((c = getopt(argc, argv, "hCR")) != -1) { + switch (c) { +#ifdef BB_FEATURE_VI_CRASHME + case 'C': + crashme = 1; + break; +#endif /* BB_FEATURE_VI_CRASHME */ +#ifdef BB_FEATURE_VI_READONLY + case 'R': // Read-only flag + readonly = TRUE; + break; +#endif /* BB_FEATURE_VI_READONLY */ + //case 'r': // recover flag- ignore- we don't use tmp file + //case 'x': // encryption flag- ignore + //case 'c': // execute command first + //case 'h': // help -- just use default + default: + show_help(); + return 1; + } + } + + // The argv array can be used by the ":next" and ":rewind" commands + // save optind. + fn_start = optind; // remember first file name for :next and :rew + save_argc = argc; + + //----- This is the main file handling loop -------------- + if (optind >= argc) { + editing = 1; // 0= exit, 1= one file, 2= multiple files + edit_file(0); + } else { + for (; optind < argc; optind++) { + editing = 1; // 0=exit, 1=one file, 2+ =many files + if (cfn != 0) + free(cfn); + cfn = (Byte *) strdup(argv[optind]); + edit_file(cfn); + } + } + //----------------------------------------------------------- + + return (0); +} + +static void edit_file(Byte * fn) +{ + char c; + int cnt, size, ch; + +#ifdef BB_FEATURE_VI_USE_SIGNALS + char *msg; + int sig; +#endif /* BB_FEATURE_VI_USE_SIGNALS */ +#ifdef BB_FEATURE_VI_YANKMARK + static Byte *cur_line; +#endif /* BB_FEATURE_VI_YANKMARK */ + + rawmode(); + rows = 24; + columns = 80; + ch= -1; +#ifdef BB_FEATURE_VI_WIN_RESIZE + window_size_get(0); +#endif /* BB_FEATURE_VI_WIN_RESIZE */ + new_screen(rows, columns); // get memory for virtual screen + + cnt = file_size(fn); // file size + size = 2 * cnt; // 200% of file size + new_text(size); // get a text[] buffer + screenbegin = dot = end = text; + if (fn != 0) { + ch= file_insert(fn, text, cnt); + } + if (ch < 1) { + (void) char_insert(text, '\n'); // start empty buf with dummy line + } + file_modified = FALSE; +#ifdef BB_FEATURE_VI_YANKMARK + YDreg = 26; // default Yank/Delete reg + Ureg = 27; // hold orig line for "U" cmd + for (cnt = 0; cnt < 28; cnt++) { + mark[cnt] = 0; + } // init the marks + mark[26] = mark[27] = text; // init "previous context" +#endif /* BB_FEATURE_VI_YANKMARK */ + + err_method = 1; // flash + last_forward_char = last_input_char = '\0'; + crow = 0; + ccol = 0; + edit_status(); + +#ifdef BB_FEATURE_VI_USE_SIGNALS + signal(SIGHUP, catch_sig); + signal(SIGINT, catch_sig); + signal(SIGALRM, alarm_sig); + signal(SIGTERM, catch_sig); + signal(SIGQUIT, core_sig); + signal(SIGILL, core_sig); + signal(SIGTRAP, core_sig); + signal(SIGIOT, core_sig); + signal(SIGABRT, core_sig); + signal(SIGFPE, core_sig); + signal(SIGBUS, core_sig); + signal(SIGSEGV, core_sig); +#ifdef SIGSYS + signal(SIGSYS, core_sig); +#endif + signal(SIGWINCH, winch_sig); + signal(SIGTSTP, suspend_sig); + sig = setjmp(restart); + if (sig != 0) { + msg = ""; + if (sig == SIGWINCH) + msg = "(window resize)"; + if (sig == SIGHUP) + msg = "(hangup)"; + if (sig == SIGINT) + msg = "(interrupt)"; + if (sig == SIGTERM) + msg = "(terminate)"; + if (sig == SIGBUS) + msg = "(bus error)"; + if (sig == SIGSEGV) + msg = "(I tried to touch invalid memory)"; + if (sig == SIGALRM) + msg = "(alarm)"; + + psbs("-- caught signal %d %s--", sig, msg); + screenbegin = dot = text; + } +#endif /* BB_FEATURE_VI_USE_SIGNALS */ + + editing = 1; + cmd_mode = 0; // 0=command 1=insert 2='R'eplace + cmdcnt = 0; + tabstop = 8; + offset = 0; // no horizontal offset + c = '\0'; +#ifdef BB_FEATURE_VI_DOT_CMD + if (last_modifying_cmd != 0) + free(last_modifying_cmd); + if (ioq_start != NULL) + free(ioq_start); + ioq = ioq_start = last_modifying_cmd = 0; + adding2q = 0; +#endif /* BB_FEATURE_VI_DOT_CMD */ + redraw(FALSE); // dont force every col re-draw + show_status_line(); + + //------This is the main Vi cmd handling loop ----------------------- + while (editing > 0) { +#ifdef BB_FEATURE_VI_CRASHME + if (crashme > 0) { + if ((end - text) > 1) { + crash_dummy(); // generate a random command + } else { + crashme = 0; + dot = + string_insert(text, (Byte *) "\n\n##### Ran out of text to work on. #####\n\n"); // insert the string + refresh(FALSE); + } + } +#endif /* BB_FEATURE_VI_CRASHME */ + last_input_char = c = get_one_char(); // get a cmd from user +#ifdef BB_FEATURE_VI_YANKMARK + // save a copy of the current line- for the 'U" command + if (begin_line(dot) != cur_line) { + cur_line = begin_line(dot); + text_yank(begin_line(dot), end_line(dot), Ureg); + } +#endif /* BB_FEATURE_VI_YANKMARK */ +#ifdef BB_FEATURE_VI_DOT_CMD + // These are commands that change text[]. + // Remember the input for the "." command + if (!adding2q && ioq_start == 0 + && strchr((char *) modifying_cmds, c) != NULL) { + start_new_cmd_q(c); + } +#endif /* BB_FEATURE_VI_DOT_CMD */ + do_cmd(c); // execute the user command + // + // poll to see if there is input already waiting. if we are + // not able to display output fast enough to keep up, skip + // the display update until we catch up with input. + if (mysleep(0) == 0) { + // no input pending- so update output + refresh(FALSE); + show_status_line(); + } +#ifdef BB_FEATURE_VI_CRASHME + if (crashme > 0) + crash_test(); // test editor variables +#endif /* BB_FEATURE_VI_CRASHME */ + } + //------------------------------------------------------------------- + + place_cursor(rows, 0, FALSE); // go to bottom of screen + clear_to_eol(); // Erase to end of line + cookmode(); +} + +static Byte readbuffer[BUFSIZ]; + +#ifdef BB_FEATURE_VI_CRASHME +static int totalcmds = 0; +static int Mp = 85; // Movement command Probability +static int Np = 90; // Non-movement command Probability +static int Dp = 96; // Delete command Probability +static int Ip = 97; // Insert command Probability +static int Yp = 98; // Yank command Probability +static int Pp = 99; // Put command Probability +static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0; +char chars[20] = "\t012345 abcdABCD-=.$"; +char *words[20] = { "this", "is", "a", "test", + "broadcast", "the", "emergency", "of", + "system", "quick", "brown", "fox", + "jumped", "over", "lazy", "dogs", + "back", "January", "Febuary", "March" +}; +char *lines[20] = { + "You should have received a copy of the GNU General Public License\n", + "char c, cm, *cmd, *cmd1;\n", + "generate a command by percentages\n", + "Numbers may be typed as a prefix to some commands.\n", + "Quit, discarding changes!\n", + "Forced write, if permission originally not valid.\n", + "In general, any ex or ed command (such as substitute or delete).\n", + "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n", + "Please get w/ me and I will go over it with you.\n", + "The following is a list of scheduled, committed changes.\n", + "1. Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n", + "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n", + "Any question about transactions please contact Sterling Huxley.\n", + "I will try to get back to you by Friday, December 31.\n", + "This Change will be implemented on Friday.\n", + "Let me know if you have problems accessing this;\n", + "Sterling Huxley recently added you to the access list.\n", + "Would you like to go to lunch?\n", + "The last command will be automatically run.\n", + "This is too much english for a computer geek.\n", +}; +char *multilines[20] = { + "You should have received a copy of the GNU General Public License\n", + "char c, cm, *cmd, *cmd1;\n", + "generate a command by percentages\n", + "Numbers may be typed as a prefix to some commands.\n", + "Quit, discarding changes!\n", + "Forced write, if permission originally not valid.\n", + "In general, any ex or ed command (such as substitute or delete).\n", + "I have tickets available for the Blazers vs LA Clippers for Monday, Janurary 1 at 1:00pm.\n", + "Please get w/ me and I will go over it with you.\n", + "The following is a list of scheduled, committed changes.\n", + "1. Launch Norton Antivirus (Start, Programs, Norton Antivirus)\n", + "Reminder....Town Meeting in Central Perk cafe today at 3:00pm.\n", + "Any question about transactions please contact Sterling Huxley.\n", + "I will try to get back to you by Friday, December 31.\n", + "This Change will be implemented on Friday.\n", + "Let me know if you have problems accessing this;\n", + "Sterling Huxley recently added you to the access list.\n", + "Would you like to go to lunch?\n", + "The last command will be automatically run.\n", + "This is too much english for a computer geek.\n", +}; + +// create a random command to execute +static void crash_dummy() +{ + static int sleeptime; // how long to pause between commands + char c, cm, *cmd, *cmd1; + int i, cnt, thing, rbi, startrbi, percent; + + // "dot" movement commands + cmd1 = " \n\r\002\004\005\006\025\0310^$-+wWeEbBhjklHL"; + + // is there already a command running? + if (strlen((char *) readbuffer) > 0) + goto cd1; + cd0: + startrbi = rbi = 0; + sleeptime = 0; // how long to pause between commands + memset(readbuffer, '\0', BUFSIZ - 1); // clear the read buffer + // generate a command by percentages + percent = (int) lrand48() % 100; // get a number from 0-99 + if (percent < Mp) { // Movement commands + // available commands + cmd = cmd1; + M++; + } else if (percent < Np) { // non-movement commands + cmd = "mz<>\'\""; // available commands + N++; + } else if (percent < Dp) { // Delete commands + cmd = "dx"; // available commands + D++; + } else if (percent < Ip) { // Inset commands + cmd = "iIaAsrJ"; // available commands + I++; + } else if (percent < Yp) { // Yank commands + cmd = "yY"; // available commands + Y++; + } else if (percent < Pp) { // Put commands + cmd = "pP"; // available commands + P++; + } else { + // We do not know how to handle this command, try again + U++; + goto cd0; + } + // randomly pick one of the available cmds from "cmd[]" + i = (int) lrand48() % strlen(cmd); + cm = cmd[i]; + if (strchr(":\024", cm)) + goto cd0; // dont allow colon or ctrl-T commands + readbuffer[rbi++] = cm; // put cmd into input buffer + + // now we have the command- + // there are 1, 2, and multi char commands + // find out which and generate the rest of command as necessary + if (strchr("dmryz<>\'\"", cm)) { // 2-char commands + cmd1 = " \n\r0$^-+wWeEbBhjklHL"; + if (cm == 'm' || cm == '\'' || cm == '\"') { // pick a reg[] + cmd1 = "abcdefghijklmnopqrstuvwxyz"; + } + thing = (int) lrand48() % strlen(cmd1); // pick a movement command + c = cmd1[thing]; + readbuffer[rbi++] = c; // add movement to input buffer + } + if (strchr("iIaAsc", cm)) { // multi-char commands + if (cm == 'c') { + // change some thing + thing = (int) lrand48() % strlen(cmd1); // pick a movement command + c = cmd1[thing]; + readbuffer[rbi++] = c; // add movement to input buffer + } + thing = (int) lrand48() % 4; // what thing to insert + cnt = (int) lrand48() % 10; // how many to insert + for (i = 0; i < cnt; i++) { + if (thing == 0) { // insert chars + readbuffer[rbi++] = chars[((int) lrand48() % strlen(chars))]; + } else if (thing == 1) { // insert words + strcat((char *) readbuffer, words[(int) lrand48() % 20]); + strcat((char *) readbuffer, " "); + sleeptime = 0; // how fast to type + } else if (thing == 2) { // insert lines + strcat((char *) readbuffer, lines[(int) lrand48() % 20]); + sleeptime = 0; // how fast to type + } else { // insert multi-lines + strcat((char *) readbuffer, multilines[(int) lrand48() % 20]); + sleeptime = 0; // how fast to type + } + } + strcat((char *) readbuffer, "\033"); + } + cd1: + totalcmds++; + if (sleeptime > 0) + (void) mysleep(sleeptime); // sleep 1/100 sec +} + +// test to see if there are any errors +static void crash_test() +{ + static time_t oldtim; + time_t tim; + char d[2], buf[BUFSIZ], msg[BUFSIZ]; + + msg[0] = '\0'; + if (end < text) { + strcat((char *) msg, "end textend) { + strcat((char *) msg, "end>textend "); + } + if (dot < text) { + strcat((char *) msg, "dot end) { + strcat((char *) msg, "dot>end "); + } + if (screenbegin < text) { + strcat((char *) msg, "screenbegin end - 1) { + strcat((char *) msg, "screenbegin>end-1 "); + } + + if (strlen(msg) > 0) { + alarm(0); + sprintf(buf, "\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s", + totalcmds, last_input_char, msg, SOs, SOn); + write(1, buf, strlen(buf)); + while (read(0, d, 1) > 0) { + if (d[0] == '\n' || d[0] == '\r') + break; + } + alarm(3); + } + tim = (time_t) time((time_t *) 0); + if (tim >= (oldtim + 3)) { + sprintf((char *) status_buffer, + "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d", + totalcmds, M, N, I, D, Y, P, U, end - text + 1); + oldtim = tim; + } + return; +} +#endif /* BB_FEATURE_VI_CRASHME */ + +//--------------------------------------------------------------------- +//----- the Ascii Chart ----------------------------------------------- +// +// 00 nul 01 soh 02 stx 03 etx 04 eot 05 enq 06 ack 07 bel +// 08 bs 09 ht 0a nl 0b vt 0c np 0d cr 0e so 0f si +// 10 dle 11 dc1 12 dc2 13 dc3 14 dc4 15 nak 16 syn 17 etb +// 18 can 19 em 1a sub 1b esc 1c fs 1d gs 1e rs 1f us +// 20 sp 21 ! 22 " 23 # 24 $ 25 % 26 & 27 ' +// 28 ( 29 ) 2a * 2b + 2c , 2d - 2e . 2f / +// 30 0 31 1 32 2 33 3 34 4 35 5 36 6 37 7 +// 38 8 39 9 3a : 3b ; 3c < 3d = 3e > 3f ? +// 40 @ 41 A 42 B 43 C 44 D 45 E 46 F 47 G +// 48 H 49 I 4a J 4b K 4c L 4d M 4e N 4f O +// 50 P 51 Q 52 R 53 S 54 T 55 U 56 V 57 W +// 58 X 59 Y 5a Z 5b [ 5c \ 5d ] 5e ^ 5f _ +// 60 ` 61 a 62 b 63 c 64 d 65 e 66 f 67 g +// 68 h 69 i 6a j 6b k 6c l 6d m 6e n 6f o +// 70 p 71 q 72 r 73 s 74 t 75 u 76 v 77 w +// 78 x 79 y 7a z 7b { 7c | 7d } 7e ~ 7f del +//--------------------------------------------------------------------- + +//----- Execute a Vi Command ----------------------------------- +static void do_cmd(Byte c) +{ + Byte c1, *p, *q, *msg, buf[9], *save_dot; + int cnt, i, j, dir, yf; + + c1 = c; // quiet the compiler + cnt = yf = dir = 0; // quiet the compiler + p = q = save_dot = msg = buf; // quiet the compiler + memset(buf, '\0', 9); // clear buf + + /* if this is a cursor key, skip these checks */ + switch (c) { + case VI_K_UP: + case VI_K_DOWN: + case VI_K_LEFT: + case VI_K_RIGHT: + case VI_K_HOME: + case VI_K_END: + case VI_K_PAGEUP: + case VI_K_PAGEDOWN: + goto key_cmd_mode; + } + + if (cmd_mode == 2) { + // we are 'R'eplacing the current *dot with new char + if (*dot == '\n') { + // don't Replace past E-o-l + cmd_mode = 1; // convert to insert + } else { + if (1 <= c && c <= 127) { // only ASCII chars + if (c != 27) + dot = yank_delete(dot, dot, 0, YANKDEL); // delete char + dot = char_insert(dot, c); // insert new char + } + goto dc1; + } + } + if (cmd_mode == 1) { + // hitting "Insert" twice means "R" replace mode + if (c == VI_K_INSERT) goto dc5; + // insert the char c at "dot" + if (1 <= c && c <= 127) { + dot = char_insert(dot, c); // only ASCII chars + } + goto dc1; + } + +key_cmd_mode: + switch (c) { + //case 0x01: // soh + //case 0x09: // ht + //case 0x0b: // vt + //case 0x0e: // so + //case 0x0f: // si + //case 0x10: // dle + //case 0x11: // dc1 + //case 0x13: // dc3 +#ifdef BB_FEATURE_VI_CRASHME + case 0x14: // dc4 ctrl-T + crashme = (crashme == 0) ? 1 : 0; + break; +#endif /* BB_FEATURE_VI_CRASHME */ + //case 0x16: // syn + //case 0x17: // etb + //case 0x18: // can + //case 0x1c: // fs + //case 0x1d: // gs + //case 0x1e: // rs + //case 0x1f: // us + //case '!': // !- + //case '#': // #- + //case '&': // &- + //case '(': // (- + //case ')': // )- + //case '*': // *- + //case ',': // ,- + //case '=': // =- + //case '@': // @- + //case 'F': // F- + //case 'K': // K- + //case 'Q': // Q- + //case 'S': // S- + //case 'T': // T- + //case 'V': // V- + //case '[': // [- + //case '\\': // \- + //case ']': // ]- + //case '_': // _- + //case '`': // `- + //case 'g': // g- + //case 'u': // u- FIXME- there is no undo + //case 'v': // v- + default: // unrecognised command + buf[0] = c; + buf[1] = '\0'; + if (c <= ' ') { + buf[0] = '^'; + buf[1] = c + '@'; + buf[2] = '\0'; + } + ni((Byte *) buf); + end_cmd_q(); // stop adding to q + case 0x00: // nul- ignore + break; + case 2: // ctrl-B scroll up full screen + case VI_K_PAGEUP: // Cursor Key Page Up + dot_scroll(rows - 2, -1); + break; +#ifdef BB_FEATURE_VI_USE_SIGNALS + case 0x03: // ctrl-C interrupt + longjmp(restart, 1); + break; + case 26: // ctrl-Z suspend + suspend_sig(SIGTSTP); + break; +#endif /* BB_FEATURE_VI_USE_SIGNALS */ + case 4: // ctrl-D scroll down half screen + dot_scroll((rows - 2) / 2, 1); + break; + case 5: // ctrl-E scroll down one line + dot_scroll(1, 1); + break; + case 6: // ctrl-F scroll down full screen + case VI_K_PAGEDOWN: // Cursor Key Page Down + dot_scroll(rows - 2, 1); + break; + case 7: // ctrl-G show current status + edit_status(); + break; + case 'h': // h- move left + case VI_K_LEFT: // cursor key Left + case 8: // ctrl-H- move left (This may be ERASE char) + case 127: // DEL- move left (This may be ERASE char) + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dot_left(); + break; + case 10: // Newline ^J + case 'j': // j- goto next line, same col + case VI_K_DOWN: // cursor key Down + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dot_next(); // go to next B-o-l + dot = move_to_col(dot, ccol + offset); // try stay in same col + break; + case 12: // ctrl-L force redraw whole screen + case 18: // ctrl-R force redraw + place_cursor(0, 0, FALSE); // put cursor in correct place + clear_to_eos(); // tel terminal to erase display + (void) mysleep(10); + screen_erase(); // erase the internal screen buffer + refresh(TRUE); // this will redraw the entire display + break; + case 13: // Carriage Return ^M + case '+': // +- goto next line + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dot_next(); + dot_skip_over_ws(); + break; + case 21: // ctrl-U scroll up half screen + dot_scroll((rows - 2) / 2, -1); + break; + case 25: // ctrl-Y scroll up one line + dot_scroll(1, -1); + break; + case 27: // esc + if (cmd_mode == 0) + indicate_error(c); + cmd_mode = 0; // stop insrting + end_cmd_q(); + *status_buffer = '\0'; // clear status buffer + break; + case ' ': // move right + case 'l': // move right + case VI_K_RIGHT: // Cursor Key Right + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dot_right(); + break; +#ifdef BB_FEATURE_VI_YANKMARK + case '"': // "- name a register to use for Delete/Yank + c1 = get_one_char(); + c1 = tolower(c1); + if (islower(c1)) { + YDreg = c1 - 'a'; + } else { + indicate_error(c); + } + break; + case '\'': // '- goto a specific mark + c1 = get_one_char(); + c1 = tolower(c1); + if (islower(c1)) { + c1 = c1 - 'a'; + // get the b-o-l + q = mark[(int) c1]; + if (text <= q && q < end) { + dot = q; + dot_begin(); // go to B-o-l + dot_skip_over_ws(); + } + } else if (c1 == '\'') { // goto previous context + dot = swap_context(dot); // swap current and previous context + dot_begin(); // go to B-o-l + dot_skip_over_ws(); + } else { + indicate_error(c); + } + break; + case 'm': // m- Mark a line + // this is really stupid. If there are any inserts or deletes + // between text[0] and dot then this mark will not point to the + // correct location! It could be off by many lines! + // Well..., at least its quick and dirty. + c1 = get_one_char(); + c1 = tolower(c1); + if (islower(c1)) { + c1 = c1 - 'a'; + // remember the line + mark[(int) c1] = dot; + } else { + indicate_error(c); + } + break; + case 'P': // P- Put register before + case 'p': // p- put register after + p = reg[YDreg]; + if (p == 0) { + psbs("Nothing in register %c", what_reg()); + break; + } + // are we putting whole lines or strings + if (strchr((char *) p, '\n') != NULL) { + if (c == 'P') { + dot_begin(); // putting lines- Put above + } + if (c == 'p') { + // are we putting after very last line? + if (end_line(dot) == (end - 1)) { + dot = end; // force dot to end of text[] + } else { + dot_next(); // next line, then put before + } + } + } else { + if (c == 'p') + dot_right(); // move to right, can move to NL + } + dot = string_insert(dot, p); // insert the string + end_cmd_q(); // stop adding to q + break; + case 'U': // U- Undo; replace current line with original version + if (reg[Ureg] != 0) { + p = begin_line(dot); + q = end_line(dot); + p = text_hole_delete(p, q); // delete cur line + p = string_insert(p, reg[Ureg]); // insert orig line + dot = p; + dot_skip_over_ws(); + } + break; +#endif /* BB_FEATURE_VI_YANKMARK */ + case '$': // $- goto end of line + case VI_K_END: // Cursor Key End + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dot = end_line(dot + 1); + break; + case '%': // %- find matching char of pair () [] {} + for (q = dot; q < end && *q != '\n'; q++) { + if (strchr("()[]{}", *q) != NULL) { + // we found half of a pair + p = find_pair(q, *q); + if (p == NULL) { + indicate_error(c); + } else { + dot = p; + } + break; + } + } + if (*q == '\n') + indicate_error(c); + break; + case 'f': // f- forward to a user specified char + last_forward_char = get_one_char(); // get the search char + // + // dont seperate these two commands. 'f' depends on ';' + // + //**** fall thru to ... 'i' + case ';': // ;- look at rest of line for last forward char + if (cmdcnt-- > 1) { + do_cmd(';'); + } // repeat cnt + if (last_forward_char == 0) break; + q = dot + 1; + while (q < end - 1 && *q != '\n' && *q != last_forward_char) { + q++; + } + if (*q == last_forward_char) + dot = q; + break; + case '-': // -- goto prev line + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dot_prev(); + dot_skip_over_ws(); + break; +#ifdef BB_FEATURE_VI_DOT_CMD + case '.': // .- repeat the last modifying command + // Stuff the last_modifying_cmd back into stdin + // and let it be re-executed. + if (last_modifying_cmd != 0) { + ioq = ioq_start = (Byte *) strdup((char *) last_modifying_cmd); + } + break; +#endif /* BB_FEATURE_VI_DOT_CMD */ +#ifdef BB_FEATURE_VI_SEARCH + case '?': // /- search for a pattern + case '/': // /- search for a pattern + buf[0] = c; + buf[1] = '\0'; + q = get_input_line(buf); // get input line- use "status line" + if (strlen((char *) q) == 1) + goto dc3; // if no pat re-use old pat + if (strlen((char *) q) > 1) { // new pat- save it and find + // there is a new pat + if (last_search_pattern != 0) { + free(last_search_pattern); + } + last_search_pattern = (Byte *) strdup((char *) q); + goto dc3; // now find the pattern + } + // user changed mind and erased the "/"- do nothing + break; + case 'N': // N- backward search for last pattern + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dir = BACK; // assume BACKWARD search + p = dot - 1; + if (last_search_pattern[0] == '?') { + dir = FORWARD; + p = dot + 1; + } + goto dc4; // now search for pattern + break; + case 'n': // n- repeat search for last pattern + // search rest of text[] starting at next char + // if search fails return orignal "p" not the "p+1" address + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dc3: + if (last_search_pattern == 0) { + msg = (Byte *) "No previous regular expression"; + goto dc2; + } + if (last_search_pattern[0] == '/') { + dir = FORWARD; // assume FORWARD search + p = dot + 1; + } + if (last_search_pattern[0] == '?') { + dir = BACK; + p = dot - 1; + } + dc4: + q = char_search(p, last_search_pattern + 1, dir, FULL); + if (q != NULL) { + dot = q; // good search, update "dot" + msg = (Byte *) ""; + goto dc2; + } + // no pattern found between "dot" and "end"- continue at top + p = text; + if (dir == BACK) { + p = end - 1; + } + q = char_search(p, last_search_pattern + 1, dir, FULL); + if (q != NULL) { // found something + dot = q; // found new pattern- goto it + msg = (Byte *) "search hit BOTTOM, continuing at TOP"; + if (dir == BACK) { + msg = (Byte *) "search hit TOP, continuing at BOTTOM"; + } + } else { + msg = (Byte *) "Pattern not found"; + } + dc2: + psbs("%s", msg); + break; + case '{': // {- move backward paragraph + q = char_search(dot, (Byte *) "\n\n", BACK, FULL); + if (q != NULL) { // found blank line + dot = next_line(q); // move to next blank line + } + break; + case '}': // }- move forward paragraph + q = char_search(dot, (Byte *) "\n\n", FORWARD, FULL); + if (q != NULL) { // found blank line + dot = next_line(q); // move to next blank line + } + break; +#endif /* BB_FEATURE_VI_SEARCH */ + case '0': // 0- goto begining of line + case '1': // 1- + case '2': // 2- + case '3': // 3- + case '4': // 4- + case '5': // 5- + case '6': // 6- + case '7': // 7- + case '8': // 8- + case '9': // 9- + if (c == '0' && cmdcnt < 1) { + dot_begin(); // this was a standalone zero + } else { + cmdcnt = cmdcnt * 10 + (c - '0'); // this 0 is part of a number + } + break; + case ':': // :- the colon mode commands + p = get_input_line((Byte *) ":"); // get input line- use "status line" +#ifdef BB_FEATURE_VI_COLON + colon(p); // execute the command +#else /* BB_FEATURE_VI_COLON */ + if (*p == ':') + p++; // move past the ':' + cnt = strlen((char *) p); + if (cnt <= 0) + break; + if (strncasecmp((char *) p, "quit", cnt) == 0 || + strncasecmp((char *) p, "q!", cnt) == 0) { // delete lines + if (file_modified == TRUE && p[1] != '!') { + psbs("No write since last change (:quit! overrides)"); + } else { + editing = 0; + } + } else if (strncasecmp((char *) p, "write", cnt) == 0 || + strncasecmp((char *) p, "wq", cnt) == 0) { + cnt = file_write(cfn, text, end - 1); + file_modified = FALSE; + psb("\"%s\" %dL, %dC", cfn, count_lines(text, end - 1), cnt); + if (p[1] == 'q') { + editing = 0; + } + } else if (strncasecmp((char *) p, "file", cnt) == 0 ) { + edit_status(); // show current file status + } else if (sscanf((char *) p, "%d", &j) > 0) { + dot = find_line(j); // go to line # j + dot_skip_over_ws(); + } else { // unrecognised cmd + ni((Byte *) p); + } +#endif /* BB_FEATURE_VI_COLON */ + break; + case '<': // <- Left shift something + case '>': // >- Right shift something + cnt = count_lines(text, dot); // remember what line we are on + c1 = get_one_char(); // get the type of thing to delete + find_range(&p, &q, c1); + (void) yank_delete(p, q, 1, YANKONLY); // save copy before change + p = begin_line(p); + q = end_line(q); + i = count_lines(p, q); // # of lines we are shifting + for ( ; i > 0; i--, p = next_line(p)) { + if (c == '<') { + // shift left- remove tab or 8 spaces + if (*p == '\t') { + // shrink buffer 1 char + (void) text_hole_delete(p, p); + } else if (*p == ' ') { + // we should be calculating columns, not just SPACE + for (j = 0; *p == ' ' && j < tabstop; j++) { + (void) text_hole_delete(p, p); + } + } + } else if (c == '>') { + // shift right -- add tab or 8 spaces + (void) char_insert(p, '\t'); + } + } + dot = find_line(cnt); // what line were we on + dot_skip_over_ws(); + end_cmd_q(); // stop adding to q + break; + case 'A': // A- append at e-o-l + dot_end(); // go to e-o-l + //**** fall thru to ... 'a' + case 'a': // a- append after current char + if (*dot != '\n') + dot++; + goto dc_i; + break; + case 'B': // B- back a blank-delimited Word + case 'E': // E- end of a blank-delimited word + case 'W': // W- forward a blank-delimited word + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dir = FORWARD; + if (c == 'B') + dir = BACK; + if (c == 'W' || isspace(dot[dir])) { + dot = skip_thing(dot, 1, dir, S_TO_WS); + dot = skip_thing(dot, 2, dir, S_OVER_WS); + } + if (c != 'W') + dot = skip_thing(dot, 1, dir, S_BEFORE_WS); + break; + case 'C': // C- Change to e-o-l + case 'D': // D- delete to e-o-l + save_dot = dot; + dot = dollar_line(dot); // move to before NL + // copy text into a register and delete + dot = yank_delete(save_dot, dot, 0, YANKDEL); // delete to e-o-l + if (c == 'C') + goto dc_i; // start inserting +#ifdef BB_FEATURE_VI_DOT_CMD + if (c == 'D') + end_cmd_q(); // stop adding to q +#endif /* BB_FEATURE_VI_DOT_CMD */ + break; + case 'G': // G- goto to a line number (default= E-O-F) + dot = end - 1; // assume E-O-F + if (cmdcnt > 0) { + dot = find_line(cmdcnt); // what line is #cmdcnt + } + dot_skip_over_ws(); + break; + case 'H': // H- goto top line on screen + dot = screenbegin; + if (cmdcnt > (rows - 1)) { + cmdcnt = (rows - 1); + } + if (cmdcnt-- > 1) { + do_cmd('+'); + } // repeat cnt + dot_skip_over_ws(); + break; + case 'I': // I- insert before first non-blank + dot_begin(); // 0 + dot_skip_over_ws(); + //**** fall thru to ... 'i' + case 'i': // i- insert before current char + case VI_K_INSERT: // Cursor Key Insert + dc_i: + cmd_mode = 1; // start insrting + psb("-- Insert --"); + break; + case 'J': // J- join current and next lines together + if (cmdcnt-- > 2) { + do_cmd(c); + } // repeat cnt + dot_end(); // move to NL + if (dot < end - 1) { // make sure not last char in text[] + *dot++ = ' '; // replace NL with space + while (isblnk(*dot)) { // delete leading WS + dot_delete(); + } + } + end_cmd_q(); // stop adding to q + break; + case 'L': // L- goto bottom line on screen + dot = end_screen(); + if (cmdcnt > (rows - 1)) { + cmdcnt = (rows - 1); + } + if (cmdcnt-- > 1) { + do_cmd('-'); + } // repeat cnt + dot_begin(); + dot_skip_over_ws(); + break; + case 'M': // M- goto middle line on screen + dot = screenbegin; + for (cnt = 0; cnt < (rows-1) / 2; cnt++) + dot = next_line(dot); + break; + case 'O': // O- open a empty line above + // 0i\n ESC -i + p = begin_line(dot); + if (p[-1] == '\n') { + dot_prev(); + case 'o': // o- open a empty line below; Yes, I know it is in the middle of the "if (..." + dot_end(); + dot = char_insert(dot, '\n'); + } else { + dot_begin(); // 0 + dot = char_insert(dot, '\n'); // i\n ESC + dot_prev(); // - + } + goto dc_i; + break; + case 'R': // R- continuous Replace char + dc5: + cmd_mode = 2; + psb("-- Replace --"); + break; + case 'X': // X- delete char before dot + case 'x': // x- delete the current char + case 's': // s- substitute the current char + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dir = 0; + if (c == 'X') + dir = -1; + if (dot[dir] != '\n') { + if (c == 'X') + dot--; // delete prev char + dot = yank_delete(dot, dot, 0, YANKDEL); // delete char + } + if (c == 's') + goto dc_i; // start insrting + end_cmd_q(); // stop adding to q + break; + case 'Z': // Z- if modified, {write}; exit + // ZZ means to save file (if necessary), then exit + c1 = get_one_char(); + if (c1 != 'Z') { + indicate_error(c); + break; + } + if (file_modified == TRUE +#ifdef BB_FEATURE_VI_READONLY + && vi_readonly == FALSE + && readonly == FALSE +#endif /* BB_FEATURE_VI_READONLY */ + ) { + cnt = file_write(cfn, text, end - 1); + if (cnt == (end - 1 - text + 1)) { + editing = 0; + } + } else { + editing = 0; + } + break; + case '^': // ^- move to first non-blank on line + dot_begin(); + dot_skip_over_ws(); + break; + case 'b': // b- back a word + case 'e': // e- end of word + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dir = FORWARD; + if (c == 'b') + dir = BACK; + if ((dot + dir) < text || (dot + dir) > end - 1) + break; + dot += dir; + if (isspace(*dot)) { + dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS); + } + if (isalnum(*dot) || *dot == '_') { + dot = skip_thing(dot, 1, dir, S_END_ALNUM); + } else if (ispunct(*dot)) { + dot = skip_thing(dot, 1, dir, S_END_PUNCT); + } + break; + case 'c': // c- change something + case 'd': // d- delete something +#ifdef BB_FEATURE_VI_YANKMARK + case 'y': // y- yank something + case 'Y': // Y- Yank a line +#endif /* BB_FEATURE_VI_YANKMARK */ + yf = YANKDEL; // assume either "c" or "d" +#ifdef BB_FEATURE_VI_YANKMARK + if (c == 'y' || c == 'Y') + yf = YANKONLY; +#endif /* BB_FEATURE_VI_YANKMARK */ + c1 = 'y'; + if (c != 'Y') + c1 = get_one_char(); // get the type of thing to delete + find_range(&p, &q, c1); + if (c1 == 27) { // ESC- user changed mind and wants out + c = c1 = 27; // Escape- do nothing + } else if (strchr("wW", c1)) { + if (c == 'c') { + // don't include trailing WS as part of word + while (isblnk(*q)) { + if (q <= text || q[-1] == '\n') + break; + q--; + } + } + dot = yank_delete(p, q, 0, yf); // delete word + } else if (strchr("^0bBeEft$", c1)) { + // single line copy text into a register and delete + dot = yank_delete(p, q, 0, yf); // delete word + } else if (strchr("cdykjHL%+-{}\r\n", c1)) { + // multiple line copy text into a register and delete + dot = yank_delete(p, q, 1, yf); // delete lines + if (c == 'c') { + dot = char_insert(dot, '\n'); + // on the last line of file don't move to prev line + if (dot != (end-1)) { + dot_prev(); + } + } else if (c == 'd') { + dot_begin(); + dot_skip_over_ws(); + } + } else { + // could not recognize object + c = c1 = 27; // error- + indicate_error(c); + } + if (c1 != 27) { + // if CHANGING, not deleting, start inserting after the delete + if (c == 'c') { + strcpy((char *) buf, "Change"); + goto dc_i; // start inserting + } + if (c == 'd') { + strcpy((char *) buf, "Delete"); + } +#ifdef BB_FEATURE_VI_YANKMARK + if (c == 'y' || c == 'Y') { + strcpy((char *) buf, "Yank"); + } + p = reg[YDreg]; + q = p + strlen((char *) p); + for (cnt = 0; p <= q; p++) { + if (*p == '\n') + cnt++; + } + psb("%s %d lines (%d chars) using [%c]", + buf, cnt, strlen((char *) reg[YDreg]), what_reg()); +#endif /* BB_FEATURE_VI_YANKMARK */ + end_cmd_q(); // stop adding to q + } + break; + case 'k': // k- goto prev line, same col + case VI_K_UP: // cursor key Up + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + dot_prev(); + dot = move_to_col(dot, ccol + offset); // try stay in same col + break; + case 'r': // r- replace the current char with user input + c1 = get_one_char(); // get the replacement char + if (*dot != '\n') { + *dot = c1; + file_modified = TRUE; // has the file been modified + } + end_cmd_q(); // stop adding to q + break; + case 't': // t- move to char prior to next x + last_forward_char = get_one_char(); + do_cmd(';'); + if (*dot == last_forward_char) + dot_left(); + last_forward_char= 0; + break; + case 'w': // w- forward a word + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + if (isalnum(*dot) || *dot == '_') { // we are on ALNUM + dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); + } else if (ispunct(*dot)) { // we are on PUNCT + dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT); + } + if (dot < end - 1) + dot++; // move over word + if (isspace(*dot)) { + dot = skip_thing(dot, 2, FORWARD, S_OVER_WS); + } + break; + case 'z': // z- + c1 = get_one_char(); // get the replacement char + cnt = 0; + if (c1 == '.') + cnt = (rows - 2) / 2; // put dot at center + if (c1 == '-') + cnt = rows - 2; // put dot at bottom + screenbegin = begin_line(dot); // start dot at top + dot_scroll(cnt, -1); + break; + case '|': // |- move to column "cmdcnt" + dot = move_to_col(dot, cmdcnt - 1); // try to move to column + break; + case '~': // ~- flip the case of letters a-z -> A-Z + if (cmdcnt-- > 1) { + do_cmd(c); + } // repeat cnt + if (islower(*dot)) { + *dot = toupper(*dot); + file_modified = TRUE; // has the file been modified + } else if (isupper(*dot)) { + *dot = tolower(*dot); + file_modified = TRUE; // has the file been modified + } + dot_right(); + end_cmd_q(); // stop adding to q + break; + //----- The Cursor and Function Keys ----------------------------- + case VI_K_HOME: // Cursor Key Home + dot_begin(); + break; + // The Fn keys could point to do_macro which could translate them + case VI_K_FUN1: // Function Key F1 + case VI_K_FUN2: // Function Key F2 + case VI_K_FUN3: // Function Key F3 + case VI_K_FUN4: // Function Key F4 + case VI_K_FUN5: // Function Key F5 + case VI_K_FUN6: // Function Key F6 + case VI_K_FUN7: // Function Key F7 + case VI_K_FUN8: // Function Key F8 + case VI_K_FUN9: // Function Key F9 + case VI_K_FUN10: // Function Key F10 + case VI_K_FUN11: // Function Key F11 + case VI_K_FUN12: // Function Key F12 + break; + } + + dc1: + // if text[] just became empty, add back an empty line + if (end == text) { + (void) char_insert(text, '\n'); // start empty buf with dummy line + dot = text; + } + // it is OK for dot to exactly equal to end, otherwise check dot validity + if (dot != end) { + dot = bound_dot(dot); // make sure "dot" is valid + } +#ifdef BB_FEATURE_VI_YANKMARK + check_context(c); // update the current context +#endif /* BB_FEATURE_VI_YANKMARK */ + + if (!isdigit(c)) + cmdcnt = 0; // cmd was not a number, reset cmdcnt + cnt = dot - begin_line(dot); + // Try to stay off of the Newline + if (*dot == '\n' && cnt > 0 && cmd_mode == 0) + dot--; +} + +//----- The Colon commands ------------------------------------- +#ifdef BB_FEATURE_VI_COLON +static Byte *get_one_address(Byte * p, int *addr) // get colon addr, if present +{ + int st; + Byte *q; + +#ifdef BB_FEATURE_VI_YANKMARK + Byte c; +#endif /* BB_FEATURE_VI_YANKMARK */ +#ifdef BB_FEATURE_VI_SEARCH + Byte *pat, buf[BUFSIZ]; +#endif /* BB_FEATURE_VI_SEARCH */ + + *addr = -1; // assume no addr + if (*p == '.') { // the current line + p++; + q = begin_line(dot); + *addr = count_lines(text, q); +#ifdef BB_FEATURE_VI_YANKMARK + } else if (*p == '\'') { // is this a mark addr + p++; + c = tolower(*p); + p++; + if (c >= 'a' && c <= 'z') { + // we have a mark + c = c - 'a'; + q = mark[(int) c]; + if (q != NULL) { // is mark valid + *addr = count_lines(text, q); // count lines + } + } +#endif /* BB_FEATURE_VI_YANKMARK */ +#ifdef BB_FEATURE_VI_SEARCH + } else if (*p == '/') { // a search pattern + q = buf; + for (p++; *p; p++) { + if (*p == '/') + break; + *q++ = *p; + *q = '\0'; + } + pat = (Byte *) strdup((char *) buf); // save copy of pattern + if (*p == '/') + p++; + q = char_search(dot, pat, FORWARD, FULL); + if (q != NULL) { + *addr = count_lines(text, q); + } + free(pat); +#endif /* BB_FEATURE_VI_SEARCH */ + } else if (*p == '$') { // the last line in file + p++; + q = begin_line(end - 1); + *addr = count_lines(text, q); + } else if (isdigit(*p)) { // specific line number + sscanf((char *) p, "%d%n", addr, &st); + p += st; + } else { // I don't reconise this + // unrecognised address- assume -1 + *addr = -1; + } + return (p); +} + +static Byte *get_address(Byte *p, int *b, int *e) // get two colon addrs, if present +{ + //----- get the address' i.e., 1,3 'a,'b ----- + // get FIRST addr, if present + while (isblnk(*p)) + p++; // skip over leading spaces + if (*p == '%') { // alias for 1,$ + p++; + *b = 1; + *e = count_lines(text, end-1); + goto ga0; + } + p = get_one_address(p, b); + while (isblnk(*p)) + p++; + if (*p == ',') { // is there a address seperator + p++; + while (isblnk(*p)) + p++; + // get SECOND addr, if present + p = get_one_address(p, e); + } +ga0: + while (isblnk(*p)) + p++; // skip over trailing spaces + return (p); +} + +static void colon(Byte * buf) +{ + Byte c, *orig_buf, *buf1, *q, *r; + Byte *fn, cmd[BUFSIZ], args[BUFSIZ]; + int i, l, li, ch, st, b, e; + int useforce, forced; + struct stat st_buf; + + // :3154 // if (-e line 3154) goto it else stay put + // :4,33w! foo // write a portion of buffer to file "foo" + // :w // write all of buffer to current file + // :q // quit + // :q! // quit- dont care about modified file + // :'a,'z!sort -u // filter block through sort + // :'f // goto mark "f" + // :'fl // list literal the mark "f" line + // :.r bar // read file "bar" into buffer before dot + // :/123/,/abc/d // delete lines from "123" line to "abc" line + // :/xyz/ // goto the "xyz" line + // :s/find/replace/ // substitute pattern "find" with "replace" + // :! // run then return + // + if (strlen((char *) buf) <= 0) + goto vc1; + if (*buf == ':') + buf++; // move past the ':' + + forced = useforce = FALSE; + li = st = ch = i = 0; + b = e = -1; + q = text; // assume 1,$ for the range + r = end - 1; + li = count_lines(text, end - 1); + fn = cfn; // default to current file + memset(cmd, '\0', BUFSIZ); // clear cmd[] + memset(args, '\0', BUFSIZ); // clear args[] + + // look for optional address(es) :. :1 :1,9 :'q,'a :% + buf = get_address(buf, &b, &e); + + // remember orig command line + orig_buf = buf; + + // get the COMMAND into cmd[] + buf1 = cmd; + while (*buf != '\0') { + if (isspace(*buf)) + break; + *buf1++ = *buf++; + } + // get any ARGuments + while (isblnk(*buf)) + buf++; + strcpy((char *) args, (char *) buf); + buf1 = last_char_is((char *)cmd, '!'); + if (buf1) { + useforce = TRUE; + *buf1 = '\0'; // get rid of ! + } + if (b >= 0) { + // if there is only one addr, then the addr + // is the line number of the single line the + // user wants. So, reset the end + // pointer to point at end of the "b" line + q = find_line(b); // what line is #b + r = end_line(q); + li = 1; + } + if (e >= 0) { + // we were given two addrs. change the + // end pointer to the addr given by user. + r = find_line(e); // what line is #e + r = end_line(r); + li = e - b + 1; + } + // ------------ now look for the command ------------ + i = strlen((char *) cmd); + if (i == 0) { // :123CR goto line #123 + if (b >= 0) { + dot = find_line(b); // what line is #b + dot_skip_over_ws(); + } + } else if (strncmp((char *) cmd, "!", 1) == 0) { // run a cmd + // :!ls run the + (void) alarm(0); // wait for input- no alarms + place_cursor(rows - 1, 0, FALSE); // go to Status line + clear_to_eol(); // clear the line + cookmode(); + system(orig_buf+1); // run the cmd + rawmode(); + Hit_Return(); // let user see results + (void) alarm(3); // done waiting for input + } else if (strncmp((char *) cmd, "=", i) == 0) { // where is the address + if (b < 0) { // no addr given- use defaults + b = e = count_lines(text, dot); + } + psb("%d", b); + } else if (strncasecmp((char *) cmd, "delete", i) == 0) { // delete lines + if (b < 0) { // no addr given- use defaults + q = begin_line(dot); // assume .,. for the range + r = end_line(dot); + } + dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines + dot_skip_over_ws(); + } else if (strncasecmp((char *) cmd, "edit", i) == 0) { // Edit a file + int sr; + sr= 0; + // don't edit, if the current file has been modified + if (file_modified == TRUE && useforce != TRUE) { + psbs("No write since last change (:edit! overrides)"); + goto vc1; + } + if (strlen(args) > 0) { + // the user supplied a file name + fn= args; + } else if (cfn != 0 && strlen(cfn) > 0) { + // no user supplied name- use the current filename + fn= cfn; + goto vc5; + } else { + // no user file name, no current name- punt + psbs("No current filename"); + goto vc1; + } + + // see if file exists- if not, its just a new file request + if ((sr=stat((char*)fn, &st_buf)) < 0) { + // This is just a request for a new file creation. + // The file_insert below will fail but we get + // an empty buffer with a file name. Then the "write" + // command can do the create. + } else { + if ((st_buf.st_mode & (S_IFREG)) == 0) { + // This is not a regular file + psbs("\"%s\" is not a regular file", fn); + goto vc1; + } + if ((st_buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) { + // dont have any read permissions + psbs("\"%s\" is not readable", fn); + goto vc1; + } + } + + // There is a read-able regular file + // make this the current file + q = (Byte *) strdup((char *) fn); // save the cfn + if (cfn != 0) + free(cfn); // free the old name + cfn = q; // remember new cfn + + vc5: + // delete all the contents of text[] + new_text(2 * file_size(fn)); + screenbegin = dot = end = text; + + // insert new file + ch = file_insert(fn, text, file_size(fn)); + + if (ch < 1) { + // start empty buf with dummy line + (void) char_insert(text, '\n'); + ch= 1; + } + file_modified = FALSE; +#ifdef BB_FEATURE_VI_YANKMARK + if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { + free(reg[Ureg]); // free orig line reg- for 'U' + reg[Ureg]= 0; + } + if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) { + free(reg[YDreg]); // free default yank/delete register + reg[YDreg]= 0; + } + for (li = 0; li < 28; li++) { + mark[li] = 0; + } // init the marks +#endif /* BB_FEATURE_VI_YANKMARK */ + // how many lines in text[]? + li = count_lines(text, end - 1); + psb("\"%s\"%s" +#ifdef BB_FEATURE_VI_READONLY + "%s" +#endif /* BB_FEATURE_VI_READONLY */ + " %dL, %dC", cfn, + (sr < 0 ? " [New file]" : ""), +#ifdef BB_FEATURE_VI_READONLY + ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""), +#endif /* BB_FEATURE_VI_READONLY */ + li, ch); + } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this + if (b != -1 || e != -1) { + ni((Byte *) "No address allowed on this command"); + goto vc1; + } + if (strlen((char *) args) > 0) { + // user wants a new filename + if (cfn != NULL) + free(cfn); + cfn = (Byte *) strdup((char *) args); + } else { + // user wants file status info + edit_status(); + } + } else if (strncasecmp((char *) cmd, "features", i) == 0) { // what features are available + // print out values of all features + place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen + clear_to_eol(); // clear the line + cookmode(); + show_help(); + rawmode(); + Hit_Return(); + } else if (strncasecmp((char *) cmd, "list", i) == 0) { // literal print line + if (b < 0) { // no addr given- use defaults + q = begin_line(dot); // assume .,. for the range + r = end_line(dot); + } + place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen + clear_to_eol(); // clear the line + write(1, "\r\n", 2); + for (; q <= r; q++) { + c = *q; + if (c > '~') + standout_start(); + if (c == '\n') { + write(1, "$\r", 2); + } else if (*q < ' ') { + write(1, "^", 1); + c += '@'; + } + write(1, &c, 1); + if (c > '~') + standout_end(); + } +#ifdef BB_FEATURE_VI_SET + vc2: +#endif /* BB_FEATURE_VI_SET */ + Hit_Return(); + } else if ((strncasecmp((char *) cmd, "quit", i) == 0) || // Quit + (strncasecmp((char *) cmd, "next", i) == 0)) { // edit next file + if (useforce == TRUE) { + // force end of argv list + if (*cmd == 'q') { + optind = save_argc; + } + editing = 0; + goto vc1; + } + // don't exit if the file been modified + if (file_modified == TRUE) { + psbs("No write since last change (:%s! overrides)", + (*cmd == 'q' ? "quit" : "next")); + goto vc1; + } + // are there other file to edit + if (*cmd == 'q' && optind < save_argc - 1) { + psbs("%d more file to edit", (save_argc - optind - 1)); + goto vc1; + } + if (*cmd == 'n' && optind >= save_argc - 1) { + psbs("No more files to edit"); + goto vc1; + } + editing = 0; + } else if (strncasecmp((char *) cmd, "read", i) == 0) { // read file into text[] + fn = args; + if (strlen((char *) fn) <= 0) { + psbs("No filename given"); + goto vc1; + } + if (b < 0) { // no addr given- use defaults + q = begin_line(dot); // assume "dot" + } + // read after current line- unless user said ":0r foo" + if (b != 0) + q = next_line(q); +#ifdef BB_FEATURE_VI_READONLY + l= readonly; // remember current files' status +#endif + ch = file_insert(fn, q, file_size(fn)); +#ifdef BB_FEATURE_VI_READONLY + readonly= l; +#endif + if (ch < 0) + goto vc1; // nothing was inserted + // how many lines in text[]? + li = count_lines(q, q + ch - 1); + psb("\"%s\"" +#ifdef BB_FEATURE_VI_READONLY + "%s" +#endif /* BB_FEATURE_VI_READONLY */ + " %dL, %dC", fn, +#ifdef BB_FEATURE_VI_READONLY + ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""), +#endif /* BB_FEATURE_VI_READONLY */ + li, ch); + if (ch > 0) { + // if the insert is before "dot" then we need to update + if (q <= dot) + dot += ch; + file_modified = TRUE; + } + } else if (strncasecmp((char *) cmd, "rewind", i) == 0) { // rewind cmd line args + if (file_modified == TRUE && useforce != TRUE) { + psbs("No write since last change (:rewind! overrides)"); + } else { + // reset the filenames to edit + optind = fn_start - 1; + editing = 0; + } +#ifdef BB_FEATURE_VI_SET + } else if (strncasecmp((char *) cmd, "set", i) == 0) { // set or clear features + i = 0; // offset into args + if (strlen((char *) args) == 0) { + // print out values of all options + place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen + clear_to_eol(); // clear the line + printf("----------------------------------------\r\n"); +#ifdef BB_FEATURE_VI_SETOPTS + if (!autoindent) + printf("no"); + printf("autoindent "); + if (!err_method) + printf("no"); + printf("flash "); + if (!ignorecase) + printf("no"); + printf("ignorecase "); + if (!showmatch) + printf("no"); + printf("showmatch "); + printf("tabstop=%d ", tabstop); +#endif /* BB_FEATURE_VI_SETOPTS */ + printf("\r\n"); + goto vc2; + } + if (strncasecmp((char *) args, "no", 2) == 0) + i = 2; // ":set noautoindent" +#ifdef BB_FEATURE_VI_SETOPTS + if (strncasecmp((char *) args + i, "autoindent", 10) == 0 || + strncasecmp((char *) args + i, "ai", 2) == 0) { + autoindent = (i == 2) ? 0 : 1; + } + if (strncasecmp((char *) args + i, "flash", 5) == 0 || + strncasecmp((char *) args + i, "fl", 2) == 0) { + err_method = (i == 2) ? 0 : 1; + } + if (strncasecmp((char *) args + i, "ignorecase", 10) == 0 || + strncasecmp((char *) args + i, "ic", 2) == 0) { + ignorecase = (i == 2) ? 0 : 1; + } + if (strncasecmp((char *) args + i, "showmatch", 9) == 0 || + strncasecmp((char *) args + i, "sm", 2) == 0) { + showmatch = (i == 2) ? 0 : 1; + } + if (strncasecmp((char *) args + i, "tabstop", 7) == 0) { + sscanf(strchr((char *) args + i, '='), "=%d", &ch); + if (ch > 0 && ch < columns - 1) + tabstop = ch; + } +#endif /* BB_FEATURE_VI_SETOPTS */ +#endif /* BB_FEATURE_VI_SET */ +#ifdef BB_FEATURE_VI_SEARCH + } else if (strncasecmp((char *) cmd, "s", 1) == 0) { // substitute a pattern with a replacement pattern + Byte *ls, *F, *R; + int gflag; + + // F points to the "find" pattern + // R points to the "replace" pattern + // replace the cmd line delimiters "/" with NULLs + gflag = 0; // global replace flag + c = orig_buf[1]; // what is the delimiter + F = orig_buf + 2; // start of "find" + R = (Byte *) strchr((char *) F, c); // middle delimiter + if (!R) goto colon_s_fail; + *R++ = '\0'; // terminate "find" + buf1 = (Byte *) strchr((char *) R, c); + if (!buf1) goto colon_s_fail; + *buf1++ = '\0'; // terminate "replace" + if (*buf1 == 'g') { // :s/foo/bar/g + buf1++; + gflag++; // turn on gflag + } + q = begin_line(q); + if (b < 0) { // maybe :s/foo/bar/ + q = begin_line(dot); // start with cur line + b = count_lines(text, q); // cur line number + } + if (e < 0) + e = b; // maybe :.s/foo/bar/ + for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 + ls = q; // orig line start + vc4: + buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" + if (buf1 != NULL) { + // we found the "find" pattern- delete it + (void) text_hole_delete(buf1, buf1 + strlen((char *) F) - 1); + // inset the "replace" patern + (void) string_insert(buf1, R); // insert the string + // check for "global" :s/foo/bar/g + if (gflag == 1) { + if ((buf1 + strlen((char *) R)) < end_line(ls)) { + q = buf1 + strlen((char *) R); + goto vc4; // don't let q move past cur line + } + } + } + q = next_line(ls); + } +#endif /* BB_FEATURE_VI_SEARCH */ + } else if (strncasecmp((char *) cmd, "version", i) == 0) { // show software version + psb("%s", vi_Version); + } else if ((strncasecmp((char *) cmd, "write", i) == 0) || // write text to file + (strncasecmp((char *) cmd, "wq", i) == 0)) { // write text to file + // is there a file name to write to? + if (strlen((char *) args) > 0) { + fn = args; + } +#ifdef BB_FEATURE_VI_READONLY + if ((vi_readonly == TRUE || readonly == TRUE) && useforce == FALSE) { + psbs("\"%s\" File is read only", fn); + goto vc3; + } +#endif /* BB_FEATURE_VI_READONLY */ + // how many lines in text[]? + li = count_lines(q, r); + ch = r - q + 1; + // see if file exists- if not, its just a new file request + if (useforce == TRUE) { + // if "fn" is not write-able, chmod u+w + // sprintf(syscmd, "chmod u+w %s", fn); + // system(syscmd); + forced = TRUE; + } + l = file_write(fn, q, r); + if (useforce == TRUE && forced == TRUE) { + // chmod u-w + // sprintf(syscmd, "chmod u-w %s", fn); + // system(syscmd); + forced = FALSE; + } + psb("\"%s\" %dL, %dC", fn, li, l); + if (q == text && r == end - 1 && l == ch) + file_modified = FALSE; + if (cmd[1] == 'q' && l == ch) { + editing = 0; + } +#ifdef BB_FEATURE_VI_READONLY + vc3:; +#endif /* BB_FEATURE_VI_READONLY */ +#ifdef BB_FEATURE_VI_YANKMARK + } else if (strncasecmp((char *) cmd, "yank", i) == 0) { // yank lines + if (b < 0) { // no addr given- use defaults + q = begin_line(dot); // assume .,. for the range + r = end_line(dot); + } + text_yank(q, r, YDreg); + li = count_lines(q, r); + psb("Yank %d lines (%d chars) into [%c]", + li, strlen((char *) reg[YDreg]), what_reg()); +#endif /* BB_FEATURE_VI_YANKMARK */ + } else { + // cmd unknown + ni((Byte *) cmd); + } + vc1: + dot = bound_dot(dot); // make sure "dot" is valid + return; +#ifdef BB_FEATURE_VI_SEARCH +colon_s_fail: + psb(":s expression missing delimiters"); + return; +#endif + +} + +static void Hit_Return(void) +{ + char c; + + standout_start(); // start reverse video + write(1, "[Hit return to continue]", 24); + standout_end(); // end reverse video + while ((c = get_one_char()) != '\n' && c != '\r') /*do nothing */ + ; + redraw(TRUE); // force redraw all +} +#endif /* BB_FEATURE_VI_COLON */ + +//----- Synchronize the cursor to Dot -------------------------- +static void sync_cursor(Byte * d, int *row, int *col) +{ + Byte *beg_cur, *end_cur; // begin and end of "d" line + Byte *beg_scr, *end_scr; // begin and end of screen + Byte *tp; + int cnt, ro, co; + + beg_cur = begin_line(d); // first char of cur line + end_cur = end_line(d); // last char of cur line + + beg_scr = end_scr = screenbegin; // first char of screen + end_scr = end_screen(); // last char of screen + + if (beg_cur < screenbegin) { + // "d" is before top line on screen + // how many lines do we have to move + cnt = count_lines(beg_cur, screenbegin); + sc1: + screenbegin = beg_cur; + if (cnt > (rows - 1) / 2) { + // we moved too many lines. put "dot" in middle of screen + for (cnt = 0; cnt < (rows - 1) / 2; cnt++) { + screenbegin = prev_line(screenbegin); + } + } + } else if (beg_cur > end_scr) { + // "d" is after bottom line on screen + // how many lines do we have to move + cnt = count_lines(end_scr, beg_cur); + if (cnt > (rows - 1) / 2) + goto sc1; // too many lines + for (ro = 0; ro < cnt - 1; ro++) { + // move screen begin the same amount + screenbegin = next_line(screenbegin); + // now, move the end of screen + end_scr = next_line(end_scr); + end_scr = end_line(end_scr); + } + } + // "d" is on screen- find out which row + tp = screenbegin; + for (ro = 0; ro < rows - 1; ro++) { // drive "ro" to correct row + if (tp == beg_cur) + break; + tp = next_line(tp); + } + + // find out what col "d" is on + co = 0; + do { // drive "co" to correct column + if (*tp == '\n' || *tp == '\0') + break; + if (*tp == '\t') { + // 7 - (co % 8 ) + co += ((tabstop - 1) - (co % tabstop)); + } else if (*tp < ' ') { + co++; // display as ^X, use 2 columns + } + } while (tp++ < d && ++co); + + // "co" is the column where "dot" is. + // The screen has "columns" columns. + // The currently displayed columns are 0+offset -- columns+ofset + // |-------------------------------------------------------------| + // ^ ^ ^ + // offset | |------- columns ----------------| + // + // If "co" is already in this range then we do not have to adjust offset + // but, we do have to subtract the "offset" bias from "co". + // If "co" is outside this range then we have to change "offset". + // If the first char of a line is a tab the cursor will try to stay + // in column 7, but we have to set offset to 0. + + if (co < 0 + offset) { + offset = co; + } + if (co >= columns + offset) { + offset = co - columns + 1; + } + // if the first char of the line is a tab, and "dot" is sitting on it + // force offset to 0. + if (d == beg_cur && *d == '\t') { + offset = 0; + } + co -= offset; + + *row = ro; + *col = co; +} + +//----- Text Movement Routines --------------------------------- +static Byte *begin_line(Byte * p) // return pointer to first char cur line +{ + while (p > text && p[-1] != '\n') + p--; // go to cur line B-o-l + return (p); +} + +static Byte *end_line(Byte * p) // return pointer to NL of cur line line +{ + while (p < end - 1 && *p != '\n') + p++; // go to cur line E-o-l + return (p); +} + +static Byte *dollar_line(Byte * p) // return pointer to just before NL line +{ + while (p < end - 1 && *p != '\n') + p++; // go to cur line E-o-l + // Try to stay off of the Newline + if (*p == '\n' && (p - begin_line(p)) > 0) + p--; + return (p); +} + +static Byte *prev_line(Byte * p) // return pointer first char prev line +{ + p = begin_line(p); // goto begining of cur line + if (p[-1] == '\n' && p > text) + p--; // step to prev line + p = begin_line(p); // goto begining of prev line + return (p); +} + +static Byte *next_line(Byte * p) // return pointer first char next line +{ + p = end_line(p); + if (*p == '\n' && p < end - 1) + p++; // step to next line + return (p); +} + +//----- Text Information Routines ------------------------------ +static Byte *end_screen(void) +{ + Byte *q; + int cnt; + + // find new bottom line + q = screenbegin; + for (cnt = 0; cnt < rows - 2; cnt++) + q = next_line(q); + q = end_line(q); + return (q); +} + +static int count_lines(Byte * start, Byte * stop) // count line from start to stop +{ + Byte *q; + int cnt; + + if (stop < start) { // start and stop are backwards- reverse them + q = start; + start = stop; + stop = q; + } + cnt = 0; + stop = end_line(stop); // get to end of this line + for (q = start; q <= stop && q <= end - 1; q++) { + if (*q == '\n') + cnt++; + } + return (cnt); +} + +static Byte *find_line(int li) // find begining of line #li +{ + Byte *q; + + for (q = text; li > 1; li--) { + q = next_line(q); + } + return (q); +} + +//----- Dot Movement Routines ---------------------------------- +static void dot_left(void) +{ + if (dot > text && dot[-1] != '\n') + dot--; +} + +static void dot_right(void) +{ + if (dot < end - 1 && *dot != '\n') + dot++; +} + +static void dot_begin(void) +{ + dot = begin_line(dot); // return pointer to first char cur line +} + +static void dot_end(void) +{ + dot = end_line(dot); // return pointer to last char cur line +} + +static Byte *move_to_col(Byte * p, int l) +{ + int co; + + p = begin_line(p); + co = 0; + do { + if (*p == '\n' || *p == '\0') + break; + if (*p == '\t') { + // 7 - (co % 8 ) + co += ((tabstop - 1) - (co % tabstop)); + } else if (*p < ' ') { + co++; // display as ^X, use 2 columns + } + } while (++co <= l && p++ < end); + return (p); +} + +static void dot_next(void) +{ + dot = next_line(dot); +} + +static void dot_prev(void) +{ + dot = prev_line(dot); +} + +static void dot_scroll(int cnt, int dir) +{ + Byte *q; + + for (; cnt > 0; cnt--) { + if (dir < 0) { + // scroll Backwards + // ctrl-Y scroll up one line + screenbegin = prev_line(screenbegin); + } else { + // scroll Forwards + // ctrl-E scroll down one line + screenbegin = next_line(screenbegin); + } + } + // make sure "dot" stays on the screen so we dont scroll off + if (dot < screenbegin) + dot = screenbegin; + q = end_screen(); // find new bottom line + if (dot > q) + dot = begin_line(q); // is dot is below bottom line? + dot_skip_over_ws(); +} + +static void dot_skip_over_ws(void) +{ + // skip WS + while (isspace(*dot) && *dot != '\n' && dot < end - 1) + dot++; +} + +static void dot_delete(void) // delete the char at 'dot' +{ + (void) text_hole_delete(dot, dot); +} + +static Byte *bound_dot(Byte * p) // make sure text[0] <= P < "end" +{ + if (p >= end && end > text) { + p = end - 1; + indicate_error('1'); + } + if (p < text) { + p = text; + indicate_error('2'); + } + return (p); +} + +//----- Helper Utility Routines -------------------------------- + +//---------------------------------------------------------------- +//----- Char Routines -------------------------------------------- +/* Chars that are part of a word- + * 0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz + * Chars that are Not part of a word (stoppers) + * !"#$%&'()*+,-./:;<=>?@[\]^`{|}~ + * Chars that are WhiteSpace + * TAB NEWLINE VT FF RETURN SPACE + * DO NOT COUNT NEWLINE AS WHITESPACE + */ + +static Byte *new_screen(int ro, int co) +{ + int li; + + if (screen != 0) + free(screen); + screensize = ro * co + 8; + screen = (Byte *) xmalloc(screensize); + // initialize the new screen. assume this will be a empty file. + screen_erase(); + // non-existant text[] lines start with a tilde (~). + for (li = 1; li < ro - 1; li++) { + screen[(li * co) + 0] = '~'; + } + return (screen); +} + +static Byte *new_text(int size) +{ + if (size < 10240) + size = 10240; // have a minimum size for new files + if (text != 0) { + //text -= 4; + free(text); + } + text = (Byte *) xmalloc(size + 8); + memset(text, '\0', size); // clear new text[] + //text += 4; // leave some room for "oops" + textend = text + size - 1; + //textend -= 4; // leave some root for "oops" + return (text); +} + +#ifdef BB_FEATURE_VI_SEARCH +static int mycmp(Byte * s1, Byte * s2, int len) +{ + int i; + + i = strncmp((char *) s1, (char *) s2, len); +#ifdef BB_FEATURE_VI_SETOPTS + if (ignorecase) { + i = strncasecmp((char *) s1, (char *) s2, len); + } +#endif /* BB_FEATURE_VI_SETOPTS */ + return (i); +} + +static Byte *char_search(Byte * p, Byte * pat, int dir, int range) // search for pattern starting at p +{ +#ifndef REGEX_SEARCH + Byte *start, *stop; + int len; + + len = strlen((char *) pat); + if (dir == FORWARD) { + stop = end - 1; // assume range is p - end-1 + if (range == LIMITED) + stop = next_line(p); // range is to next line + for (start = p; start < stop; start++) { + if (mycmp(start, pat, len) == 0) { + return (start); + } + } + } else if (dir == BACK) { + stop = text; // assume range is text - p + if (range == LIMITED) + stop = prev_line(p); // range is to prev line + for (start = p - len; start >= stop; start--) { + if (mycmp(start, pat, len) == 0) { + return (start); + } + } + } + // pattern not found + return (NULL); +#else /*REGEX_SEARCH */ + char *q; + struct re_pattern_buffer preg; + int i; + int size, range; + + re_syntax_options = RE_SYNTAX_POSIX_EXTENDED; + preg.translate = 0; + preg.fastmap = 0; + preg.buffer = 0; + preg.allocated = 0; + + // assume a LIMITED forward search + q = next_line(p); + q = end_line(q); + q = end - 1; + if (dir == BACK) { + q = prev_line(p); + q = text; + } + // count the number of chars to search over, forward or backward + size = q - p; + if (size < 0) + size = p - q; + // RANGE could be negative if we are searching backwards + range = q - p; + + q = (char *) re_compile_pattern(pat, strlen((char *) pat), &preg); + if (q != 0) { + // The pattern was not compiled + psbs("bad search pattern: \"%s\": %s", pat, q); + i = 0; // return p if pattern not compiled + goto cs1; + } + + q = p; + if (range < 0) { + q = p - size; + if (q < text) + q = text; + } + // search for the compiled pattern, preg, in p[] + // range < 0- search backward + // range > 0- search forward + // 0 < start < size + // re_search() < 0 not found or error + // re_search() > 0 index of found pattern + // struct pattern char int int int struct reg + // re_search (*pattern_buffer, *string, size, start, range, *regs) + i = re_search(&preg, q, size, 0, range, 0); + if (i == -1) { + p = 0; + i = 0; // return NULL if pattern not found + } + cs1: + if (dir == FORWARD) { + p = p + i; + } else { + p = p - i; + } + return (p); +#endif /*REGEX_SEARCH */ +} +#endif /* BB_FEATURE_VI_SEARCH */ + +static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p' +{ + if (c == 22) { // Is this an ctrl-V? + p = stupid_insert(p, '^'); // use ^ to indicate literal next + p--; // backup onto ^ + refresh(FALSE); // show the ^ + c = get_one_char(); + *p = c; + p++; + file_modified = TRUE; // has the file been modified + } else if (c == 27) { // Is this an ESC? + cmd_mode = 0; + cmdcnt = 0; + end_cmd_q(); // stop adding to q + strcpy((char *) status_buffer, " "); // clear the status buffer + if ((p[-1] != '\n') && (dot>text)) { + p--; + } + } else if (c == erase_char) { // Is this a BS + // 123456789 + if ((p[-1] != '\n') && (dot>text)) { + p--; + p = text_hole_delete(p, p); // shrink buffer 1 char +#ifdef BB_FEATURE_VI_DOT_CMD + // also rmove char from last_modifying_cmd + if (strlen((char *) last_modifying_cmd) > 0) { + Byte *q; + + q = last_modifying_cmd; + q[strlen((char *) q) - 1] = '\0'; // erase BS + q[strlen((char *) q) - 1] = '\0'; // erase prev char + } +#endif /* BB_FEATURE_VI_DOT_CMD */ + } + } else { + // insert a char into text[] + Byte *sp; // "save p" + + if (c == 13) + c = '\n'; // translate \r to \n + sp = p; // remember addr of insert + p = stupid_insert(p, c); // insert the char +#ifdef BB_FEATURE_VI_SETOPTS + if (showmatch && strchr(")]}", *sp) != NULL) { + showmatching(sp); + } + if (autoindent && c == '\n') { // auto indent the new line + Byte *q; + + q = prev_line(p); // use prev line as templet + for (; isblnk(*q); q++) { + p = stupid_insert(p, *q); // insert the char + } + } +#endif /* BB_FEATURE_VI_SETOPTS */ + } + return (p); +} + +static Byte *stupid_insert(Byte * p, Byte c) // stupidly insert the char c at 'p' +{ + p = text_hole_make(p, 1); + if (p != 0) { + *p = c; + file_modified = TRUE; // has the file been modified + p++; + } + return (p); +} + +static Byte find_range(Byte ** start, Byte ** stop, Byte c) +{ + Byte *save_dot, *p, *q; + int cnt; + + save_dot = dot; + p = q = dot; + + if (strchr("cdy><", c)) { + // these cmds operate on whole lines + p = q = begin_line(p); + for (cnt = 1; cnt < cmdcnt; cnt++) { + q = next_line(q); + } + q = end_line(q); + } else if (strchr("^%$0bBeEft", c)) { + // These cmds operate on char positions + do_cmd(c); // execute movement cmd + q = dot; + } else if (strchr("wW", c)) { + do_cmd(c); // execute movement cmd + if (dot > text) + dot--; // move back off of next word + if (dot > text && *dot == '\n') + dot--; // stay off NL + q = dot; + } else if (strchr("H-k{", c)) { + // these operate on multi-lines backwards + q = end_line(dot); // find NL + do_cmd(c); // execute movement cmd + dot_begin(); + p = dot; + } else if (strchr("L+j}\r\n", c)) { + // these operate on multi-lines forwards + p = begin_line(dot); + do_cmd(c); // execute movement cmd + dot_end(); // find NL + q = dot; + } else { + c = 27; // error- return an ESC char + //break; + } + *start = p; + *stop = q; + if (q < p) { + *start = q; + *stop = p; + } + dot = save_dot; + return (c); +} + +static int st_test(Byte * p, int type, int dir, Byte * tested) +{ + Byte c, c0, ci; + int test, inc; + + inc = dir; + c = c0 = p[0]; + ci = p[inc]; + test = 0; + + if (type == S_BEFORE_WS) { + c = ci; + test = ((!isspace(c)) || c == '\n'); + } + if (type == S_TO_WS) { + c = c0; + test = ((!isspace(c)) || c == '\n'); + } + if (type == S_OVER_WS) { + c = c0; + test = ((isspace(c))); + } + if (type == S_END_PUNCT) { + c = ci; + test = ((ispunct(c))); + } + if (type == S_END_ALNUM) { + c = ci; + test = ((isalnum(c)) || c == '_'); + } + *tested = c; + return (test); +} + +static Byte *skip_thing(Byte * p, int linecnt, int dir, int type) +{ + Byte c; + + while (st_test(p, type, dir, &c)) { + // make sure we limit search to correct number of lines + if (c == '\n' && --linecnt < 1) + break; + if (dir >= 0 && p >= end - 1) + break; + if (dir < 0 && p <= text) + break; + p += dir; // move to next char + } + return (p); +} + +// find matching char of pair () [] {} +static Byte *find_pair(Byte * p, Byte c) +{ + Byte match, *q; + int dir, level; + + match = ')'; + level = 1; + dir = 1; // assume forward + switch (c) { + case '(': + match = ')'; + break; + case '[': + match = ']'; + break; + case '{': + match = '}'; + break; + case ')': + match = '('; + dir = -1; + break; + case ']': + match = '['; + dir = -1; + break; + case '}': + match = '{'; + dir = -1; + break; + } + for (q = p + dir; text <= q && q < end; q += dir) { + // look for match, count levels of pairs (( )) + if (*q == c) + level++; // increase pair levels + if (*q == match) + level--; // reduce pair level + if (level == 0) + break; // found matching pair + } + if (level != 0) + q = NULL; // indicate no match + return (q); +} + +#ifdef BB_FEATURE_VI_SETOPTS +// show the matching char of a pair, () [] {} +static void showmatching(Byte * p) +{ + Byte *q, *save_dot; + + // we found half of a pair + q = find_pair(p, *p); // get loc of matching char + if (q == NULL) { + indicate_error('3'); // no matching char + } else { + // "q" now points to matching pair + save_dot = dot; // remember where we are + dot = q; // go to new loc + refresh(FALSE); // let the user see it + (void) mysleep(40); // give user some time + dot = save_dot; // go back to old loc + refresh(FALSE); + } +} +#endif /* BB_FEATURE_VI_SETOPTS */ + +// open a hole in text[] +static Byte *text_hole_make(Byte * p, int size) // at "p", make a 'size' byte hole +{ + Byte *src, *dest; + int cnt; + + if (size <= 0) + goto thm0; + src = p; + dest = p + size; + cnt = end - src; // the rest of buffer + if (memmove(dest, src, cnt) != dest) { + psbs("can't create room for new characters"); + } + memset(p, ' ', size); // clear new hole + end = end + size; // adjust the new END + file_modified = TRUE; // has the file been modified + thm0: + return (p); +} + +// close a hole in text[] +static Byte *text_hole_delete(Byte * p, Byte * q) // delete "p" thru "q", inclusive +{ + Byte *src, *dest; + int cnt, hole_size; + + // move forwards, from beginning + // assume p <= q + src = q + 1; + dest = p; + if (q < p) { // they are backward- swap them + src = p + 1; + dest = q; + } + hole_size = q - p + 1; + cnt = end - src; + if (src < text || src > end) + goto thd0; + if (dest < text || dest >= end) + goto thd0; + if (src >= end) + goto thd_atend; // just delete the end of the buffer + if (memmove(dest, src, cnt) != dest) { + psbs("can't delete the character"); + } + thd_atend: + end = end - hole_size; // adjust the new END + if (dest >= end) + dest = end - 1; // make sure dest in below end-1 + if (end <= text) + dest = end = text; // keep pointers valid + file_modified = TRUE; // has the file been modified + thd0: + return (dest); +} + +// copy text into register, then delete text. +// if dist <= 0, do not include, or go past, a NewLine +// +static Byte *yank_delete(Byte * start, Byte * stop, int dist, int yf) +{ + Byte *p; + + // make sure start <= stop + if (start > stop) { + // they are backwards, reverse them + p = start; + start = stop; + stop = p; + } + if (dist <= 0) { + // we can not cross NL boundaries + p = start; + if (*p == '\n') + return (p); + // dont go past a NewLine + for (; p + 1 <= stop; p++) { + if (p[1] == '\n') { + stop = p; // "stop" just before NewLine + break; + } + } + } + p = start; +#ifdef BB_FEATURE_VI_YANKMARK + text_yank(start, stop, YDreg); +#endif /* BB_FEATURE_VI_YANKMARK */ + if (yf == YANKDEL) { + p = text_hole_delete(start, stop); + } // delete lines + return (p); +} + +static void show_help(void) +{ + puts("These features are available:" +#ifdef BB_FEATURE_VI_SEARCH + "\n\tPattern searches with / and ?" +#endif /* BB_FEATURE_VI_SEARCH */ +#ifdef BB_FEATURE_VI_DOT_CMD + "\n\tLast command repeat with \'.\'" +#endif /* BB_FEATURE_VI_DOT_CMD */ +#ifdef BB_FEATURE_VI_YANKMARK + "\n\tLine marking with 'x" + "\n\tNamed buffers with \"x" +#endif /* BB_FEATURE_VI_YANKMARK */ +#ifdef BB_FEATURE_VI_READONLY + "\n\tReadonly if vi is called as \"view\"" + "\n\tReadonly with -R command line arg" +#endif /* BB_FEATURE_VI_READONLY */ +#ifdef BB_FEATURE_VI_SET + "\n\tSome colon mode commands with \':\'" +#endif /* BB_FEATURE_VI_SET */ +#ifdef BB_FEATURE_VI_SETOPTS + "\n\tSettable options with \":set\"" +#endif /* BB_FEATURE_VI_SETOPTS */ +#ifdef BB_FEATURE_VI_USE_SIGNALS + "\n\tSignal catching- ^C" + "\n\tJob suspend and resume with ^Z" +#endif /* BB_FEATURE_VI_USE_SIGNALS */ +#ifdef BB_FEATURE_VI_WIN_RESIZE + "\n\tAdapt to window re-sizes" +#endif /* BB_FEATURE_VI_WIN_RESIZE */ + ); +} + +static void print_literal(Byte * buf, Byte * s) // copy s to buf, convert unprintable +{ + Byte c, b[2]; + + b[1] = '\0'; + strcpy((char *) buf, ""); // init buf + if (strlen((char *) s) <= 0) + s = (Byte *) "(NULL)"; + for (; *s > '\0'; s++) { + c = *s; + if (*s > '~') { + strcat((char *) buf, SOs); + c = *s - 128; + } + if (*s < ' ') { + strcat((char *) buf, "^"); + c += '@'; + } + b[0] = c; + strcat((char *) buf, (char *) b); + if (*s > '~') + strcat((char *) buf, SOn); + if (*s == '\n') { + strcat((char *) buf, "$"); + } + } +} + +#ifdef BB_FEATURE_VI_DOT_CMD +static void start_new_cmd_q(Byte c) +{ + // release old cmd + if (last_modifying_cmd != 0) + free(last_modifying_cmd); + // get buffer for new cmd + last_modifying_cmd = (Byte *) xmalloc(BUFSIZ); + memset(last_modifying_cmd, '\0', BUFSIZ); // clear new cmd queue + // if there is a current cmd count put it in the buffer first + if (cmdcnt > 0) + sprintf((char *) last_modifying_cmd, "%d", cmdcnt); + // save char c onto queue + last_modifying_cmd[strlen((char *) last_modifying_cmd)] = c; + adding2q = 1; + return; +} + +static void end_cmd_q() +{ +#ifdef BB_FEATURE_VI_YANKMARK + YDreg = 26; // go back to default Yank/Delete reg +#endif /* BB_FEATURE_VI_YANKMARK */ + adding2q = 0; + return; +} +#endif /* BB_FEATURE_VI_DOT_CMD */ + +#if defined(BB_FEATURE_VI_YANKMARK) || defined(BB_FEATURE_VI_COLON) || defined(BB_FEATURE_VI_CRASHME) +static Byte *string_insert(Byte * p, Byte * s) // insert the string at 'p' +{ + int cnt, i; + + i = strlen((char *) s); + p = text_hole_make(p, i); + strncpy((char *) p, (char *) s, i); + for (cnt = 0; *s != '\0'; s++) { + if (*s == '\n') + cnt++; + } +#ifdef BB_FEATURE_VI_YANKMARK + psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); +#endif /* BB_FEATURE_VI_YANKMARK */ + return (p); +} +#endif /* BB_FEATURE_VI_YANKMARK || BB_FEATURE_VI_COLON || BB_FEATURE_VI_CRASHME */ + +#ifdef BB_FEATURE_VI_YANKMARK +static Byte *text_yank(Byte * p, Byte * q, int dest) // copy text into a register +{ + Byte *t; + int cnt; + + if (q < p) { // they are backwards- reverse them + t = q; + q = p; + p = t; + } + cnt = q - p + 1; + t = reg[dest]; + if (t != 0) { // if already a yank register + free(t); // free it + } + t = (Byte *) xmalloc(cnt + 1); // get a new register + memset(t, '\0', cnt + 1); // clear new text[] + strncpy((char *) t, (char *) p, cnt); // copy text[] into bufer + reg[dest] = t; + return (p); +} + +static Byte what_reg(void) +{ + Byte c; + int i; + + i = 0; + c = 'D'; // default to D-reg + if (0 <= YDreg && YDreg <= 25) + c = 'a' + (Byte) YDreg; + if (YDreg == 26) + c = 'D'; + if (YDreg == 27) + c = 'U'; + return (c); +} + +static void check_context(Byte cmd) +{ + // A context is defined to be "modifying text" + // Any modifying command establishes a new context. + + if (dot < context_start || dot > context_end) { + if (strchr((char *) modifying_cmds, cmd) != NULL) { + // we are trying to modify text[]- make this the current context + mark[27] = mark[26]; // move cur to prev + mark[26] = dot; // move local to cur + context_start = prev_line(prev_line(dot)); + context_end = next_line(next_line(dot)); + //loiter= start_loiter= now; + } + } + return; +} + +static Byte *swap_context(Byte * p) // goto new context for '' command make this the current context +{ + Byte *tmp; + + // the current context is in mark[26] + // the previous context is in mark[27] + // only swap context if other context is valid + if (text <= mark[27] && mark[27] <= end - 1) { + tmp = mark[27]; + mark[27] = mark[26]; + mark[26] = tmp; + p = mark[26]; // where we are going- previous context + context_start = prev_line(prev_line(prev_line(p))); + context_end = next_line(next_line(next_line(p))); + } + return (p); +} +#endif /* BB_FEATURE_VI_YANKMARK */ + +static int isblnk(Byte c) // is the char a blank or tab +{ + return (c == ' ' || c == '\t'); +} + +//----- Set terminal attributes -------------------------------- +static void rawmode(void) +{ + tcgetattr(0, &term_orig); + term_vi = term_orig; + term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's + term_vi.c_iflag &= (~IXON & ~ICRNL); + term_vi.c_oflag &= (~ONLCR); + term_vi.c_cc[VMIN] = 1; + term_vi.c_cc[VTIME] = 0; + erase_char = term_vi.c_cc[VERASE]; + tcsetattr(0, TCSANOW, &term_vi); +} + +static void cookmode(void) +{ + tcsetattr(0, TCSANOW, &term_orig); +} + +#ifdef BB_FEATURE_VI_WIN_RESIZE +//----- See what the window size currently is -------------------- +static void window_size_get(int sig) +{ + int i; + + i = ioctl(0, TIOCGWINSZ, &winsize); + if (i != 0) { + // force 24x80 + winsize.ws_row = 24; + winsize.ws_col = 80; + } + if (winsize.ws_row <= 1) { + winsize.ws_row = 24; + } + if (winsize.ws_col <= 1) { + winsize.ws_col = 80; + } + rows = (int) winsize.ws_row; + columns = (int) winsize.ws_col; +} +#endif /* BB_FEATURE_VI_WIN_RESIZE */ + +//----- Come here when we get a window resize signal --------- +#ifdef BB_FEATURE_VI_USE_SIGNALS +static void winch_sig(int sig) +{ + signal(SIGWINCH, winch_sig); +#ifdef BB_FEATURE_VI_WIN_RESIZE + window_size_get(0); +#endif /* BB_FEATURE_VI_WIN_RESIZE */ + new_screen(rows, columns); // get memory for virtual screen + redraw(TRUE); // re-draw the screen +} + +//----- Come here when we get a continue signal ------------------- +static void cont_sig(int sig) +{ + rawmode(); // terminal to "raw" + *status_buffer = '\0'; // clear the status buffer + redraw(TRUE); // re-draw the screen + + signal(SIGTSTP, suspend_sig); + signal(SIGCONT, SIG_DFL); + kill(getpid(), SIGCONT); +} + +//----- Come here when we get a Suspend signal ------------------- +static void suspend_sig(int sig) +{ + place_cursor(rows - 1, 0, FALSE); // go to bottom of screen + clear_to_eol(); // Erase to end of line + cookmode(); // terminal to "cooked" + + signal(SIGCONT, cont_sig); + signal(SIGTSTP, SIG_DFL); + kill(getpid(), SIGTSTP); +} + +//----- Come here when we get a signal --------------------------- +static void catch_sig(int sig) +{ + signal(SIGHUP, catch_sig); + signal(SIGINT, catch_sig); + signal(SIGTERM, catch_sig); + longjmp(restart, sig); +} + +static void alarm_sig(int sig) +{ + signal(SIGALRM, catch_sig); + longjmp(restart, sig); +} + +//----- Come here when we get a core dump signal ----------------- +static void core_sig(int sig) +{ + signal(SIGQUIT, core_sig); + signal(SIGILL, core_sig); + signal(SIGTRAP, core_sig); + signal(SIGIOT, core_sig); + signal(SIGABRT, core_sig); + signal(SIGFPE, core_sig); + signal(SIGBUS, core_sig); + signal(SIGSEGV, core_sig); +#ifdef SIGSYS + signal(SIGSYS, core_sig); +#endif + + dot = bound_dot(dot); // make sure "dot" is valid + + longjmp(restart, sig); +} +#endif /* BB_FEATURE_VI_USE_SIGNALS */ + +static int mysleep(int hund) // sleep for 'h' 1/100 seconds +{ + // Don't hang- Wait 5/100 seconds- 1 Sec= 1000000 + FD_ZERO(&rfds); + FD_SET(0, &rfds); + tv.tv_sec = 0; + tv.tv_usec = hund * 10000; + select(1, &rfds, NULL, NULL, &tv); + return (FD_ISSET(0, &rfds)); +} + +//----- IO Routines -------------------------------------------- +static Byte readit(void) // read (maybe cursor) key from stdin +{ + Byte c; + int i, bufsiz, cnt, cmdindex; + struct esc_cmds { + Byte *seq; + Byte val; + }; + + static struct esc_cmds esccmds[] = { + {(Byte *) "OA", (Byte) VI_K_UP}, // cursor key Up + {(Byte *) "OB", (Byte) VI_K_DOWN}, // cursor key Down + {(Byte *) "OC", (Byte) VI_K_RIGHT}, // Cursor Key Right + {(Byte *) "OD", (Byte) VI_K_LEFT}, // cursor key Left + {(Byte *) "OH", (Byte) VI_K_HOME}, // Cursor Key Home + {(Byte *) "OF", (Byte) VI_K_END}, // Cursor Key End + {(Byte *) "", (Byte) VI_K_UP}, // cursor key Up + {(Byte *) "", (Byte) VI_K_DOWN}, // cursor key Down + {(Byte *) "", (Byte) VI_K_RIGHT}, // Cursor Key Right + {(Byte *) "", (Byte) VI_K_LEFT}, // cursor key Left + {(Byte *) "", (Byte) VI_K_HOME}, // Cursor Key Home + {(Byte *) "", (Byte) VI_K_END}, // Cursor Key End + {(Byte *) "[2~", (Byte) VI_K_INSERT}, // Cursor Key Insert + {(Byte *) "[5~", (Byte) VI_K_PAGEUP}, // Cursor Key Page Up + {(Byte *) "[6~", (Byte) VI_K_PAGEDOWN}, // Cursor Key Page Down + {(Byte *) "OP", (Byte) VI_K_FUN1}, // Function Key F1 + {(Byte *) "OQ", (Byte) VI_K_FUN2}, // Function Key F2 + {(Byte *) "OR", (Byte) VI_K_FUN3}, // Function Key F3 + {(Byte *) "OS", (Byte) VI_K_FUN4}, // Function Key F4 + {(Byte *) "[15~", (Byte) VI_K_FUN5}, // Function Key F5 + {(Byte *) "[17~", (Byte) VI_K_FUN6}, // Function Key F6 + {(Byte *) "[18~", (Byte) VI_K_FUN7}, // Function Key F7 + {(Byte *) "[19~", (Byte) VI_K_FUN8}, // Function Key F8 + {(Byte *) "[20~", (Byte) VI_K_FUN9}, // Function Key F9 + {(Byte *) "[21~", (Byte) VI_K_FUN10}, // Function Key F10 + {(Byte *) "[23~", (Byte) VI_K_FUN11}, // Function Key F11 + {(Byte *) "[24~", (Byte) VI_K_FUN12}, // Function Key F12 + {(Byte *) "[11~", (Byte) VI_K_FUN1}, // Function Key F1 + {(Byte *) "[12~", (Byte) VI_K_FUN2}, // Function Key F2 + {(Byte *) "[13~", (Byte) VI_K_FUN3}, // Function Key F3 + {(Byte *) "[14~", (Byte) VI_K_FUN4}, // Function Key F4 + }; + +#define ESCCMDS_COUNT (sizeof(esccmds)/sizeof(struct esc_cmds)) + + (void) alarm(0); // turn alarm OFF while we wait for input + // get input from User- are there already input chars in Q? + bufsiz = strlen((char *) readbuffer); + if (bufsiz <= 0) { + ri0: + // the Q is empty, wait for a typed char + bufsiz = read(0, readbuffer, BUFSIZ - 1); + if (bufsiz < 0) { + if (errno == EINTR) + goto ri0; // interrupted sys call + if (errno == EBADF) + editing = 0; + if (errno == EFAULT) + editing = 0; + if (errno == EINVAL) + editing = 0; + if (errno == EIO) + editing = 0; + errno = 0; + bufsiz = 0; + } + readbuffer[bufsiz] = '\0'; + } + // return char if it is not part of ESC sequence + if (readbuffer[0] != 27) + goto ri1; + + // This is an ESC char. Is this Esc sequence? + // Could be bare Esc key. See if there are any + // more chars to read after the ESC. This would + // be a Function or Cursor Key sequence. + FD_ZERO(&rfds); + FD_SET(0, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 50000; // Wait 5/100 seconds- 1 Sec=1000000 + + // keep reading while there are input chars and room in buffer + while (select(1, &rfds, NULL, NULL, &tv) > 0 && bufsiz <= (BUFSIZ - 5)) { + // read the rest of the ESC string + i = read(0, (void *) (readbuffer + bufsiz), BUFSIZ - bufsiz); + if (i > 0) { + bufsiz += i; + readbuffer[bufsiz] = '\0'; // Terminate the string + } + } + // Maybe cursor or function key? + for (cmdindex = 0; cmdindex < ESCCMDS_COUNT; cmdindex++) { + cnt = strlen((char *) esccmds[cmdindex].seq); + i = strncmp((char *) esccmds[cmdindex].seq, (char *) readbuffer, cnt); + if (i == 0) { + // is a Cursor key- put derived value back into Q + readbuffer[0] = esccmds[cmdindex].val; + // squeeze out the ESC sequence + for (i = 1; i < cnt; i++) { + memmove(readbuffer + 1, readbuffer + 2, BUFSIZ - 2); + readbuffer[BUFSIZ - 1] = '\0'; + } + break; + } + } + ri1: + c = readbuffer[0]; + // remove one char from Q + memmove(readbuffer, readbuffer + 1, BUFSIZ - 1); + readbuffer[BUFSIZ - 1] = '\0'; + (void) alarm(3); // we are done waiting for input, turn alarm ON + return (c); +} + +//----- IO Routines -------------------------------------------- +static Byte get_one_char() +{ + static Byte c; + +#ifdef BB_FEATURE_VI_DOT_CMD + // ! adding2q && ioq == 0 read() + // ! adding2q && ioq != 0 *ioq + // adding2q *last_modifying_cmd= read() + if (!adding2q) { + // we are not adding to the q. + // but, we may be reading from a q + if (ioq == 0) { + // there is no current q, read from STDIN + c = readit(); // get the users input + } else { + // there is a queue to get chars from first + c = *ioq++; + if (c == '\0') { + // the end of the q, read from STDIN + free(ioq_start); + ioq_start = ioq = 0; + c = readit(); // get the users input + } + } + } else { + // adding STDIN chars to q + c = readit(); // get the users input + if (last_modifying_cmd != 0) { + int len = strlen((char *) last_modifying_cmd); + if (len + 1 >= BUFSIZ) { + psbs("last_modifying_cmd overrun"); + } else { + // add new char to q + last_modifying_cmd[len] = c; + } + + } + } +#else /* BB_FEATURE_VI_DOT_CMD */ + c = readit(); // get the users input +#endif /* BB_FEATURE_VI_DOT_CMD */ + return (c); // return the char, where ever it came from +} + +static Byte *get_input_line(Byte * prompt) // get input line- use "status line" +{ + Byte buf[BUFSIZ]; + Byte c; + int i; + static Byte *obufp = NULL; + + strcpy((char *) buf, (char *) prompt); + *status_buffer = '\0'; // clear the status buffer + place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen + clear_to_eol(); // clear the line + write(1, prompt, strlen((char *) prompt)); // write out the :, /, or ? prompt + + for (i = strlen((char *) buf); i < BUFSIZ;) { + c = get_one_char(); // read user input + if (c == '\n' || c == '\r' || c == 27) + break; // is this end of input + if (c == erase_char) { // user wants to erase prev char + i--; // backup to prev char + buf[i] = '\0'; // erase the char + buf[i + 1] = '\0'; // null terminate buffer + write(1, " ", 3); // erase char on screen + if (i <= 0) { // user backs up before b-o-l, exit + break; + } + } else { + buf[i] = c; // save char in buffer + buf[i + 1] = '\0'; // make sure buffer is null terminated + write(1, buf + i, 1); // echo the char back to user + i++; + } + } + refresh(FALSE); + if (obufp != NULL) + free(obufp); + obufp = (Byte *) strdup((char *) buf); + return (obufp); +} + +static int file_size(Byte * fn) // what is the byte size of "fn" +{ + struct stat st_buf; + int cnt, sr; + + if (fn == 0 || strlen(fn) <= 0) + return (-1); + cnt = -1; + sr = stat((char *) fn, &st_buf); // see if file exists + if (sr >= 0) { + cnt = (int) st_buf.st_size; + } + return (cnt); +} + +static int file_insert(Byte * fn, Byte * p, int size) +{ + int fd, cnt; + + cnt = -1; +#ifdef BB_FEATURE_VI_READONLY + readonly = FALSE; +#endif /* BB_FEATURE_VI_READONLY */ + if (fn == 0 || strlen((char*) fn) <= 0) { + psbs("No filename given"); + goto fi0; + } + if (size == 0) { + // OK- this is just a no-op + cnt = 0; + goto fi0; + } + if (size < 0) { + psbs("Trying to insert a negative number (%d) of characters", size); + goto fi0; + } + if (p < text || p > end) { + psbs("Trying to insert file outside of memory"); + goto fi0; + } + + // see if we can open the file +#ifdef BB_FEATURE_VI_READONLY + if (vi_readonly == TRUE) goto fi1; // do not try write-mode +#endif + fd = open((char *) fn, O_RDWR); // assume read & write + if (fd < 0) { + // could not open for writing- maybe file is read only +#ifdef BB_FEATURE_VI_READONLY + fi1: +#endif + fd = open((char *) fn, O_RDONLY); // try read-only + if (fd < 0) { + psbs("\"%s\" %s", fn, "could not open file"); + goto fi0; + } +#ifdef BB_FEATURE_VI_READONLY + // got the file- read-only + readonly = TRUE; +#endif /* BB_FEATURE_VI_READONLY */ + } + p = text_hole_make(p, size); + cnt = read(fd, p, size); + close(fd); + if (cnt < 0) { + cnt = -1; + p = text_hole_delete(p, p + size - 1); // un-do buffer insert + psbs("could not read file \"%s\"", fn); + } else if (cnt < size) { + // There was a partial read, shrink unused space text[] + p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert + psbs("could not read all of file \"%s\"", fn); + } + if (cnt >= size) + file_modified = TRUE; + fi0: + return (cnt); +} + +static int file_write(Byte * fn, Byte * first, Byte * last) +{ + int fd, cnt, charcnt; + + if (fn == 0) { + psbs("No current filename"); + return (-1); + } + charcnt = 0; + // FIXIT- use the correct umask() + fd = open((char *) fn, (O_WRONLY | O_CREAT | O_TRUNC), 0664); + if (fd < 0) + return (-1); + cnt = last - first + 1; + charcnt = write(fd, first, cnt); + if (charcnt == cnt) { + // good write + //file_modified= FALSE; // the file has not been modified + } else { + charcnt = 0; + } + close(fd); + return (charcnt); +} + +//----- Terminal Drawing --------------------------------------- +// The terminal is made up of 'rows' line of 'columns' columns. +// classicly this would be 24 x 80. +// screen coordinates +// 0,0 ... 0,79 +// 1,0 ... 1,79 +// . ... . +// . ... . +// 22,0 ... 22,79 +// 23,0 ... 23,79 status line +// + +//----- Move the cursor to row x col (count from 0, not 1) ------- +static void place_cursor(int row, int col, int opti) +{ + char cm1[BUFSIZ]; + char *cm; + int l; +#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR + char cm2[BUFSIZ]; + Byte *screenp; + // char cm3[BUFSIZ]; + int Rrow= last_row; +#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ + + memset(cm1, '\0', BUFSIZ - 1); // clear the buffer + + if (row < 0) row = 0; + if (row >= rows) row = rows - 1; + if (col < 0) col = 0; + if (col >= columns) col = columns - 1; + + //----- 1. Try the standard terminal ESC sequence + sprintf((char *) cm1, CMrc, row + 1, col + 1); + cm= cm1; + if (opti == FALSE) goto pc0; + +#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR + //----- find the minimum # of chars to move cursor ------------- + //----- 2. Try moving with discreet chars (Newline, [back]space, ...) + memset(cm2, '\0', BUFSIZ - 1); // clear the buffer + + // move to the correct row + while (row < Rrow) { + // the cursor has to move up + strcat(cm2, CMup); + Rrow--; + } + while (row > Rrow) { + // the cursor has to move down + strcat(cm2, CMdown); + Rrow++; + } + + // now move to the correct column + strcat(cm2, "\r"); // start at col 0 + // just send out orignal source char to get to correct place + screenp = &screen[row * columns]; // start of screen line + strncat(cm2, screenp, col); + + //----- 3. Try some other way of moving cursor + //--------------------------------------------- + + // pick the shortest cursor motion to send out + cm= cm1; + if (strlen(cm2) < strlen(cm)) { + cm= cm2; + } /* else if (strlen(cm3) < strlen(cm)) { + cm= cm3; + } */ +#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ + pc0: + l= strlen(cm); + if (l) write(1, cm, l); // move the cursor +} + +//----- Erase from cursor to end of line ----------------------- +static void clear_to_eol() +{ + write(1, Ceol, strlen(Ceol)); // Erase from cursor to end of line +} + +//----- Erase from cursor to end of screen ----------------------- +static void clear_to_eos() +{ + write(1, Ceos, strlen(Ceos)); // Erase from cursor to end of screen +} + +//----- Start standout mode ------------------------------------ +static void standout_start() // send "start reverse video" sequence +{ + write(1, SOs, strlen(SOs)); // Start reverse video mode +} + +//----- End standout mode -------------------------------------- +static void standout_end() // send "end reverse video" sequence +{ + write(1, SOn, strlen(SOn)); // End reverse video mode +} + +//----- Flash the screen -------------------------------------- +static void flash(int h) +{ + standout_start(); // send "start reverse video" sequence + redraw(TRUE); + (void) mysleep(h); + standout_end(); // send "end reverse video" sequence + redraw(TRUE); +} + +static void beep() +{ + write(1, bell, strlen(bell)); // send out a bell character +} + +static void indicate_error(char c) +{ +#ifdef BB_FEATURE_VI_CRASHME + if (crashme > 0) + return; // generate a random command +#endif /* BB_FEATURE_VI_CRASHME */ + if (err_method == 0) { + beep(); + } else { + flash(10); + } +} + +//----- Screen[] Routines -------------------------------------- +//----- Erase the Screen[] memory ------------------------------ +static void screen_erase() +{ + memset(screen, ' ', screensize); // clear new screen +} + +//----- Draw the status line at bottom of the screen ------------- +static void show_status_line(void) +{ + static int last_cksum; + int l, cnt, cksum; + + cnt = strlen((char *) status_buffer); + for (cksum= l= 0; l < cnt; l++) { cksum += (int)(status_buffer[l]); } + // don't write the status line unless it changes + if (cnt > 0 && last_cksum != cksum) { + last_cksum= cksum; // remember if we have seen this line + place_cursor(rows - 1, 0, FALSE); // put cursor on status line + write(1, status_buffer, cnt); + clear_to_eol(); + place_cursor(crow, ccol, FALSE); // put cursor back in correct place + } +} + +//----- format the status buffer, the bottom line of screen ------ +// print status buffer, with STANDOUT mode +static void psbs(char *format, ...) +{ + va_list args; + + va_start(args, format); + strcpy((char *) status_buffer, SOs); // Terminal standout mode on + vsprintf((char *) status_buffer + strlen((char *) status_buffer), format, + args); + strcat((char *) status_buffer, SOn); // Terminal standout mode off + va_end(args); + + return; +} + +// print status buffer +static void psb(char *format, ...) +{ + va_list args; + + va_start(args, format); + vsprintf((char *) status_buffer, format, args); + va_end(args); + return; +} + +static void ni(Byte * s) // display messages +{ + Byte buf[BUFSIZ]; + + print_literal(buf, s); + psbs("\'%s\' is not implemented", buf); +} + +static void edit_status(void) // show file status on status line +{ + int cur, tot, percent; + + cur = count_lines(text, dot); + tot = count_lines(text, end - 1); + // current line percent + // ------------- ~~ ---------- + // total lines 100 + if (tot > 0) { + percent = (100 * cur) / tot; + } else { + cur = tot = 0; + percent = 100; + } + psb("\"%s\"" +#ifdef BB_FEATURE_VI_READONLY + "%s" +#endif /* BB_FEATURE_VI_READONLY */ + "%s line %d of %d --%d%%--", + (cfn != 0 ? (char *) cfn : "No file"), +#ifdef BB_FEATURE_VI_READONLY + ((vi_readonly == TRUE || readonly == TRUE) ? " [Read only]" : ""), +#endif /* BB_FEATURE_VI_READONLY */ + (file_modified == TRUE ? " [modified]" : ""), + cur, tot, percent); +} + +//----- Force refresh of all Lines ----------------------------- +static void redraw(int full_screen) +{ + place_cursor(0, 0, FALSE); // put cursor in correct place + clear_to_eos(); // tel terminal to erase display + screen_erase(); // erase the internal screen buffer + refresh(full_screen); // this will redraw the entire display +} + +//----- Format a text[] line into a buffer --------------------- +static void format_line(Byte *dest, Byte *src, int li) +{ + int co; + Byte c; + + for (co= 0; co < MAX_SCR_COLS; co++) { + c= ' '; // assume blank + if (li > 0 && co == 0) { + c = '~'; // not first line, assume Tilde + } + // are there chars in text[] and have we gone past the end + if (text < end && src < end) { + c = *src++; + } + if (c == '\n') + break; + if (c < ' ' || c > '~') { + if (c == '\t') { + c = ' '; + // co % 8 != 7 + for (; (co % tabstop) != (tabstop - 1); co++) { + dest[co] = c; + } + } else { + dest[co++] = '^'; + c |= '@'; // make it visible + c &= 0x7f; // get rid of hi bit + } + } + // the co++ is done here so that the column will + // not be overwritten when we blank-out the rest of line + dest[co] = c; + if (src >= end) + break; + } +} + +//----- Refresh the changed screen lines ----------------------- +// Copy the source line from text[] into the buffer and note +// if the current screenline is different from the new buffer. +// If they differ then that line needs redrawing on the terminal. +// +static void refresh(int full_screen) +{ + static int old_offset; + int li, changed; + Byte buf[MAX_SCR_COLS]; + Byte *tp, *sp; // pointer into text[] and screen[] +#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR + int last_li= -2; // last line that changed- for optimizing cursor movement +#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ + +#ifdef BB_FEATURE_VI_WIN_RESIZE + window_size_get(0); +#endif /* BB_FEATURE_VI_WIN_RESIZE */ + sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot") + tp = screenbegin; // index into text[] of top line + + // compare text[] to screen[] and mark screen[] lines that need updating + for (li = 0; li < rows - 1; li++) { + int cs, ce; // column start & end + memset(buf, ' ', MAX_SCR_COLS); // blank-out the buffer + buf[MAX_SCR_COLS-1] = 0; // NULL terminate the buffer + // format current text line into buf + format_line(buf, tp, li); + + // skip to the end of the current text[] line + while (tp < end && *tp++ != '\n') /*no-op*/ ; + + // see if there are any changes between vitual screen and buf + changed = FALSE; // assume no change + cs= 0; + ce= columns-1; + sp = &screen[li * columns]; // start of screen line + if (full_screen == TRUE) { + // force re-draw of every single column from 0 - columns-1 + goto re0; + } + // compare newly formatted buffer with virtual screen + // look forward for first difference between buf and screen + for ( ; cs <= ce; cs++) { + if (buf[cs + offset] != sp[cs]) { + changed = TRUE; // mark for redraw + break; + } + } + + // look backward for last difference between buf and screen + for ( ; ce >= cs; ce--) { + if (buf[ce + offset] != sp[ce]) { + changed = TRUE; // mark for redraw + break; + } + } + // now, cs is index of first diff, and ce is index of last diff + + // if horz offset has changed, force a redraw + if (offset != old_offset) { + re0: + changed = TRUE; + } + + // make a sanity check of columns indexes + if (cs < 0) cs= 0; + if (ce > columns-1) ce= columns-1; + if (cs > ce) { cs= 0; ce= columns-1; } + // is there a change between vitual screen and buf + if (changed == TRUE) { + // copy changed part of buffer to virtual screen + memmove(sp+cs, buf+(cs+offset), ce-cs+1); + + // move cursor to column of first change + if (offset != old_offset) { + // opti_cur_move is still too stupid + // to handle offsets correctly + place_cursor(li, cs, FALSE); + } else { +#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR + // if this just the next line + // try to optimize cursor movement + // otherwise, use standard ESC sequence + place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE); + last_li= li; +#else /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ + place_cursor(li, cs, FALSE); // use standard ESC sequence +#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ + } + + // write line out to terminal + write(1, sp+cs, ce-cs+1); +#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR + last_row = li; +#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ + } + } + +#ifdef BB_FEATURE_VI_OPTIMIZE_CURSOR + place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE); + last_row = crow; +#else + place_cursor(crow, ccol, FALSE); +#endif /* BB_FEATURE_VI_OPTIMIZE_CURSOR */ + + if (offset != old_offset) + old_offset = offset; +} diff --git a/watchdog.c b/watchdog.c new file mode 100644 index 000000000..f0b0ebd0e --- /dev/null +++ b/watchdog.c @@ -0,0 +1,49 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini watchdog implementation for busybox + * + * Copyright (C) 2000 spoon . + * + * 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 + * + */ + +/* getopt not needed */ + +#include +#include +#include +#include +#include "busybox.h" + +extern int watchdog_main(int argc, char **argv) +{ + int fd; + + if (argc != 2) { + show_usage(); + } + + if ((fd=open(argv[1], O_WRONLY)) == -1) { + perror_msg_and_die(argv[1]); + } + + while (1) { + sleep(30); + write(fd, "\0", 1); + } + + return EXIT_FAILURE; +} diff --git a/wc.c b/wc.c new file mode 100644 index 000000000..fb81c0a8f --- /dev/null +++ b/wc.c @@ -0,0 +1,169 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini wc implementation for busybox + * + * 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 + * + */ + +#include +#include +#include +#include +#include "busybox.h" + +enum print_e { + print_lines = 1, + print_words = 2, + print_chars = 4, + print_length = 8 +}; + +static unsigned int total_lines = 0; +static unsigned int total_words = 0; +static unsigned int total_chars = 0; +static unsigned int max_length = 0; +static char print_type = 0; + +static void print_counts(const unsigned int lines, const unsigned int words, + const unsigned int chars, const unsigned int length, const char *name) +{ + if (print_type & print_lines) { + printf("%7d ", lines); + } + if (print_type & print_words) { + printf("%7d ", words); + } + if (print_type & print_chars) { + printf("%7d ", chars); + } + if (print_type & print_length) { + printf("%7d ", length); + } + if (*name) { + printf("%s", name); + } + putchar('\n'); +} + +static void wc_file(FILE * file, const char *name) +{ + unsigned int lines = 0; + unsigned int words = 0; + unsigned int chars = 0; + unsigned int length = 0; + unsigned int linepos = 0; + char in_word = 0; + int c; + + while ((c = getc(file)) != EOF) { + chars++; + switch (c) { + case '\n': + lines++; + case '\r': + case '\f': + if (linepos > length) + length = linepos; + linepos = 0; + goto word_separator; + case '\t': + linepos += 8 - (linepos % 8); + goto word_separator; + case ' ': + linepos++; + case '\v': +word_separator: + if (in_word) { + in_word = 0; + words++; + } + break; + default: + linepos++; + in_word = 1; + break; + } + } + if (linepos > length) { + length = linepos; + } + if (in_word) { + words++; + } + print_counts(lines, words, chars, length, name); + total_lines += lines; + total_words += words; + total_chars += chars; + if (length > max_length) { + max_length = length; + } +} + +int wc_main(int argc, char **argv) +{ + int opt; + + while ((opt = getopt(argc, argv, "clLw")) > 0) { + switch (opt) { + case 'c': + print_type |= print_chars; + break; + case 'l': + print_type |= print_lines; + break; + case 'L': + print_type |= print_length; + break; + case 'w': + print_type |= print_words; + break; + default: + show_usage(); + } + } + + if (print_type == 0) { + print_type = print_lines | print_words | print_chars; + } + + if (argv[optind] == NULL || strcmp(argv[optind], "-") == 0) { + wc_file(stdin, ""); + } else { + unsigned short num_files_counted = 0; + while (optind < argc) { + if (print_type == print_chars) { + struct stat statbuf; + stat(argv[optind], &statbuf); + print_counts(0, 0, statbuf.st_size, 0, argv[optind]); + total_chars += statbuf.st_size; + } else { + FILE *file; + file = xfopen(argv[optind], "r"); + wc_file(file, argv[optind]); + fclose(file); + } + optind++; + num_files_counted++; + } + if (num_files_counted > 1) { + print_counts(total_lines, total_words, total_chars, max_length, "total"); + } + } + + return(EXIT_SUCCESS); +} diff --git a/wget.c b/wget.c new file mode 100644 index 000000000..ef85b62fb --- /dev/null +++ b/wget.c @@ -0,0 +1,847 @@ +/* vi: set sw=4 ts=4: */ +/* + * wget - retrieve a file using HTTP or FTP + * + * Chip Rosenthal Covad Communications + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include + +#include "busybox.h" + +/* Stupid libc5 doesn't define this... */ +#ifndef timersub +#define timersub(a, b, result) \ + do { \ + (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ + (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ + if ((result)->tv_usec < 0) { \ + --(result)->tv_sec; \ + (result)->tv_usec += 1000000; \ + } \ + } while (0) +#endif + +struct host_info { + char *host; + int port; + char *path; + int is_ftp; + char *user; +}; + +static void parse_url(char *url, struct host_info *h); +static struct sockaddr_in *lookup_host(char *host); +static FILE *open_socket(struct sockaddr_in *s_in, int port); +static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc); +static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf); + +/* Globals (can be accessed from signal handlers */ +static off_t filesize = 0; /* content-length of the file */ +static int chunked = 0; /* chunked transfer encoding */ +#ifdef BB_FEATURE_WGET_STATUSBAR +static void progressmeter(int flag); +static char *curfile; /* Name of current file being transferred. */ +static struct timeval start; /* Time a transfer started. */ +static volatile unsigned long statbytes = 0; /* Number of bytes transferred so far. */ +/* For progressmeter() -- number of seconds before xfer considered "stalled" */ +static const int STALLTIME = 5; +#endif + +static void close_and_delete_outfile(FILE* output, char *fname_out, int do_continue) +{ + if (output != stdout && do_continue==0) { + fclose(output); + unlink(fname_out); + } +} + +/* Read NMEMB elements of SIZE bytes into PTR from STREAM. Returns the + * number of elements read, and a short count if an eof or non-interrupt + * error is encountered. */ +static size_t safe_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + size_t ret = 0; + + do { + clearerr(stream); + ret += fread((char *)ptr + (ret * size), size, nmemb - ret, stream); + } while (ret < nmemb && ferror(stream) && errno == EINTR); + + return ret; +} + +/* Write NMEMB elements of SIZE bytes from PTR to STREAM. Returns the + * number of elements written, and a short count if an eof or non-interrupt + * error is encountered. */ +static size_t safe_fwrite(void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + size_t ret = 0; + + do { + clearerr(stream); + ret += fwrite((char *)ptr + (ret * size), size, nmemb - ret, stream); + } while (ret < nmemb && ferror(stream) && errno == EINTR); + + return ret; +} + +/* Read a line or SIZE - 1 bytes into S, whichever is less, from STREAM. + * Returns S, or NULL if an eof or non-interrupt error is encountered. */ +static char *safe_fgets(char *s, int size, FILE *stream) +{ + char *ret; + + do { + clearerr(stream); + ret = fgets(s, size, stream); + } while (ret == NULL && ferror(stream) && errno == EINTR); + + return ret; +} + +#define close_delete_and_die(s...) { \ + close_and_delete_outfile(output, fname_out, do_continue); \ + error_msg_and_die(s); } + + +#ifdef BB_FEATURE_WGET_AUTHENTICATION +/* + * Base64-encode character string + * oops... isn't something similar in uuencode.c? + * It would be better to use already existing code + */ +char *base64enc(char *p, char *buf, int len) { + + char al[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + char *s = buf; + + while(*p) { + if (s >= buf+len-4) + error_msg_and_die("buffer overflow"); + *(s++) = al[(*p >> 2) & 0x3F]; + *(s++) = al[((*p << 4) & 0x30) | ((*(p+1) >> 4) & 0x0F)]; + *s = *(s+1) = '='; + *(s+2) = 0; + if (! *(++p)) break; + *(s++) = al[((*p << 2) & 0x3C) | ((*(p+1) >> 6) & 0x03)]; + if (! *(++p)) break; + *(s++) = al[*(p++) & 0x3F]; + } + + return buf; +} +#endif + +int wget_main(int argc, char **argv) +{ + int n, try=5, status; + int port; + char *proxy; + char *dir_prefix=NULL; + char *s, buf[512]; + struct stat sbuf; + char extra_headers[1024]; + char *extra_headers_ptr = extra_headers; + int extra_headers_left = sizeof(extra_headers); + int which_long_opt = 0, option_index = -1; + struct host_info server, target; + struct sockaddr_in *s_in; + + FILE *sfp = NULL; /* socket to web/ftp server */ + FILE *dfp = NULL; /* socket to ftp server (data) */ + char *fname_out = NULL; /* where to direct output (-O) */ + int do_continue = 0; /* continue a prev transfer (-c) */ + long beg_range = 0L; /* range at which continue begins */ + int got_clen = 0; /* got content-length: from server */ + FILE *output; /* socket to web server */ + int quiet_flag = FALSE; /* Be verry, verry quiet... */ + +#define LONG_HEADER 1 + struct option long_options[] = { + { "continue", 0, NULL, 'c' }, + { "quiet", 0, NULL, 'q' }, + { "output-document", 1, NULL, 'O' }, + { "header", 1, &which_long_opt, LONG_HEADER }, + { 0, 0, 0, 0 } + }; + /* + * Crack command line. + */ + while ((n = getopt_long(argc, argv, "cqO:P:", long_options, &option_index)) != EOF) { + switch (n) { + case 'c': + ++do_continue; + break; + case 'P': + dir_prefix = optarg; + break; + case 'q': + quiet_flag = TRUE; + break; + case 'O': + /* can't set fname_out to NULL if outputting to stdout, because + * this gets interpreted as the auto-gen output filename + * case below - tausq@debian.org + */ + fname_out = optarg; + break; + case 0: + switch (which_long_opt) { + case LONG_HEADER: { + int arglen = strlen(optarg); + if(extra_headers_left - arglen - 2 <= 0) + error_msg_and_die("extra_headers buffer too small(need %i)", extra_headers_left - arglen); + strcpy(extra_headers_ptr, optarg); + extra_headers_ptr += arglen; + extra_headers_left -= ( arglen + 2 ); + *extra_headers_ptr++ = '\r'; + *extra_headers_ptr++ = '\n'; + *(extra_headers_ptr + 1) = 0; + break; + } + } + break; + default: + show_usage(); + } + } + + if (argc - optind != 1) + show_usage(); + + parse_url(argv[optind], &target); + server.host = target.host; + server.port = target.port; + + /* + * Use the proxy if necessary. + */ + proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy"); + if (proxy) + parse_url(xstrdup(proxy), &server); + + /* Guess an output filename */ + if (!fname_out) { + fname_out = +#ifdef BB_FEATURE_WGET_STATUSBAR + curfile = +#endif + get_last_path_component(target.path); + if (fname_out==NULL || strlen(fname_out)<1) { + fname_out = +#ifdef BB_FEATURE_WGET_STATUSBAR + curfile = +#endif + "index.html"; + } + if (dir_prefix != NULL) + fname_out = concat_path_file(dir_prefix, fname_out); +#ifdef BB_FEATURE_WGET_STATUSBAR + } else { + curfile = get_last_path_component(fname_out); +#endif + } + if (do_continue && !fname_out) + error_msg_and_die("cannot specify continue (-c) without a filename (-O)"); + + + /* + * Open the output file stream. + */ + if (strcmp(fname_out, "-") == 0) { + output = stdout; + quiet_flag = TRUE; + } else { + output = xfopen(fname_out, (do_continue ? "a" : "w")); + } + + /* + * Determine where to start transfer. + */ + if (do_continue) { + if (fstat(fileno(output), &sbuf) < 0) + perror_msg_and_die("fstat()"); + if (sbuf.st_size > 0) + beg_range = sbuf.st_size; + else + do_continue = 0; + } + + s_in = lookup_host (server.host); + + if (proxy || !target.is_ftp) { + /* + * HTTP session + */ + do { + if (! --try) + close_delete_and_die("too many redirections"); + + /* + * Open socket to http server + */ + if (sfp) fclose(sfp); + sfp = open_socket(s_in, server.port); + + /* + * Send HTTP request. + */ + if (proxy) { + fprintf(sfp, "GET %stp://%s:%d/%s HTTP/1.1\r\n", + target.is_ftp ? "f" : "ht", target.host, + target.port, target.path); + } else { + fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); + } + + fprintf(sfp, "Host: %s\r\nUser-Agent: Wget\r\n", target.host); + +#ifdef BB_FEATURE_WGET_AUTHENTICATION + if (target.user) { + fprintf(sfp, "Authorization: Basic %s\r\n", + base64enc(target.user, buf, sizeof(buf))); + } + if (proxy && server.user) { + fprintf(sfp, "Proxy-Authorization: Basic %s\r\n", + base64enc(server.user, buf, sizeof(buf))); + } +#endif + + if (do_continue) + fprintf(sfp, "Range: bytes=%ld-\r\n", beg_range); + if(extra_headers_left < sizeof(extra_headers)) + fputs(extra_headers,sfp); + fprintf(sfp,"Connection: close\r\n\r\n"); + + /* + * Retrieve HTTP response line and check for "200" status code. + */ +read_response: if (fgets(buf, sizeof(buf), sfp) == NULL) + close_delete_and_die("no response from server"); + + for (s = buf ; *s != '\0' && !isspace(*s) ; ++s) + ; + for ( ; isspace(*s) ; ++s) + ; + switch (status = atoi(s)) { + case 0: + case 100: + while (gethdr(buf, sizeof(buf), sfp, &n) != NULL); + goto read_response; + case 200: + if (do_continue && output != stdout) + output = freopen(fname_out, "w", output); + do_continue = 0; + break; + case 300: /* redirection */ + case 301: + case 302: + case 303: + break; + case 206: + if (do_continue) + break; + /*FALLTHRU*/ + default: + chomp(buf); + close_delete_and_die("server returned error %d: %s", atoi(s), buf); + } + + /* + * Retrieve HTTP headers. + */ + while ((s = gethdr(buf, sizeof(buf), sfp, &n)) != NULL) { + if (strcasecmp(buf, "content-length") == 0) { + filesize = atol(s); + got_clen = 1; + continue; + } + if (strcasecmp(buf, "transfer-encoding") == 0) { + if (strcasecmp(s, "chunked") == 0) { + chunked = got_clen = 1; + } else { + close_delete_and_die("server wants to do %s transfer encoding", s); + } + } + if (strcasecmp(buf, "location") == 0) { + if (s[0] == '/') + target.path = xstrdup(s+1); + else { + parse_url(xstrdup(s), &target); + if (!proxy) { + server.host = target.host; + server.port = target.port; + } + } + } + } + } while(status >= 300); + + dfp = sfp; + } + else + { + /* + * FTP session + */ + if (! target.user) + target.user = xstrdup("anonymous:busybox@"); + + sfp = open_socket(s_in, server.port); + if (ftpcmd(NULL, NULL, sfp, buf) != 220) + close_delete_and_die("%s", buf+4); + + /* + * Splitting username:password pair, + * trying to log in + */ + s = strchr(target.user, ':'); + if (s) + *(s++) = '\0'; + switch(ftpcmd("USER ", target.user, sfp, buf)) { + case 230: + break; + case 331: + if (ftpcmd("PASS ", s, sfp, buf) == 230) + break; + /* FALLTHRU (failed login) */ + default: + close_delete_and_die("ftp login: %s", buf+4); + } + + ftpcmd("CDUP", NULL, sfp, buf); + ftpcmd("TYPE I", NULL, sfp, buf); + + /* + * Querying file size + */ + if (ftpcmd("SIZE /", target.path, sfp, buf) == 213) { + filesize = atol(buf+4); + got_clen = 1; + } + + /* + * Entering passive mode + */ + if (ftpcmd("PASV", NULL, sfp, buf) != 227) + close_delete_and_die("PASV: %s", buf+4); + s = strrchr(buf, ','); + *s = 0; + port = atoi(s+1); + s = strrchr(buf, ','); + port += atoi(s+1) * 256; + dfp = open_socket(s_in, port); + + if (do_continue) { + sprintf(buf, "REST %ld", beg_range); + if (ftpcmd(buf, NULL, sfp, buf) != 350) { + if (output != stdout) + output = freopen(fname_out, "w", output); + do_continue = 0; + } else + filesize -= beg_range; + } + + if (ftpcmd("RETR /", target.path, sfp, buf) > 150) + close_delete_and_die("RETR: %s", buf+4); + + } + + + /* + * Retrieve file + */ + if (chunked) { + fgets(buf, sizeof(buf), dfp); + filesize = strtol(buf, (char **) NULL, 16); + } +#ifdef BB_FEATURE_WGET_STATUSBAR + if (quiet_flag==FALSE) + progressmeter(-1); +#endif + do { + while ((filesize > 0 || !got_clen) && (n = safe_fread(buf, 1, chunked ? (filesize > sizeof(buf) ? sizeof(buf) : filesize) : sizeof(buf), dfp)) > 0) { + if (safe_fwrite(buf, 1, n, output) != n) + perror_msg_and_die("fwrite"); +#ifdef BB_FEATURE_WGET_STATUSBAR + statbytes+=n; +#endif + if (got_clen) + filesize -= n; + } + + if (chunked) { + safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */ + safe_fgets(buf, sizeof(buf), dfp); + filesize = strtol(buf, (char **) NULL, 16); + if (filesize==0) chunked = 0; /* all done! */ + } + + if (n == 0 && ferror(dfp)) + perror_msg_and_die("network read error"); + } while (chunked); +#ifdef BB_FEATURE_WGET_STATUSBAR + if (quiet_flag==FALSE) + progressmeter(1); +#endif + if (!proxy && target.is_ftp) { + fclose(dfp); + if (ftpcmd(NULL, NULL, sfp, buf) != 226) + error_msg_and_die("ftp error: %s", buf+4); + ftpcmd("QUIT", NULL, sfp, buf); + } + exit(EXIT_SUCCESS); +} + + +void parse_url(char *url, struct host_info *h) +{ + char *cp, *sp, *up; + + if (strncmp(url, "http://", 7) == 0) { + h->port = 80; + h->host = url + 7; + h->is_ftp = 0; + } else if (strncmp(url, "ftp://", 6) == 0) { + h->port = 21; + h->host = url + 6; + h->is_ftp = 1; + } else + error_msg_and_die("not an http or ftp url: %s", url); + + sp = strchr(h->host, '/'); + if (sp != NULL) { + *sp++ = '\0'; + h->path = sp; + } else + h->path = xstrdup(""); + + up = strrchr(h->host, '@'); + if (up != NULL) { + h->user = h->host; + *up++ = '\0'; + h->host = up; + } else + h->user = NULL; + + cp = strchr(h->host, ':'); + if (cp != NULL) { + *cp++ = '\0'; + h->port = atoi(cp); + } + +} + + +static struct sockaddr_in *lookup_host(char *host) +{ + static struct sockaddr_in s_in; + struct hostent *hp; + + memset(&s_in, 0, sizeof(s_in)); + s_in.sin_family = AF_INET; + hp = xgethostbyname(host); + memcpy(&s_in.sin_addr, hp->h_addr_list[0], hp->h_length); + + return &s_in; +} + + +FILE *open_socket(struct sockaddr_in *s_in, int port) +{ + int fd; + FILE *fp; + + s_in->sin_port = htons(port); + + /* + * Get the server onto a stdio stream. + */ + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + perror_msg_and_die("socket()"); + if (connect(fd, (struct sockaddr *) s_in, sizeof(*s_in)) < 0) + perror_msg_and_die("connect()"); + if ((fp = fdopen(fd, "r+")) == NULL) + perror_msg_and_die("fdopen()"); + + return fp; +} + + +char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc) +{ + char *s, *hdrval; + int c; + + *istrunc = 0; + + /* retrieve header line */ + if (fgets(buf, bufsiz, fp) == NULL) + return NULL; + + /* see if we are at the end of the headers */ + for (s = buf ; *s == '\r' ; ++s) + ; + if (s[0] == '\n') + return NULL; + + /* convert the header name to lower case */ + for (s = buf ; isalnum(*s) || *s == '-' ; ++s) + *s = tolower(*s); + + /* verify we are at the end of the header name */ + if (*s != ':') + error_msg_and_die("bad header line: %s", buf); + + /* locate the start of the header value */ + for (*s++ = '\0' ; *s == ' ' || *s == '\t' ; ++s) + ; + hdrval = s; + + /* locate the end of header */ + while (*s != '\0' && *s != '\r' && *s != '\n') + ++s; + + /* end of header found */ + if (*s != '\0') { + *s = '\0'; + return hdrval; + } + + /* Rats! The buffer isn't big enough to hold the entire header value. */ + while (c = getc(fp), c != EOF && c != '\n') + ; + *istrunc = 1; + return hdrval; +} + +static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf) +{ + char *p; + + if (s1) { + if (!s2) s2=""; + fprintf(fp, "%s%s\n", s1, s2); + fflush(fp); + } + + do { + p = fgets(buf, 510, fp); + if (!p) + perror_msg_and_die("fgets()"); + } while (! isdigit(buf[0]) || buf[3] != ' '); + + return atoi(buf); +} + +#ifdef BB_FEATURE_WGET_STATUSBAR +/* Stuff below is from BSD rcp util.c, as added to openshh. + * Original copyright notice is retained at the end of this file. + * + */ + + +static int +getttywidth(void) +{ + struct winsize winsize; + + if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1) + return (winsize.ws_col ? winsize.ws_col : 80); + else + return (80); +} + +static void +updateprogressmeter(int ignore) +{ + int save_errno = errno; + + progressmeter(0); + errno = save_errno; +} + +static void +alarmtimer(int wait) +{ + struct itimerval itv; + + itv.it_value.tv_sec = wait; + itv.it_value.tv_usec = 0; + itv.it_interval = itv.it_value; + setitimer(ITIMER_REAL, &itv, NULL); +} + + +static void +progressmeter(int flag) +{ + static const char prefixes[] = " KMGTP"; + static struct timeval lastupdate; + static off_t lastsize, totalsize; + struct timeval now, td, wait; + off_t cursize, abbrevsize; + double elapsed; + int ratio, barlength, i, remaining; + char buf[256]; + + if (flag == -1) { + (void) gettimeofday(&start, (struct timezone *) 0); + lastupdate = start; + lastsize = 0; + totalsize = filesize; /* as filesize changes.. */ + } + + (void) gettimeofday(&now, (struct timezone *) 0); + cursize = statbytes; + if (totalsize != 0 && !chunked) { + ratio = 100.0 * cursize / totalsize; + ratio = MAX(ratio, 0); + ratio = MIN(ratio, 100); + } else + ratio = 100; + + snprintf(buf, sizeof(buf), "\r%-20.20s %3d%% ", curfile, ratio); + + barlength = getttywidth() - 51; + if (barlength > 0) { + i = barlength * ratio / 100; + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + "|%.*s%*s|", i, + "*****************************************************************************" + "*****************************************************************************", + barlength - i, ""); + } + i = 0; + abbrevsize = cursize; + while (abbrevsize >= 100000 && i < sizeof(prefixes)) { + i++; + abbrevsize >>= 10; + } + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5d %c%c ", + (int) abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' : + 'B'); + + timersub(&now, &lastupdate, &wait); + if (cursize > lastsize) { + lastupdate = now; + lastsize = cursize; + if (wait.tv_sec >= STALLTIME) { + start.tv_sec += wait.tv_sec; + start.tv_usec += wait.tv_usec; + } + wait.tv_sec = 0; + } + timersub(&now, &start, &td); + elapsed = td.tv_sec + (td.tv_usec / 1000000.0); + + if (wait.tv_sec >= STALLTIME) { + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + " - stalled -"); + } else if (statbytes <= 0 || elapsed <= 0.0 || cursize > totalsize || chunked) { + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + " --:-- ETA"); + } else { + remaining = (int) (totalsize / (statbytes / elapsed) - elapsed); + i = remaining / 3600; + if (i) + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + "%2d:", i); + else + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + " "); + i = remaining % 3600; + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + "%02d:%02d ETA", i / 60, i % 60); + } + write(fileno(stderr), buf, strlen(buf)); + + if (flag == -1) { + struct sigaction sa; + sa.sa_handler = updateprogressmeter; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction(SIGALRM, &sa, NULL); + alarmtimer(1); + } else if (flag == 1) { + alarmtimer(0); + statbytes = 0; + putc('\n', stderr); + } +} +#endif + +/* Original copyright notice which applies to the BB_FEATURE_WGET_STATUSBAR stuff, + * much of which was blatently stolen from openssh. */ + +/*- + * Copyright (c) 1992, 1993 + * The 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. + * + * $Id: wget.c,v 1.48 2002/04/27 07:40:00 andersen Exp $ + */ + + + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ + + + diff --git a/which.c b/which.c new file mode 100644 index 000000000..365c83bcd --- /dev/null +++ b/which.c @@ -0,0 +1,98 @@ +/* vi: set sw=4 ts=4: */ +/* + * Which 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 + * + */ + +/* getopt not needed */ +#include +#include +#include +#include "busybox.h" + +static int file_exists(char *file) +{ + struct stat filestat; + + if (stat(file, &filestat) == 0 && filestat.st_mode & S_IXUSR) + return 1; + else + return 0; +} + +extern int which_main(int argc, char **argv) +{ + char *path_list, *path_n; + int i, count=1, found, status = EXIT_SUCCESS; + + if (argc <= 1 || **(argv + 1) == '-') + show_usage(); + argc--; + + path_list = getenv("PATH"); + if (path_list != NULL) { + for(i=strlen(path_list); i > 0; i--) + if (path_list[i]==':') { + path_list[i]=0; + count++; + } + } else { + path_list = "/bin\0/sbin\0/usr/bin\0/usr/sbin\0/usr/local/bin"; + count = 5; + } + + while(argc-- > 0) { + char *buf; + path_n = path_list; + argv++; + found = 0; + + /* + * Check if we were given the full path, first. + * Otherwise see if the file exists in our $PATH. + */ + buf = *argv; + if (file_exists(buf)) { + puts(buf); + found = 1; + } else { + for (i = 0; i < count; i++) { + buf = concat_path_file(path_n, *argv); + if (file_exists(buf)) { + puts(buf); + found = 1; + break; + } + free(buf); + path_n += (strlen(path_n) + 1); + } + } + if (!found) + status = EXIT_FAILURE; + } + return status; +} + +/* +Local Variables: +c-file-style: "linux" +c-basic-offset: 4 +tab-width: 4 +End: +*/ diff --git a/whoami.c b/whoami.c new file mode 100644 index 000000000..c3b1140e6 --- /dev/null +++ b/whoami.c @@ -0,0 +1,44 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini whoami implementation for busybox + * + * 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 + * + */ + +/* getopt not needed */ + +#include +#include +#include +#include "busybox.h" + +extern int whoami_main(int argc, char **argv) +{ + char user[9]; + uid_t uid = geteuid(); + + if (argc > 1) + show_usage(); + + my_getpwuid(user, uid); + if (*user) { + puts(user); + return EXIT_SUCCESS; + } + error_msg_and_die("cannot find username for UID %u", (unsigned) uid); +} diff --git a/xargs.c b/xargs.c new file mode 100644 index 000000000..a89a799a2 --- /dev/null +++ b/xargs.c @@ -0,0 +1,110 @@ +/* + * Mini xargs implementation for busybox + * + * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen + * Copyright (C) 1999,2000,2001 by Erik Andersen + * Remixed 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 + * + */ + +#include +#include +#include +#include "busybox.h" + +int xargs_main(int argc, char **argv) +{ + char *cmd_to_be_executed; + char *file_to_act_on; + int i; + int len = 0; + + /* + * No options are supported in this version of xargs; no getopt. + * + * Re: The missing -t flag: Most programs that produce output also print + * the filename, so xargs doesn't really need to do it again. Supporting + * the -t flag =greatly= bloats up the size of this app and the memory it + * uses because you have to buffer all the input file strings in memory. If + * you really want to see the filenames that xargs will act on, just run it + * once with no args and xargs will echo the filename. Simple. + */ + + /* Store the command to be executed (taken from the command line) */ + if (argc == 1) { + /* default behavior is to echo all the filenames */ + argv[0] = "/bin/echo"; + len++; /* space for trailing ' ' */ + len++; /* space for trailing '\0' */ + } else { + argv++; + len = argc; /* arg = count for ' ' + trailing '\0' */ + argc--; + } + /* concatenate all the arguments passed to xargs together */ + for (i = 0; i < argc; i++) + len += strlen(argv[i]); + cmd_to_be_executed = xmalloc (len); + for (i = len = 0; i < argc; i++) { + len += sprintf(cmd_to_be_executed + len, "%s ", argv[i]); + } + + /* Now, read in one line at a time from stdin, and store this + * line to be used later as an argument to the command */ + while ((file_to_act_on = get_line_from_file(stdin)) !=NULL) { + + FILE *cmd_output; + char *output_line; + char *execstr; + + /* eat the newline off the filename. */ + chomp(file_to_act_on); + + /* eat blank lines */ + if (file_to_act_on[0] == 0) + continue; + + /* assemble the command and execute it */ + execstr = xcalloc(strlen(cmd_to_be_executed) + + strlen(file_to_act_on) + 1, sizeof(char)); + strcat(execstr, cmd_to_be_executed); + strcat(execstr, file_to_act_on); + + cmd_output = popen(execstr, "r"); + if (cmd_output == NULL) + perror_msg_and_die("popen"); + + /* harvest the output */ + while ((output_line = get_line_from_file(cmd_output)) != NULL) { + fputs(output_line, stdout); + free(output_line); + } + + /* clean up */ + pclose(cmd_output); + free(execstr); + free(file_to_act_on); + } + +#ifdef BB_FEATURE_CLEAN_UP + free(cmd_to_be_executed); +#endif + + return 0; +} + +/* vi: set sw=4 ts=4: */ diff --git a/yes.c b/yes.c new file mode 100644 index 000000000..7d9596d0b --- /dev/null +++ b/yes.c @@ -0,0 +1,53 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini yes implementation for busybox + * + * 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 + * + */ + +/* getopt not needed */ + +#include +#include +#include "busybox.h" + +extern int yes_main(int argc, char **argv) +{ + int i; + + if (argc >= 2 && *argv[1] == '-') + show_usage(); + + if (argc == 1) { + while (1) + if (puts("y") == EOF) { + perror("yes"); + return EXIT_FAILURE; + } + } + + while (1) + for (i = 1; i < argc; i++) + if (fputs(argv[i], stdout) == EOF + || putchar(i == argc - 1 ? '\n' : ' ') == EOF) { + perror("yes"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +}